Главная
Новости рынка
Рубрикатор



Архив новостей -->



 



   

В. Клочко

Дискретные занозы аналоговых ног

Речь пойдёт о возможных побочных эффектах при не совсем тривиальной работе с портами и АЦП. Для начала небольшое предисловие: употребляемые в дальнейшем формулировки типа “нечто-может-произойти” (“значение-может-измениться”) отнюдь не означают какой-то случайности этого события, всё полностью предсказуемо, но оговаривать влияющие факторы в каждом случае было бы излишним (чаще всего, это pull-up или pull-down на соответствующем выводе или другие внешние источники сигнала).
Начнём издалека. В документации (см. параграф “Выполнение команд”) указано, что после чтения и декодирования команды производится чтение байта данных из источника, далее АЛУ выполняет требуемую операцию, затем результат записывается в приёмник (по адресу операнда или в регистр W). То есть все операции над данными выполняются как “чтение-модификация-запись” (read-modify-write, далее — RMW), даже если одно или два из этих трёх элементарных действий излишни при выполнении конкретной команды. Естественно, в АЛУ используются только те данные, которые реально нужны для этой команды. Так, например, для команды “movwf PCLATH” безразлично старое значение PCLATH. Конечно, такой подход приводит к выполнению “бесполезных” действий, однако это не замедляет работу, так как узлы, выполняющие эти “бесполезные” действия, всё равно никак не могли бы помочь в выполнении действий “полезных” (а реализацию процессора это существенно упрощает): не забудем, что для гарвардской архитектуры одновременное обращение к памяти программ и памяти данных совершенно естественно.
Но иногда RMW приводит к некоторым неочевидным эффектам. Так, например, команда “tstf XXX”, которая на самом деле “movf XXX,f” (пересылка из XXX в XXX), действительно выполнит запись в XXX. Конечно, в большинстве случаев это ни на чём не отражается, но для некоторых регистров бывает важен сам факт записи, даже если записываемое значение совпадает со старым содержимым. Таковы, например, регистры PCL (любая запись приводит к разрушению конвейера команд) и TMR0 (сброс прескалера и пауза после записи).
Иногда к неочевидным (а потому нежелательным) последствиям может привести не запись, а чтение данных (похоже, что именно это — чтение в неподходящий момент, сам факт чтения — является первопричиной некоторых ошибок, отражённых в errata). В этом смысле регистры портов вполне “обычные”, и при работе с ними важен не столько факт чтения, сколько само прочитанное значение в сочетании с последующей записью. Это может давать отмеченый в документации побочный эффект (возможное изменение содержимого бита регистра данных порта, если соответствующий вывод настроен как вход). При изучении документации этот момент кажется совершенно очевидным и потому не всегда воспринимается и запоминается как источник возможной ошибки. А источник коварный. Ситуации “тут работаем с одним битом порта, а десятью строками выше (или ниже) — с другим, причём забыв о RMW” отслеживаются относительно легко, вполне достаточно “обычной” аккуратности. Но ведь то же самое может произойти и при обработке прерывания, если оно использует другие биты того же порта. Приведём пример фрагмента программы (команды переключения страниц опущены):

clrf TRISB ; весь RB — выходы
bcf PORTB,0 ; состояние “0” (важно что известное)
Part1:
... ; что-то делаем, но RB0 не трогаем
bsf TRISB,0 ; RB0 в hi-Z (вход), но его буфер по-прежнему “0”
Part2:
... ; здесь нет обращений к PORTB...
bcf TRISB,0 ; ... и мы надеемся получить
на RB0 тот же самый ”0”

