Порты ввода/вывода

Все внешние схемы, с которыми взаимодействует микроконтроллер подключены к портам ввода/вывода. Мы их уже рассматривали в разделе «Микроконтроллер под микроскопом». Сейчас же наша цель посмотреть регистры портов и разобраться как их настраивать.

В микроконтроллерах STM32 все ножки сгруппированы в порты и обозначаются буквами: A, B, C, D и т.д. В библиотеке CMSIS под них выделены структуры вида GPIOx. Например: третья ножка порта A. В каждом порте может быть до 16 ножке. Словосочетание «может быть» не случайно — физическое количество выводов МК ограничено, а значит не все они реализованы в железе. Конкретно в stm32f103c8 имеется 48 выводов и присутствуют порты A, B, C и D.

gpio pins

Изображение из Datasheet, раздел Pinouts and pin description, корпус LQFP48

Наряду с обычными портами присутствуют и специальные выводы — питание, сброс и boot0. Их нельзя использовать для управления внешними цепями. Часть ножек микроконтроллера отведены для программатора, в нашем случае PA13 отвечает за SWDIO, а PA14 за SWCLK. Плюс ко всему по-умолчанию включен и другой интерфейс отладки, JTAG. Он задействует ножки PAx. Все эти выводы можно использовать как обычные порты ввода-вывода, т.е. ими можно управлять внешними цепями, но для этого их нужно переключить в «обычный» режим, а после этого перепрошить устройство у вас не получится, только изменив конфигурацию загрузки (ножки boo0 и boo1).

Если у вас не хватает ножек, вы вполне можете задействовать, например SWDIO, просто поставьте на время разработки пятисекундную задержу при старте, что бы у вас оставалась возможность прошить устройство до запуска основной программы. В наборе не используются такие ножек, но чуть ниже будет рассказано, как их переключить.

Откройте Reference Manual и найдите в оглавлении пункт General-purpose I/Os (GPIO). С текстовым описанием вы можете ознакомиться самостоятельно, но перед тем как перейти к подразделу GPIO Registers, вернитесь к разделу «Микроконтроллер под микроскопом» или в Reference Manual и ещё раз рассмотрите структуру порта.

Первые два регистра, которые мы встречаем, называются GPIOx_CRL (L, нижний) и GPIOx_CRH (H, высокий).

gpio crl

Регистр CRL из Reference Manual

Каждой ножке порта ставится в соответствие 4 бита: два MODE и два CNF. Первые 8 описываются в нижнем регистре, вторые восемь в верхнем. Например нам нужно настроить пятую ножку порта A, тогда нужно записать некоторые значения в биты с 20 по 23 (нумерация с нуля). Понять что именно нужно записать, можно всё из того же Reference Manual. Под таблицей регистров располагается описание битов. Посмотрите внимательно и определите, что нужно записать в биты MODE5 и CNF5, чтобы настроить ножку на вход с плавающим выходом.

gpio mode

Описание настройки регистра CRL из Reference Manual

Сперва следует заполнить биты MODE. Так как нам нужен вход, туда следует установить 00. Далее в биты CNF записать 01. Не трудно заметить, что в скобочках у нужных нам значений указано «reset state», т.е. значение по-умолчанию, т.е. то, которое будет выставлено при сбросе МК. Если данную ножку вы будите использовать только в таком режиме, то настраивать её в не обязательно, однако ножка может быть настроена по другому и её состояние нужно будет изменить во время работы. Сделать это можно уже известным нам способом: применить логические операции и взять макросы из файла stm32f10x.h.

Если ножка была настроена на вход, то считать значение логического уровня на ней можно через регистр IDR (input data register). Каждой ножке соответствует один бит. Так как мы говорили о первой ножке порта, то и реагировать нужно на первый (второй по счёту) бит.

gpio_idr

Регистр IDR из Reference Manual

Применив операцию логического умножения значения регистра с маской мы гарантировано затерём все значения и оставим единицу, если она там была, на месте первого бита.

Так как в Си всё что не равняется нулю считается истиной, то условный оператор сработает где бы бит не находился.

В случае когда ножка настроена на выход, нужно использовать другой регистр ODR (output data register). Его строение сходно с регистром входа. Записав 1 в нужной позиции, на соответствующей биту ножке будет выставлен высокий логический уровень.

Здесь стоит отметить, что максимально допустимый выходной ток для одной ножки — 25 мА, а выходной ток на весь порт 160 мА. Таким образом, пытаться питать «прожорливую» нагрузку через МК может стать фатальным для системы питания порта, после чего он просто перестанет работать. Используйте транзисторный ключ для коммутации таких нагрузок как реле.

Если вы рассмотрели функциональную схему порта, то должны были заметить, что регистр ODR подключен через блок set/reset register. Следующие два регистра в документации BSRR и BRR. Может возникнуть резонный вопрос, — «Для чего ещё два регистра установки значений, когда есть ODR?». Ответ не совсем очевидный для новичка. Проблема здесь в том, что когда вы записываете в регистра ODR вам приходится его считывать. Если в это время произойдёт асинхронное к программе событие (о них мы поговорим позже), то операция будет на некоторое время прервана. В некоторых случаях такое поведение является недопустимым. Для этой цели ST предоставляет два отдельных регистра, в которые можно записывать значения, не считывая сам регистр.

В данной строчке мы записываем маску сразу в регистр. Нули будут проигнорирована, а вот единица во второй (третьей) позиции скажет, что нужно переключить третью ножку порта A.

Последний регистр, LCKR довольно не обычный, он позволяет заблокировать конфигурацию каждой ножки в отдельности. Последний бит, шестнадцатый (семнадцатый) отводится под «замок». Подав на неё специальную последовательность вы можете активировать блокировку конфигурации порта. Мы не будем пользоваться данной функциональностью.

У ножки может быть альтернативная функция. При записи 00 в CNFx она автоматически работать не станет, нужно как минимум включить тактирование блока альтернативных функций.

Затем тактирование нужного блока, допустим это будет SPI2.

После этого настроить порт и периферию. Однако... такое сработает не всегда. Дело в том, что альтернативные функции ножек могут быть подключены хитрым способом и их нужно переназначить (англ. remap), т.е. переназначать. Например ножки PC14 и PC15 по-умолчанию работают как вход и выход низкочастотного кварцевого резонатор (LSE). Если вам не хватает ножке, то их можно использовать как обычные GPIO. Тоже касается ножек интерфейса отладчика. Все эти настройки совершаются через регистр MAPR, но мы не будем задевать его в данном устройстве.

Быстро определить что и куда можно переназначить можно через документ Datasheet, в разделе Pinouts and pin description.

gpio pinout remap

Таблица из Datasheet, Table 5. Medium-density STM32F103xx pin definitions

Как видите в отдельной колонке выписаны все возможные переназначаемые функции ножки.


Назад | Оглавление | Дальше