В прошлый раз я рассказывал, что такое адресное пространство МК, и как мог показал отличия разных архитектур. Настала пора рассказать, как примерно устроены порты GPIO, и с чем их лучше готовить. Каждый функциональный регистр - это, с точки зрения программиста, просто адрес, куда мы пишем или откуда читаем данные. Но с точки зрения железячника это место в адресном пространстве выглядит примерно так:
Примечание: На рисунке показаны только 16 ячеек. Более рисовать не имеет смысла. Там где разрядность 32, представьте, что там стоит регистр на 32.
Слева у нас есть входы/выходы DIO0-DIO15, справа выходы DO0-DO15. DIO подключаются к шине данных МК, данные можно записать в регистр или считать из него. А с выходов DO данные уходят в недра драйвера GPIO и теряются где-то там. Поищем чуть позже...
Как происходит работа с этим монстром? Всё очень просто. Режим записи:
- На шину данных выставляется информация для записи в регистр.
- Сигнал CS притягивается к 0.
- Сигнал WR притягивается к 0.
- Пусть будет так, что по фронту тактового импульса на входе C данные защёлкиваются в триггерах регистра и поступают на выход DO.
Режим чтения:
- Сигнал RD притягивается к 0.
- Сигнал CS притягивается к 0.
- На DIO появляется информация.
- МК её считывает.
В режиме чтения сигнал С не используется, так как данные защёлкивать не нужно. Мы просто сигналом WR говорим, что хотим считать, а после сигнала CS на выходе появляются данные. Но они никому не мешают, так как в других узлах МК все входы/выходы находятся в Z-состоянии, а МК при следующем тактовом импульсе считает данные с шины данных. Как формируются эти сигналы - в данном случае это не наша забота, статья не об этом.
Кто-то может сказать, что регистры так не работают, но это гипотетический регистр, и я знаю более 20 регистров, описывая работу которых, можно написать целую книгу. И среди них встретится примерно такой регистр. Если нужна более подробная информация, читайте журнал Радио за 1986 год, где описан компьютер "Радио РК86". Там очень понятно и доходчиво описана адресация и работа регистров, дешифраторов и мультиплексоров. А также можно почитать книгу Шило В.Л. "Популярные цифровые микросхемы".
Теперь мы знаем, что за зверь находится по определённому адресу и что он умеет делать. Посмотрим структурную схему, которую нам даёт ST:
Вроде всё нормально, но как это связано с регистрами порта. А у нас их вот такой список:
- MODER - регистр режима, на каждый вывод МК используются два бита. При записи в него меняем режимы работы вывода:
- 00 - Вход;
- 01 - Выход;
- 10 - Альтернативная функция;
- 11 - Аналоговый вход.
- OTYPER - Режим работы выхода. Используются только 16 разрядов по 1 биту на вывод:
- 0 - Обычный выход (тяни-толкай)
- 1 - Выход с открытым истоком.
- OSPEEDR - Скорость порта, 32 разряда по 2 бита на вывод:
- х0 - Малая скорость;
- 01 - Средняя скорость;
- 11 - Высокая скорость.
- PUPDR - Подтяжка выхода, 32 разряда по 2 бита на вывод:
- 00 - Нет подтяжки;
- 01 - Подтяжка к питанию;
- 10 - Подтяжка к земле;
- 11 - Зарезервировано.
- IDR - Входной порт, 16 разрядов.
- ODR - Выходной порт, 16 разрядов.
- BSRR - Регистр установки/сброса отдельных выводов.
- LCKR - Блокировка настроек.
- AFRL - Режим альтернативных функций, 32 бита, 4 бита на вывод. Младшие выводы: GPIO0-GPIO7.
- AFRH - Режим альтернативных функций, 32 бита, 4 бита на вывод. Старшие выводы: GPIO8-GPIO15.
- BRR - Сброс вывода.
Теперь примерная схема, как это может выглядеть (скачать в PDF.):
Будем рассматривать GPIOA, вывод GPIO_PIN_0. На остальных портах всё точно также, кроме альтернативных выводов.
MODER - регистр режима вывода - 32 бита. На функциональной схеме показаны только 16 бит в виде блока DD3 и дешифратора DD8. Позволяет нам включить один из четырёх режимов:
- 00 - вход. На выходе дешифратора DD3 будет 1 на выводе Out0. Эта единица поступает на вход EN регистра IDR - DD10. По синхросигналу с тактового генератора считывается состояние вывода, сигнал которого пропущен через триггер Шмитта DD13 (управляющие цепи не рассматриваем). Остальные узлы не работают.
- 01 - выход. На выходе Out1 дешифратора будет единица (1), которая разрешит работать DD11 - регистр ODR. Этот сигнал разрешает выдачу записанной в него информации через мультиплексор DD12 и контроллер вывода DM1, который управляет двумя транзисторами VT1 и VT2. В зависимости от того, что там будет - 0 или 1 - будет открыт один из транзисторов и вывод будет подключен или к питанию или к земле.
- 10 - альтернативная функция. Так как регистр у нас 32 бита, а на альтернативную отводится 4 бита, то одного регистра не хватает. Поэтому альтернативных регистров у нас два: младший и старший (не забываем, что я показал регистры 16-ти разрядными, чтобы ещё больше не монструозить схему). На схеме нарисована только половина одного регистра DD2 - AFRL. На выходе дешифратора Out3 появится 1, которая переключит мультиплексор DD12 на работу с альтернативными выходами.
- 11 - аналоговый вход. В этом случае на выводе дешифратора Out3 появляется 1, отключающая триггер Шмитта DD13, и сигнал со входа можно будет считать аналоговым. Но это не означает, что к данному выводу подключено АЦП, компаратор или усилитель. Получается, что все выводы можно сделать аналоговыми, но не все куда-то при этом подключены. Для чего это? Фирма ST говорит, что это позволяет отключить входной триггер Шмитта, что снижает потребляемую мощность и повышает помехозащищённость, если вывод никуда не подключен. Ладно, поверим.
OTYPER - режим выхода, регистр DD5, управляет входом UpDis контроллера DM1:
- 0 - при этом значении выход работает как обычный. Работают оба транзистора.
- 1 - транзистор VT1 отключается, в работе не участвует. Таким образом, выход становится с открытым истоком, что позволяет нам использовать его как монтажное ИЛИ, например, в протоколе I2C.
OSPEEDR - на схеме не показан. Выставляет максимальную частоту выхода. Разбираясь с этой функцией с помощью осцилографа, увидел, что частота идёт всё равно максимальная, а вот фронты могут быть или чёткими или заваленными, скорее всего действует на скорость нарастания. ST говорит по этому поводу, что на малых скоростях лучше включать низкую скорость вывода, если заботитесь об энергосбережении. Поверим.
PUPDR - подтяжка вывода, за это отвечает регистр DD7, дешифратор DD14 и хитрые ключи RA1, RA2 при подключении которых к выводу у нас осуществляется подтяжка или к питанию, или к земле. Следует учесть, что резисторы в этой подтяжке более 50 КОм. Поэтому в помехозащищённой аппаратуре лучше использовать внешнюю.
IDR - чтение данных со входа, реализовано на регистре DD10. Если включен режим входа, в нём хранится то же, что и на входе вывода. Если включен другой режим, читается 0, реже мусор.
ODR - регистр выхода, реализован на регистре DD11. У регистра ODR есть интересная особенность. Если мы подадим тактирование на порт и запишем в него какое-то число, то сможем считать его обратно. При этом на выходе МК не произойдёт ничего, если он не находится в режиме выхода. Соответственно у нас прокатывает такой фокус: после сброса МК (за исключением некоторых выводов в некоторых портах) порт находится в режиме входа, а ODR доступен для записи. Вывод в данный момент находится в Z-состоянии. Если мы запишем для нужного вывода 1, то после перевода в состояние выхода у нас на выводе сразу будет единица. Иначе - сначала Z-состояние, потом 0 и только потом, после записи 1, появится 1. Такой фокус иногда можно использовать, когда после инициализации должна быть сразу 1.
BSRR - регистр установки/сброса бита/бит, 32 разряда. Запись 1 в старшие 16 разрядов сбрасывает в 0 соответствующие биты в регистре DD11 - ODR, что отражается на выводе, если он настроен на выход. Обратное происходит при записи 1 в младшие 16 разрядов, т. е. вывод сбрасывается в 0.
Зачем так? Быстро, удобно. Обычный алгоритм изменения сигнала на выводах GPIO - это чтение, модификация, запись. Т. е. что бы изменить состояние вывода GPIO_PIN_0, нужно из регистра ODR считать данные, модифицировать нужные биты и записать обратно. Естественно это делает не программист, он просто пишет команду модификации нужного бита, а электроника делает всё сама. В случае сброса/установки бита/битов через регистр BSRR такого не происходит - производится установка бита в нужное положение сразу, что занимает меньше времени.
LCKR - блокировка записи в регистры настроек, регистры данных не блокируются. На схеме не показан. Запись 1 в нужный бит блокирует изменения регистров, которые участвуют в настройке порта. Блокировка сохраняется до сброса или отмены самим программистом. Для чего можно использовать, думайте сами.
AFRL, AFRH - два 32-х разрядных регистра альтернативных функций. Конфигурация одного вывода задаётся 4-мя битами.
Если в регистр MODER записать 0b10, мультиплексор DD12 переключится на вход In1, сигнал на который подаётся с модуля DD9 - контроллера альтернативных функций. На вход/выход контроллера подаются/снимаются сигналы с периферийных устройств, таких как UART, USART, SPI, I2C, таймеров и так далее. Таким образом, если смотреть порт GPIOA и GPIO_PIN_0, к нему можно подключить вход/выход таймера TIM2, канал 1, или TSC_G1 - контроллер сенсорной клавиатуры или сигнал CTS у USART2 (куда и как подключается остальная периферия можно найти в даташите на нужный МК). Какая периферия будет подключена к данному выводу задаётся в регистре DD2. Вход это будет или выход решает логика контроллера альтернативных функций.
BRR - 16-ти разрядный регистр сброса выхода в нулевое состояние. Повторяет старшие разряды регистра BSRR. Не знаю, почему так сделано, но я им иногда пользуюсь, есть не у всех МК.
И на этом на сегодня, в принципе, все.