Над портами инженеры STM поубивались знатно. Такой прорвы настроек и возможных режимов я, честно говоря, даже не ожидал. Порты у STM32F1xx могут работать в режиме*:
- Вход Hi-Z
- Вход с подтяжкой вверх
- Вход с подтяжкой вниз
- Аналоговый вход (для каналов АЦП)
- Выход с открытым коллектором (стоком, если быть точным)
- Выход тяни-толкай (push-pull)
- И альтернативные функции, т.е. работа от периферии. Тут у нас формируется выход вида вида тяни-толкай или открытый коллектор.
С железной части порты бывают двух видов стандартные и устойчивые к напряжению в 5 вольт. При том, что напряжение питания у STM32 максимум 3.3 вольта. Разница у портов в схемотехнике. А точнее в том, что у 5V tolerant входов защитные диоды видут на какую то особую шину питания Vdd_ft. Полагаю, что там стоит нечто вроде небольшого повышателя, накачивающего напругу до 5 вольт.
Стандартный вывод
Вывод 5V Tolerant
Остальное все более менее стандартно. Сигнал на выход может вывалиться либо с периферии (стрелочка Alternate function Output) либо с выходного регистра. В который мы вольны записывать биты напрямую, либо же воспользоваться служебными регистрами установки/снятия битов.
Входной сигнал с ноги попадает в Data register и в Alternate Function Input. Причем селектора там нет, а значит можно по ходу дела считывать и глядеть что там творит периферия.
Т.к. RM0008 это общий документ, сразу на все семейство STM32F10x то распиновку выводов конткретного чипа в конкретном корпусе надо смотреть в конкретном даташите. Для STM32F103C8T6, что стоит на Pinboard II она выглядит следующим образом *:
Но этого недостаточно, тут только названия GPIO. А есть же еще альтернативные функции, т.е. периферия. Там же, в даташите, вы найдете такую большую и страшную таблицу, показывающую привязку выводов к периферии, а также разные свойства выводов.
Вот примерный кусок того, что вы должны найти*:
Разберем ее чуть подробней.
- Pins тут все просто. Это номера пинов в выбраном нами корпусе. Тут сразу все, от BGA до TQFP. Если в вашем чипе меньше выводов, то будут стоять прочерки. Т.е. в ядре то пин есть, но наружу не торчит. Печаль
- Pin Name собственно имя GPIO по его основному назначению. То самое, что вы видели на картинке с распиновкой. Помогает ориентироваться.
- Type тип вывода. I только вход, I/O вход-выход, как настроишь, S supply, т.е. питание по нашенски. Через эти выводы контроллер получает разное ЖРАТ. Сюда входят разные питания (ядра, периферии, АЦП и мало ли еще чего) и земли.
- I/O Level допустимый уровень напряжения на пине. Собственно бывает только обычный (т.е. 3.3V) и устойчивый к 5 вольтам. Пятивольтовые обозначаются как FT.
- Main Function главная функция, то как настроен вывод по дефолту, после сброса питания. Обратите внимание на то, что там не все выводы ведут себя как GPIO, хотя и большинство. Всякие JTAG/SWD любят быть включенными по дефолту. А также тактовые для разных дополнительных кварцев, вроде часовых.
- Alternate Functions/Defaults дополнительные периферийные функции. В отличии от тех же AVR, где стоило только включить какой-нибудь UART, так сразу же выводы под UART становились в нужные режимы, тут все по другому. Вывод переводится в режим управления от периферии ручками. Записью битов в регистры. И вот то каким он станет после включения альтернативного режима и указано в колонке Defaults
- Alternate Functions/Remap А еще там есть бит ремапа. Позволяющий взять и перебросить многие выводы периферии на другие ноги. Т.е. у того же UART1, например, вывод TX1 может быть либо на PA9 либо на PB6, в зависимости от бита ремапинга порта. Это удобно, легче разводить плату. Цепляешь вывод туда, где удобней, но изрядно взрывает мозг 🙂 Вот в этой колонке и указывается куда что ремапится при выставлении этого бита. Правда надо учитывать, что биты периферии ремапятся не по одному, а сразу все. Т.е. если это UART то сразу RX и TX. Врочем бывают исключения. Подробней надо смотреть в описании регистров ремапинга. Там портянка на три страницы с комбинациями куда что.*
Также настояяятельно рекомендую читать сноски и пояснения к этой таблице. Там много всяких уточнений.
Конфигурация
Управляется все это хозяйство прорвой регистров. Под которые в User Manual отведена целая глава. Инфы, как минимум, на час вдумчивого вдупления в макулатуру.
Итак, портом управляют следующие регистры
Пара GPIOx_CRH:GPIOx_CRL
Т.к. порты в STM32 шестнадцати разрядные, а на конфигурацию одной ноги выделено аж четыре бита, то на 16 выводов надо 64 бита. Т.е. два регистра. В CRL хранятся конфиги выводов от 0 до 7, а в CRH с 8 до 15го.
Выглядит внутри так:
Красными блоками я выделил группы битов, отвечающих за одну ножку. Тут конфигурируются выводы от 0 до 7. Это CRL. В CRH то же самое, но настраиваются пины от 8го до 15го.
Все возможные состояния описываются в таблице 18 и 19 из User Manual
Тут стоит обратить внимание на скоростной режим порта. Т.е. с какой частотой он может дрыгать лапой. Полагаю сия настройка должна влиять на энергопотребление. Т.е. если жалко батарейку и не планируем дрыгать быстро, то имеет смысл поставить минимальную частоту.
Какой режим выставить зависит от того, что мы хотим получить. Если для ручного дрыганья портами все просто и ясно, то для периферии возможны затупы. Т.к. тут надо вручную выставлять нужные режимы портов для периферии. А кому какой? Ответ на это дает пачка таблиц с 20 по 31 из User Manual * Там таблицы такого вида:
Где сказано для какого режима периферии какой режим порта надо поставить. Так что курите документацию. Это вам не AVR, тут ее просто горы 🙂
Также есть такая вещь как ремапинг, позволяющая выводы периферии кидать на другие ножки. За ремапинг отвечает регистр AFIO_MAPR и AFIO_MAPR2 Он один на все GPIO и там описана вся периферия и разные комбинации ремапа портов. Описывать это все не буду, там ОЧЕНЬ много таблиц и разных ссылок. Укажу лишь куда смотреть если что.
- Файл RM0008 STM32 User Manual. Раздел 8.3 Alternate function I/O and debug configuration (AFIO) стр. 161
- Файл RM0008 STM32 User Manual. Раздел 8.4.2 AF remap and debug I/O configuration register (AFIO_MAPR) стр. 170 и далее.
Искать там просто находишь нужную периферию в таблице в разделе 8.3 и смотришь куда ее можно перекинуть. Затем идешь в раздел 8.4.2 и смотришь какие биты для этого нужно записать в регистр AFIO_MAPR.
Дрыгаем портами вручную
Для ручного дрыгания портами у нас есть регистр GPIOx_ODR в режимах работы порта на выход, все что туда попало вылезает наружу. Если стоит режим тяни-толкай, то запись 1 поднимает вывод вверх, к питанию, а запись нуля прижимает в землю. В режиме открытого коллектора запись 1 переводит ногу в HiZ, т.е. она повисает в воздухе, а запись 0 прижимает к земле.
Структура регистра ODR проста первые биты от 0 до 15 отвечают за соответствующий вывод, а старшие, от 16 и до 31го не используются вообще.
Все же, что на ноге появилось, вылезает во входном регистре GPIOx_IDR. Это аналог регистра PINx в AVR. Т.е. в каком логическом уровне находится вывод МК, такое значение в этом регистре. Даташит говорит, что данные считываются на каждом такте шины APB2.
Структура регистра GPIO_IDR похожая на ODR. Т.е. первые 16 бит отвечают за соответствующие выводы, а старшие не используются.
Также там есть регистры атомарных действий. Позволяющие менять значения битов в ODR без использования операций чтение-модификация-запись.
Это регистры GPIOx_BSRR и GPIOx_BRR
С BRR все просто. Его младшие 16 бит отвечают за сброс бита в ODR.
Т.е. надо тебе, например, сбросить бит 3 в ODR, не трогая остальные. Без BRR регистра, надо было бы сначала считать ODR, потом по маске загасить нужный бит, не трогая остальные, а потом вернуть его обратно в ODR в уже измененном виде. Как минимум тут будет три команды. Между которыми может вломиться прерывание и обгадить нам всю малину. C регистром сброса все упрощается до одной команды. Нам нужно только лишь записать адын в третий бит GPIOx_BRR и усе, бит 3 в ODR будет сброшен. На нули же никакой реакции не будет. Таким образом можно сбрасывать и несколько битов.
Регистр BSRR работает аналогично, только на установку. Т.е. записал ты единичку в третий разряд BSSR и она автоматом выставилась в ODR.
Разница лишь в том, что в BRR старшие биты (т.е. 16 до 31) не влияют ни на что, а в BSSR они активны и сбрасывают бит. Записал в бит 0 BSRR единичку бит 0 в ODR выставился. Записал в бит 16 BSRR единичку бит 0 в ODR сбросился. Потому то он и зовется Bit Set/Reset Register.
Блокировка портов.
Есть такой регистр как GPIOx_LCKR записал в него хитрым образом нужный бит и все, этот бит порта блокируется и больше его никак нельзя перенастроить или как либо изменить группа битов в CRH:CRL блокируется. Только сбросить контроллер через reset.
Каждый бит регистра LCKR отвечает за один бит порта. А 16й бит регистра LCKR (LCKK) служит ключиком. Для того, чтобы заблочить порт нужно:
Выставить в регистре GPIO_LCKR биты выводов которые мы хотим заблокировать.
- Записать в бит LCKK 1
- Записать в бит LCKK 0
- Записать в бит LCKK 1
- Считать из LCKK 0
- Считать из LCKK 1 (этот шаг опциональный, но считывание 1 будет означать, что блокировка установилась)
В процессе записи ключевой последовательности нельзя модфицировать биты регистра LCKR кроме 16го, ключевого. Иначе замок не сработает.
Тактирование портов
Порты GPIO сидят на шине APB2 и тактируются оттуда. По умолчанию тактирование ВЫКЛЮЧЕНО! сделано это скорей ради экономии энергии. Нет тактов нет потребления. Вообще вся периферия изначально отключена от тактирования. Поэтому то часто возникают непонятки порты все настроил, а нифига не работает.
Такты включаются в регистре RCC_APB2ENR Там такая вот картина:
Как видишь, тут каждой периферийной шняге, что висит на шине APB2 присвоен битик. Каждому из портов (от А до G) тоже. Также отдельный бит присвоен альтернативному использованию портов. Бит AFIO. Вот выставляешь эти битики и поехало.
Подведем итог. Что нам надо сделать, чтобы помигать таки этим чертовым диодиком?
- Выставить тактирование нужного порта на APB2
- Сконфигурировать порты в CRH:CRL регистрах на выход тяни-толкай
- Записать/стереть нужный бит в ODR или воспользоваться регистрами BRR или BSRR.
Просто как раз-два-три! И чего я тут распинаюсь ,)
Оцените статью!