В предыдущей статье "Микроконтроллеры для начинающих. Часть 46. Порты ввода-вывода PIC" мы познакомились с некоторыми подробностями реализации портов ввода-вывода микроконтроллеров PIC. Главной сложностью тогда было многообразие вариантов.
Сегодня мы поговорим о гораздо более логичной организации портов в микроконтроллерах STM8. При этом их функциональность достаточно высока. Но, как мы вскоре увидим, у этих микроконтроллеров гораздо больше общего, чем может показаться на первый взгляд.
Сегодня я тоже буду опираться на статью "Микроконтроллеры для начинающих. Часть 45. Порты ввода-вывода". Если вы ее еще не прочитали, то советую это сделать прямо сейчас.
В дальнейшем я буду использовать условные обозначения REG.bitx. Здесь REG это имя одного из регистров порта, а bitx обозначает один из разрядов, если номер не важен. Например, ODR.bitx будет обозначать один из битов регистра ODR (не важно, какой). Если же речь будет идти о конкретном бите, то это будет выглядеть так, ODR.bit3 - бит 3 регистра ODR.
Эти условные обозначения опираются на статью "Микроконтроллеры для начинающих. Часть 34. Мост к Си. Описываем регистры аппаратуры" и статью "Микроконтроллеры для начинающих. Часть 33. Мост к Си. Работа с битами"
Если потребуется дополнительно уточнить, о каком порте идет речь, то в начале обозначения будет добавляться имя порта. Например, PORTB.ODR.bit5 - бит регистра ODR порта B.
Реализация портов ввода-вывода STM8
В отличии от PIC, в STM8 порты реализованы одинаково (почти) во всей линейке.
Не правда ли, очень похоже на то, как устроено в PIC (с регистрами LAT)? Не верите? Давайте абстрагируемся от названий регистров и альтернативных функций (их опять не будем пока рассматривать).
В данном случае, показан более детально выходной буферный каскад. Для PIC он был показан в виде функционального блока. Но здесь, в целом, нет отличий, что я показывал в 45 статье цикла. Там же, я привел таблицу соответствия имен регистров.
Регистр ODR это регистр-защелка выходных данных, который доступен и для чтения. Это аналог регистра LAT в PIC. И точно так же, записанные в него данные не обязательно появятся на выводах микроконтроллера. При чтении ODR возвращаются именно записанные в него данные, а не фактическое состояние выводов.
Режим работы"вход"/"выход", или направление передачи данных, выбирается регистром DDR. Это аналог регистра TRIS в PIC. Но в данном случае режим "выход" задается единичным состоянием соответствующего бита, а не нулевым, как в PIC.
Регистр IDR позволяет считывать фактическое состояние выводов микроконтроллера. Это почти аналог регистра PORT в PIC (при наличии регистра LAT). Почти, так как в регистр IDR невозможна запись.
А вот все настройки разрядов порта, кроме направления передачи, задаются парой регистров, CR1 и CR2. В отличии от того винегрета, который присутствует в PIC. Но для PIC это во многом объясняется требованиями совместимости с ранними моделями, а STM8 все таки относительно молодые микроконтроллеры.
Настройки портов ввода-вывода
Два регистра управления дают 4 варианта настроек для каждого разряда. Но поскольку тут принимает участие и регистр DDR, то вариантов становится 8. 4 для входа и 4 для выхода.
Настройки для режима "вход"
Когда разряд порта работает как цифровой вход (DDR.bitx=0), регистр CR1 управляет подключением подтягивающих резисторов (к положительному выводу источника питания). Если CR1.bitx=0, то подтягивающий резистор отключен (плавающий вход). Если CR1.bitx=1, то подтягивающий резистор подключен.
Регистр CR2 управляет обработкой прерываний для соответствующего разряда порта. Мы пока не изучали прерывания, поэтому я не буду подробно описывать все связанное с генерацией и обработкой прерываний для разрядов порта, это еще впереди. Фактически, каждый вывод порта может использоваться как вход внешнего прерывания работающий по фронту или по уровню. И это настраивается специальными регистрами.
Сегодня будет достаточным сказать, что CR2.bitx=0 запрещает формирование запросов прерывания для соответствующего разряда порта. А CR2.bitx=1 разрешает использование соответствующего разряда как входа внешних прерываний.
Настройки для режима "выход"
Когда разряд порта работает как цифровой выход (DDR.bitx=1), регистр CR1 управляет переключением между двухтактным выходом и выходом с открытым стоком (псевдо-открытый сток). Разумеется, такое переключение невозможно для выводов в который двухтактный выход не реализован в принципе (истинный открытый сток).
CR1.bitx=0 переключает выход в режим открытого стока, а CR1.bitx=1 в двухтактный режим.
Регистр CR2 управляет скоростью нарастания напряжения (быстродействием вывода). CR2.bitx=0 ограничивает быстродействие вывода разряда порта, а CR2.bitx=1 разрешает работу на максимальной частоте.
Дополнительные настройки
Не смотря на то, что это относится к работе аналоговых модулей, я все таки кратко коснусь еще одного регистра. Точнее пары регистров, ADC_TDRH и ADC_TDRL.
Эти регистры управляют работой триггеров Шмитта между выводом микроконтроллера и входом регистра IDR. Дело в том, что триггер Шмитта может негативно влиять на точность работы аналогового модуля. По этой причине и предусмотрена возможность их отключения.
Но отключение триггера Шмитта приводит к тому, что для соответствующего разряда порта будет невозможно определить фактическое состояние вывода даже в том случае, если он не используется аналоговым модулем (используется как цифровой вход).
Регистры ADC_TDR определены не для портов ввода-вывода, а для аналоговых каналов. Например, для микроконтроллера STM8S103K3 в корпусе LQFP32 отключение триггера Шмитта для аналогового канала 2 (вывод 14 - PB2/AIN2/TIM1_CH3N) на самом деле отключит цифровой вход разряда 2 порта В.
Цикл чтение-модификация-запись
Для STM8 эта проблема не актуальна, так как пути чтения и записи данных для разрядов порта разделены. Точно так же, как для портов с регистрами LAT в PIC. Но в данном случае еще и регистр IDR не доступен для записи.
При этом, с точки зрения процессора, операции с битами по прежнему выполняются как чтение-модификация-запись. Только нам это уже никак не мешает.
"Темная" сторона логичности
У каждого плюса, как известно, есть свой минус. Так же и здесь.
Иногда в программах требуется частое переключение работы вывода порта между "вход" и "выход". Например, это использовалось в работе с емкостным датчиком методов переноса заряда в статье "Емкостные датчики. Измерения и обработка сигнала". И вот тут несоответствие настроек режимов может мешать.
Например, нам требуется выход в режиме "двухтактный, ограничение быстродействия". Для этого мы установим CR1.bitx=1 и CR2.bitx=0. Но если при этом нам потребуется и режим "подтяжка отключена, прерывания разрешены", то возникает проблема, так для это потребуется CR1.bitx=0 и CR2.bitx=1.
То есть, простое переключение DDR.bitx нам уже не подойдет. Нужно изменять биты сразу в трех регистрах. Причем это не всегда может быть простым. Например, в данном случае сброс бита в CR1 перед переключением в режим входа приводит к проблеме, если на выходе был установлен высокий уровень, а внешней подтяжки нет.
Поэтому иногда приходится прибегать и к объединению нескольких выводов, что бы обеспечить требуемые параметры переключения, и к использованию отключения триггеров Шмитта, и к хитрым программным решениям. Какого то единого способа нет, все определяется конкретной ситуацией.
Нужно отметить, что эта проблема не является особенностью именно STM8. Она свойственна многим микроконтроллерам со сложными настройками портов и большой их функциональностью. Но это иногда может очень сильно повлиять на выбор микроконтроллера для конкретной прикладной задачи.
Работа с большими втекающими/вытекающими токами
Для многих микроконтроллеров сегодня просто объявляется, что они могут обеспечить некоторое значение тока через выводы портов. Причем все выводы считаются в этом отношении равнозначными. Но в STM8 ситуация более сложная.
В этих микроконтроллерах выходы портов делятся на обычные и высокотоковые (high sink - HS). Причем даже отдельные выводы одного порта могут быть разными. Например, для уже ранее упоминавшегося STM8S103K3 разряды порта В 0, 1, 2 и 3 являются высокотоковыми, а остальные нет.
Вообще, этому вопросу в документации уделяется мало внимания. А это вызывает вопросы у тех, кто только начинает работать с этими микроконтроллерами. Давайте попробуем разобраться.
Во первых, для всех портов максимальный ток одного разряда может достигать 20 мА, как втекающий, так и вытекающий. То есть, по этому параметру разницы нет.
А вот по уровням напряжения на выходе разница уже есть. У высокотоковых выводов сопротивление каналов транзисторов выходного двухтактного буфера гораздо меньше. Что позволяет, при одинаковом токе через вывод обеспечивать меньшее падение напряжения на транзисторе. Вот и вся разница.
Начальное состояние после сброса (включения питания)
Здесь, в целом, нет отличия от других микроконтроллеров. После сброса разряды порта настроены как цифровые входы, без подтягивающих резисторов, а прерывания запрещены. Триггеры Шмитта разрешены.
Заключение
В STM8 порты кажутся более простыми в работе, чем в PIC. Но это несколько обманчивое впечатление.
Собственно работа с уже настроенным портом проста и в STM8, и в PIC (с LAT регистрами). Только имена регистров разные. А вот настройка в STM8 действительно проще, прежде всего из-за единообразия и логичности. Но за STM8 не тянется груз старых моделей.
Функциональность портов в STM8 практически полностью аналогична PIC современных семейств. Так что тут паритет. Но в STM8 производитель часто размещает в микроконтроллере много портов, но зато от каждого лишь несколько разрядов. Причем расположенных в середине байта. А это бывает неудобно с точки зрения программирования.
В следующий раз мы рассмотрим порты ввода-вывода AVR.