Наша надежда выглядит вполне обоснованной. Однако если во время исполнения фрагмента Part2 произойдёт прерывание, программа обработки которого изменяет какой-либо другой бит в PORTB (кроме нашего RB0, разумеется), то после “bcf TRISB,0” сигнал на выводе RB0 вполне может оказаться “1” (зависит от внешних цепей). В частности, фрагмент Part2 может быть пустым (то есть непосредственно за bsf следует bcf), что создаёт ничем не обоснованную иллюзию, что между bsf и bcf “ну вообще нет никаких обращений к PORTB”. Да, такая необходимость переключать вывод из hi-Z непосредственно в требуемое состояние возникает не так уж часто, но иногда это бывает полезно или даже необходимо (типичный пример — эмуляция открытого коллектора при реализации I2C master). И очевидно, что для невмешательства потусторонних сил достаточно просто запретить прерывания на время от установки требуемого значения в регистре данных порта до переключения этого разряда порта в режим выхода.
Конечно, это были “цветочки”, которые явным образом описаны в документации. “Ягодки” выглядят немного иначе, но зреют на тех же колючих кустах.
В документации на PIC отмечено, что выводы, сконфигурированные как аналоговые (этим “заведует” регистр ADCON1), перестают работать как цифровые входы. И связано это с тем, что при конфигурировании вывода как аналогового запрещается работа цифрового входного буфера этого вывода. Необходимость такого решения очевидна: иначе подача промежуточных значений напряжения приводила бы к протеканию сквозных токов в этом буфере. Такие входы читаются как “0” (ведь нужна же какая-то определённость). Однако работа выходного буфера не запрещается, и он по-прежнему управляется соответствующими битами регистров TRISA (TRISE) и PORTA (PORTE). Поэтому естественно, что для реального использования вывода как аналогового следует обязательно перевести его выходной буфер в hi-Z. Если же это не сделано, и выходной буфер активизирован (то есть TRIS=0; предполагается отсутствие конфликта с внешними цепями, подключенными к этому выводу), то на работу собственно модуля АЦП это никак не повлияет, и при выборе этого канала он будет добросовестно преобразовывать напряжение на этом выводе. Такой подход разработчиков ИС можно считать странным или же совершенно логичным, но никак не поводом для беспокойства. По крайней мере, на первый взгляд.
И из вышеизложенного следует, что выводы, сконфигурированные как аналоговые, при необходимости (а выводы, как и любые другие ресурсы, чаще в дефиците, чем в избытке) можно задействовать как цифровые выходы. Можно. Причём вполне законно. Однако работать с ними придётся аккуратнее, чем обычно. И не только с ними, но и с другими цифровыми выходами портов A и E, если таковые имеются. Опасность возникает именно из-за RMW при выполнении арифметических и логических операций с портом, а также установке и сбросе битов. В отличие от этого, команды “movwf” или “clrf” никак не используют старое значение и не могут иметь побочного эффекта. Но ещё раз отметим: команда “tstf” имеет этот эффект.
Пусть, например, в ADCON1 часть выводов (или все) включены как аналоговые, но 0-вой бит регистра TRISA сброшен (то есть RA0 — выход) и RA0=1 (на RA0 высокий уровень). Тогда ничем не примечательная команда “bsf PORTA,4” приведёт (помимо желаемого результата, разумеется) также и к сбросу RA0. Почему? А потому, что в регистр данных порта запишется результат выполнения команды “bsf”, то есть прочитанное значение со сброшенным 4-ым разрядом. А что же было в 0-вом разряде прочитаного значения? Конечно “0”, ведь цифровой входной буфер на RA0 выключен.
И ещё одна “ягодка” с этого куста. Пусть при проектировании системы на pic16c74 (77, etc.) потребовалось 6 аналоговых входов и 2 цифровых выхода. Очевидно, что придётся выбрать как аналоговые все 8 входов (регистр ADCON1), но 2 из них использовать как цифровые выходы. Но любые ли 2? Увы, нет. Если это будут 2 вывода одного и того же порта (A или E), то независимо манипулировать ими при помощи команд bsf и bcf не удастся — при сбросе или установке одного из них второй неизбежно будет сбрасываться.
Напоследок нелишне напомнить, что после аппаратного сброса микроконтроллера регистр ADCON1=0, то есть все аналоговые входы включены именно как аналоговые. И со стороны разработчиков кристалла это вполне логично, так как любой из этих выводов может быть подключенным к аналоговой цепи. Так что даже если в конкретной системе АЦП вообще не используется, то всё равно придётся с ним “поработать”: модифицировать регистр ADCON1, чтобы переключить выводы в цифровой режим.







Реклама на сайте
тел.: +7 (495) 514 4110. e-mail:admin@eust.ru
1998-2014 ООО Рынок микроэлектроники