Stm32. порты ввода/вывода

Содержание

addelectronics › Блог › Изучаем STM32. Урок 2. Изучаем порты ввода-вывода GPIO (ч1)

Добрый день, итак, пока есть время между редактированиями кодов и пайками)) напишу ещё одну статейку. На этот раз мы будем знакомиться с нашими ножками (нет не теми что внизу), а теми которые находятся на микроконтроллере и за счёт чего он воспринимает сигналы из внешнего мира и соответственно передаёт сигналы в него.

Итак, давайте посмотрим на блок — схему порта ввода-вывода контроллера

Тут у нас справа расположены защитные диоды, дальше внизу расположен регистр вывода и на нём мы видим два полевичка один из которых N-канаьный, второй P-канальный. Именно они нам выдают либо лог. единицу, либо лог. ноль.
Вверху нарисован регистр ввода, в котором мы видим триггер шмидта, перед ним мы видим резисторы подтяжки
Ну кому более интересно это, тот может найти feference manual и выучить всё от корки до корки, мы же в данной части урока просто разберёмся что значат разные режимы работы наших портов

Итак, помните в прошлом уроке мы настраивали чем у нас будет ножка контроллера — Входом, Выходом. Но это не все параметры. Ещё ножка может быть сконфигурирована как аналоговый входвыход для допустим работы с АЦП, или с ЦАП, у кого он есть на “борту”))

Давайте рассмотрим все режимы работы
1)Input floating — по простому это вход безо всяких подтяжек (Hi-Z состояние, плавающий). По простому вход у нас ни к чему не подключён (привет помехи))))
2)Input pull-up — режим входа, в котором он чрез подтягивающий резистор подключён к питанию (номинал резистора несколько десятков килоОм)

3)Input-pull-down — режим входа, в котором он чрез подтягивающий резистор подключён к земле (массе) (номинал резистора несколько десятков килоОм)

4)Analog — режим работы, который включаем если желаем работать с АЦП или ЦАП

5)Output open-drain with pull-up or pull-down capability — выход с “открытым коллектором”

6)Output push-pull with pull-up or pull-down capability — самый используемый режим, в котором наш пин может выдавать как лог. ноль так и лог. единицу (это будут работать те самые полевые тарнзисторы о которых писал выше)

7)Alternate function push-pull with pull-up or pull-down capability — альтернативная функция (двухтактный вывод)

8)Alternate function open-drain with pull-up or pull-down capability — альтернативная функция (открытый
коллектор)

Теперь опишу как работаем с этими параметрами в нашей среде программирования.

Вот смотрите, кусочек кода, который отвечает за настройку параметров выхода

GPIO_InitStruct.Pin = GPIO_PIN_0; — данная строчка кода указывает что конфигурировать мы будем ножку 0
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; — Данная строчка указывает что режим работы — Вход
У данной строчки могут быть вот такие параметры
GPIO_MODE_INPUT
GPIO_MODE_OUTPUT_PP
GPIO_MODE_OUTPUT_OD
GPIO_MODE_AF_PP
GPIO_MODE_AF_OD

Следующая строчка GPIO_InitStruct.Pull = GPIO_PULLDOWN; — Указывает что у нас подтяжка к массе. У данной строчки ещё могут быть вот такие варианты
GPIO_NOPULL
GPIO_PULLUP
GPIO_PULLDOWN

Ну и последняя строчка указывает нам с каким портом нашего контроллера мы вообще только что разговаривали) — HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

Здесь мы рассмотрели настройку нашего пина к которому подключена кнопка. PA0.

А давайте теперь рассмотрим настройку нашего порта, куда подключены светодиоды
/*Configure GPIO pins : PD12 PD13 */
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13;
— эта строчка указывает какие пины настраиваем
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; — эта строка указыввает нам режим работы — ВЫХОД двухтактный (push-pull) . Возможные варианты конфигурации описаны чуть выше.
GPIO_InitStruct.Pull = GPIO_PULLUP; — данная штука указывает что включена подтяжка к питанию
Возможные варианты конфигурации описаны чуть выше.
GPIO_InitStruct.Speed = GPIO_SPEED_LOW; — данная строчка настраивает скорость работы выхода
Возможны вот такие варианты
GPIO_SPEED_LOW — низкая скорость 2MHz
GPIO_SPEED_MEDIUM — средняя скорость 25MHz
GPIO_SPEED_FAST — повышеная скорость 50MHz
GPIO_SPEED_HIGH -высокая скорость до 100MHz

Также, чтобы работал наш порт, и мы что то могли с ним делать — нам нужно включить тактирование порта. Так как мы создаём проект в CubeMX, то он за нас это всё делает, но на будущее, мало ли, может кто то захочет использовать старые библиотеки- не забывайте подавать тактирование на нужные вам порты.
В нашем случае тактирование наших портов включается вот таким образом
/* GPIO Ports Clock Enable */
__GPIOA_CLK_ENABLE();
__GPIOD_CLK_ENABLE();

Если поищем дальше, что обозначают эти строки то вот что найдём. Функция включения тактирования нашего порта A.
#define __HAL_RCC_GPIOA_CLK_ENABLE() do <
__IO uint32_t tmpreg;
SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN);
/* Delay after an RCC peripheral clock enabling */
tmpreg = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN);
UNUSED(tmpreg);
> while(0)

Ну а теперь код, с помощью которого мы управляем нашими пинами.
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET); — сбрасывает пин в НОЛЬ
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_SET); — устанавливает пин в ЕДИНИЦУ
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_9); — изменяет состояние пина на противоположное. Если было 0, то станет единица, и наоборот.

Ну и добавлю сюда ещё одну функцию — функция задержки Delay. Мы её часто использовали в CAVR, и тут она тоже есть. Задаётся она в милисекундах и выглядит вот так — HAL_Delay(100);
Это означает задержка в 100 милисекунд.

Можете теперь поиграться светодиодами на плате, выставив задержку и используя HAL_GPIO_TogglePin. Ваши светодиоды будут по очереди перемигиваться.

Жмём палец вверх, и читаем, читаем, читаем мануалы, и уже в голове придумываем что мы сделаем на STM32! STM — мечты сбываются)))

Ну и не забываем про хорошую музычку, да погромче! Пока писал — наслаждался вот этим шедевральным концертом. С ним как то и светодиоды по другому перемигиваются))

Stm32. порты ввода/вывода

Для того, что бы порты стали управляемы, нужно понять следующее. По умолчанию, когда включается питание или по сигналу сброса контроллера, тактирование всей системной периферии отключено. Порты ввода / вывода находятся на системной шине APB2. И для того, что бы они могли принимать команды от процессорного ядра, их нужно затактировать. Делается это просто, установите в регистре RCC_APB2ENR флажок напротив нужного вам порта.

; Синтаксис Keil. Камушек STM32F103.

; Для включения флажка используем метод BitBand
MOV32 R0 , (RCC_APB2ENR & 0x00FFFFFF ) * 0x20
+ 0x42000000
+ 2 * 4
;^^^ здесь цифра 2 – тот самый бит, который нужно установить в 1
MOV R1 , 1
STR R1 , [ R0 ]

И это касается не только портов, но и всей периферии, находящейся на шинах APB1/APB2. Для большей наглядности, посмотрите вкладку APB Bridges в режиме отладчика Keil.

Что бы изменить настройки только избранных ножек порта, можно использовать метод чтение-модификация-запись. Создайте 4-битную маску режима порта и скопируйте её в необходимый пин. Используйте таблицу истинности Port bit configuration table из datasheet на камень, что бы понять, какие биты и зачем нужны. На следующем примере, три младших ножки порта A будут переведены в состояние выхода.

; Адрес порта
MOV32 R0 , GPIOA_CRL
; 4-битная маска настроек для Output mode 50mHz, Push-Pull
MOV R1 , GPIO_CRL_MODE0_0 + GPIO_CRL_MODE0_1
; Считали порт
LDR R3 , [ R0 ]
; Что бы растолкать маску по отдельным ножкам порта
; Используем команду копирования битового поля
; Скопировали биты маски в позицию PIN0
BFI R3 , R1 , 0 , 4
; Скопировали биты маски в позицию PIN1
BFI R3 , R1 , 4 , 4
; Скопировали биты маски в позицию PIN2
BFI R3 , R1 , 8 , 4
; Сохранили в порт
STR R3 , [ R0 ]

Что бы настроить порт целиком, создайте 32-битную маску режимов и запишите её в порт. С точки зрения экономии времени, эта операция более предпочтительная. Например, установим пины 0..3 и 6 на Output mode 50mHz, Push-Pull, а пины 4, 5 и 7 на вход с подтяжкой резистором к плюсу.

; Адрес младшей половины порта
MOV32 R0 , GPIOA_CRL
; Соберём 32-биную конфигурацию для младшей половины порта
MOV32 R1 , GPIO_CRL_MODE0_0 + GPIO_CRL_MODE0_1
+ GPIO_CRL_MODE1_0 + GPIO_CRL_MODE1_1
+ GPIO_CRL_MODE2_0 + GPIO_CRL_MODE2_1
+ GPIO_CRL_MODE3_0 + GPIO_CRL_MODE3_1
+ GPIO_CRL_MODE6_0 + GPIO_CRL_MODE6_1
+ GPIO_CRL_CNF4_1
+ GPIO_CRL_CNF5_1
+ GPIO_CRL_CNF7_1
; Сохраним в порт
STR R1 , [ R0 ]

Читайте также:  Чем мыть хрустальную люстру в домашних условиях?

; Включим pull-up резисторы для пинов 4 , 5 и 7
MOV R1 , GPIO_ODR_ODR4
+ GPIO_ODR_ODR5
+ GPIO_ODR_ODR7
; Сохраним в порт
MOV32 R0 , GPIOA_ODR
STR R1 , [ R0 ]

Для вывода информации в порт, можно использовать разные методы. Например, через биты принудительного включения в регистре GPIOA_BSRR, установим в 1 настроенные ранее выводы 0..3 и 6. Так сказать, дрыгнем ножками.

; Адрес порта выходных сигналов
MOV32 R0 , GPIOA_BSRR
; Эти ножки установить в 1
MOV R1 , PIN0 + PIN1 + PIN2 + PIN3 + PIN6
; Сохранили в порт
STR R1 , [ R0 ]

Только не забывайте, что если в регистр выходных данных записать 0x0000, любым методом, то в ранее настроенных ножках 4, 5 и 7 отключатся подтягивающие pull-up резисторы. Вернее, они переключатся на pull-down и подтянут ножки к земле.

Что ещё можно сделать

Что бы избежать случайного изменения настроек порта, залОчим отдельные ножки специальной процедурой. После чего, вы не сможете изменить настройки этих ножек до сигнала сброса порта. Порт можно сбросить установкой соотв. бита в регистре RCC_APB2ENR. Или кнопкой RESET, если таковая имеется! Или просто, отключив питание микроконтроллеру.

; Процедура залочки отдельных ножек порта
MOV32 R0 , GPIOA_LCKR
; Эти ножки залочить
MOV R1 , PIN4 + PIN5 + PIN7
; Последовательно установить в 1-0-1 флаг GPIO_LCKR_LCKK
MOVT R1 , 1
STR R1 , [ R0 ]
MOVT R1 , 0
STR R1 , [ R0 ]
MOVT R1 , 1
STR R1 , [ R0 ]
; Всё, ножки защищены от изменения

Микроконтроллеры

Основные регистры порта ввода/вывода микроконтроллера STM32

Под портом понимается определенный именованный набор ног микроконтроллера. В STM микроконтроллерах они именуются как GPIOA,GPIOB,GPIOC и т.д. Порты ввода/вывода в микроконтроллерах STM32 имеют, как правило, по 16 линий (ног). Под линией понимается та или иная ножка микроконтроллера. Каждая линия порта может быть сконфигурирована определенным образом и выполнять следующие функции:

  • цифрового ввода;
  • цифрового вывода;
  • входа внешнего прерывания;
  • функцию ввода/вывода других модулей микроконтроллера.

Сконфигурировать порт на нужный режим работы можно использую регистры микроконтроллера. К этим регистрам можно обращаться напрямую, а также использовать специальные методы из библиотеки периферий.

Давайте рассмотрим основные регистры необходимые для работы с портами ввода/вывода.

Регистры отвечающие за конфигурацию порта

Прежде чем начать работу с портом вывода его нужно сконфигурировать под ваши нужды.

За настройку или конфигурацию порта отвечают регистры конфигурации. В микроконтроллерах семейства STM32F302xx, STM32F303xx и STM32F313xx это следующие регистры:

  • GPIOx_MODER;
  • GPIOx_OTYPER;
  • GPIOx_OSPEEDR;
  • GPIOx_PUPDR.

Регистр GPIOx_MODER (где x=A. F)

Это 32-х битный регистр отвечает за режим работы линии. Для конфигурации опеределенной линии требует 2 бита. Возможны следующие комбинации:

  • 00 – линия настроена на вход;
  • 01 – на выход;
  • 10- режим альтернативной функции;
  • 11 – аналоговый режим.

Регистр GPIOx_TYPER (где x=A. F)

Данный регистр используеться для настройки типа работы линии использует в работе 16 бит остальные 16 зарезервированны. Принемает следующие значения:

  • 0 – пуш пульнай режим;
  • 1 – открытый сток

Регистр GPIOx_PUPDR (где x=A. F)

Данные регистр отвечает за подтяжку. Принемает следующие значения:

  • 00 – без подтяжки
  • 01 – подтяжка к плюсу питания
  • 10 – подтяжка к земле

Регистр GPIOx_SPEEDR (где x=A. F)

Регистр настройки скорости работы линии.

  • 00 – 2 МГц;
  • 01 – 10 МГц;
  • 10 – 50 МГц.

Регистр вывода (выходной регистр) GPIOx_ODR (где x=A…F) – output data register

Данный регистр используется для вывода данных в порт. При записи определенных значений в данный регистр на линии (ножке) устанавливается аналогичное значение. Так как у нас 16 линий а регистр имеет 32 бита, то используются только первые (младшие) 16 бит.

Регистр ввода (регистр состояния порта или входных данных) GPIOx_ >

Данный регистр доступен только для чтения. Своего рода индикатор состояния порта. Аналог PINxв микроконтроллерах серии AVR.

Регистр побитовой установки выходного порта GPIOx_BSRR

Данный регистр побитно устанавливает состояние ножки в порте вывода.

Подробнее о всех регистрах конкретного микроконтроллера можно узнать в referens manual.pdf который можно скачать с официального сайт www.st.com

Настройка порта микроконтроллера при помощи библиотеки

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

Рассмотрим пример кода включающий светодиод

В целях экономии электроэнергии, вся периферия у микроконтроллеров отключена. Для того чтобы «активировать» ту или иную периферию необходимо для начала подать на него тактовые сигналы.

Мы работаем с портом GPIOE поэтому нам необходимо включить тактирование при помощи метода

RCC_APB2PeriphClockCmd (uint32_t RCC_APB2Periph, FunctionalState NewState);

Который принимает два значение первый это собственно сам порт который нам необходимо включить, а второй это состояние данного порта, включен или выключен.

Далее объявляем структуру, и производим ее настройку.

Дата поста: 05-02-2018

Недавно коллега меня подсадил на идею создания умного дома, я даже успел заказать себе десятки разных датчиков. Встал вопрос о выборе Микроконтроллера (далее МК) или платы. После некоторых поисков нашёл несколько вариантов. Среди них были и Arduino (включая его клоны, один из которых себе заказал ради того, чтобы просто побаловаться) и Launchpad, но всё это избыточно и громоздко (хотя в плане программирования гораздо проще, но тему холиваров поднимать не буду, у каждого свои вкусы). В итоге решил определяться не с готовой платой, а взять только МК и делать всё с нуля. В итоге выбирал между Atmel ATtiny (2313), Atmel ATmega (решил отказаться т.к. не смог найти за адекватные деньги), STM32 (Cortex на ядре ARM). С тинькой я уже успел побаловаться, так что взял себе STM32VL-Discovery. Это можно назвать вступлением к циклу статей по STM32. Оговорюсь сразу, автором большинства этих статей буду являться не я, т.к. сам только познаю, здесь я публикую их в первую очередь для себя, чтоб удобнее было искать если что-то забуду. И так поехали!

Общие сведения

Микроконтроллеры семейства STM32 содержат в своём составе до семи 16-разрядных портов ввода-вывода c именами от PORTA до PORTG. В конкретной модели микроконтроллера без исключений доступны все выводы портов, общее количество которых зависит от типа корпуса и оговорено в DataSheet на соответствующее подсемейство.

Для включения в работу порта x необходимо предварительно подключить его к шине APB2 установкой соответствующего бита IOPxEN в регистре разрешения тактирования периферийных блоков RCC_APB2ENR:

Управление портами STM32 осуществляется при помощи наборов из семи 32-разрядных регистров:

  • GPIOx_CRL, GPIOx_CRH – задают режимы работы каждого из битов порта в качестве входа или выхода, определяют конфигурацию входных и выходных каскадов.
  • GPIOx_IDR – входной регистр данных для чтения физического состояния выводов порта x.
  • GPIOx_ODR– выходной регистр осуществляет запись данных непосредственно в порт.
  • GPIOx_BSRR – регистр атомарного сброса и установки битов порта.
  • GPIOx_BSR – регистр сброса битов порта.
  • GPIOx_LCKR – регистр блокировки конфигурации выводов.

Режимы работы выводов GPIO

Режимы работы отдельных выводов определяются комбинацией битов MODEy[1:0] и CNFy[1:0] регистров GPIOx_CRL и GPIOx_CRH (здесь и далее: x-имя порта, y- номер бита порта).

GPIOx_CRL — регистр конфигурации выводов 0. 7 порта x:

Структура регистра GPIOx_CRH аналогична структуре GPIOx_CRL и предназначена для управления режимами работы старших выводов порта (биты 8. 15).

Биты MODEy указанных регистров определяют направление вывода и ограничение скорости переключения в режиме выхода:

  • MODEy[1:0] = 00: Режим входа (состояние после сброса);
  • MODEy[1:0] = 01: Режим выхода, максимальная скорость – 10МГц;
  • MODEy[1:0] = 10: Режим выхода, максимальная скорость – 2МГц;
  • MODEy[1:0] = 11: Режим выхода, максимальная скорость – 50МГц.

Биты CNF задают конфигурацию выходных каскадов соответствующих выводов:

в режиме входа:

  • CNFy[1:0] = 00: Аналоговый вход;
  • CNFy[1:0] = 01: Вход в третьем состоянии (состояние после сброса);
  • CNFy[1:0] = 10: Вход с притягивающим резистором pull-up (если PxODR=1) или pull-down (если PxODR=0);
  • CNFy[1:0] = 11: Зарезервировано.

в режиме выхода:

  • CNFy[1:0] = 00: Двухтактный выход общего назначения;
  • CNFy[1:0] = 01: Выход с открытым стоком общего назначения;
  • CNFy[1:0] = 10: Двухтактный выход с альтернативной функцией;
  • CNFy[1:0] = 11: Выход с открытым стоком с альтернативной функцией.

С целью повышения помехоустойчивости все входные буферы содержат в своём составе триггеры Шмидта. Часть выводов STM32, снабженных защитными диодами, соединёнными с общей шиной и шиной питания, помечены в datasheet как FT (5V tolerant) — совместимые с напряжением 5 вольт.

Защита битов конфигурации GPIO

Для защиты битов в регистрах конфигурации от несанкционированной записи в STM32 предусмотрен регистр блокировки настроек GPIOx_LCKR
GPIOx_LCKR — регистр блокировки настроек вывода порта:

Для защиты настроек отдельного вывода порта необходимо установить соответствующий бит LCKy. После чего осуществить последовательную запись в разряд LCKK значений “1” — “0” — “1” и две операции чтения регистра LCKR, которые в случае успешной блокировки дадут для бита LCKK значения “0” и “1” . Защита настроечных битов сохранит своё действие до очередной перезагрузки микроконтроллера.

Читайте также:  Блок питания 0...12 вольт

Файл определений для периферии микроконтроллеров STM32 stm32f10x.h определяет отдельные группы регистров, объединённые общим функциональным назначением (в том числе и GPIO), как структуры языка Си, а сами регистры как элементы данной структуры. Например:

GPIOC->BSRR – регистр BSRR установки/сброса порта GPIOC.
Воспользуемся определениями из файла stm32f10x.h для иллюстрации работы с регистрами ввода-вывода микроконтроллера STM32F100RB установленного в стартовом наборе STM32VLDISCOVERY:

Запись и чтение GPIO

Для записи и чтения портов предназначены входной GPIOx_IDR и выходной GPIOx_ODR регистры данных.

Запись в выходной регистр ODR порта настроенного на вывод осуществляет установку выходных уровней всех разрядов порта в соответствии с записываемым значением. Если вывод настроен как вход с подтягивающими резисторами, состояние соответствующего бита регистра ODR активирует подтяжку вывода к шине питания (pull-up, ODR=1) или общей шине микроконтроллера (pull-down, ODR=0).

Чтение регистра IDR возвращает значение состояния выводов микроконтроллера настроенных как входы:

Сброс и установка битов порта

Для атомарного сброса и установки битов GPIO в микроконтроллерах STM32 предназначен регистр GPIOx_BSRR. Традиционный для архитектуры ARM способ управления битами регистров не требующий применения операции типа “чтение-модификация-запись” позволяет устанавливать и сбрасывать биты порта простой записью единицы в биты установки BS (BitSet) и сброса BR (BitReset) регистра BSRR. При этом запись в регистр нулевых битов не оказывает влияния на состояние соответствующих выводов.

GPIOx_BSRR – регистр сброса и установки битов порта:

Альтернативные функции GPIO и их переназначение (remapping)
Практически все внешние цепи специального назначения STM32 (включая выводы для подключения кварцевых резонаторов, JTAG/SWD и так далее) могут быть разрешены на соответствующих выводах микроконтроллера, либо отключены от них для возможности их использования в качестве выводов общего назначения. Выбор альтернативной функции вывода осуществляется при помощи регистров с префиксом “AFIO”_.
Помимо этого регистры AFIO_ позволяют выбирать несколько вариантов расположения специальных функций на выводах микроконтроллера. Это в частности относится к выводам коммуникационных интерфейсов, таймеров (регистры AFIO_MAPR), выводам внешних прерываний (регистры AFIO_EXTICR) и т. д.

Подробнее смотрите документы “Reference manual” на соответствующую подгруппу микроконтроллеров.

STM32 GPIO или порты ввода-вывода.

Для того чтобы порт заработал его надо подключить к шине APB2, установив соответствующий бит IOPxEN, в регистре разрешения тактирования периферийных блоков RCC_APB2ENR.

После включения все выводы находятся в состоянии плавающего входа, он же высокоимпедансный вход, он же Hi-Z, он же третье состояние.

  • Выходной драйвер выключен
  • Триггер Шмитта отключён
  • Подтягивающие резисторы отключены
  • В регистре IDR всегда “0”

В режиме входа

  • Выходной драйвер выключен
  • Входной Триггер Шмитта включён
  • В зависимости от настройки, включаются резисторы подтяжки
  • Каждый такт шины APB2 данные с входа поступают в регистр IDR, считав этот регистр можно узнать состояние ножки

В режиме выхода

  • В режиме Open Drain при записи “0” открывается нижний транзистор, при записи “1” линия остаётся не подключённой
  • В режиме Push Pull при записи “1” открывается верхний транзистор, при записи “0” — нижний
  • Входной Триггер Шмитта включён
  • Резисторы подтяжки отключены
  • По каждому такту шины APB2 данные c выхода передаются в регистр IDR, оттуда же их можно считать в режиме Open Drain
  • Чтение регистра ODR возвращает последнее записанное значение в режиме Push Pull

В режиме альтернативной функции

  • Драйвер включается в режиме Push Pull или Open Drain, в зависимости от конфигурации
  • Выходной драйвер управляется сигналами периферии, а не регистром ODR
  • Входной триггер Шмитта включён
  • Резисторы подтяжки отключены
  • По каждому такту шины APB2 данные c выхода передаются в регистр IDR, оттуда же их можно считать в режиме Open Drain
  • Чтение регистра ODR возвращает последнее записанное значение в режиме Push Pull

Из таблицы видно, что возможны два варианта конфигурации, в режиме альтернативной функции: Push Pull и Open Drain. Например, мы хотим, настроить в режим альтернативной функции ножку, отвечающую за приём данных по USART. Для этого в Reference Manual RM0008, начиная с 161 страницы, идут таблицы, в которых можно посмотреть как cконфигурировать вывод, для разной периферии.

Нам подойдет Input floating или Input pull-up.

Конфигурация выводов задаётся в регистрах GPIOx_CRL, GPIOx_CRH, в этих регистрах для конфигурации каждого вывода отведено 4 бита, MODE[1:0] и CNF[1:0]. В GPIOx_CRL конфигурируются выводы с 0 по 7, а в GPIOx_CRH с 8 по 15.

Если MODE[1:0] = 00, то вывод настроен на вход, конфигурация входа в таком случае задаётся в регистрах CNF[1:0]. Если MODE[1:0] не равен 00, в таком случае вывод настроен как выход, а значение MODE [1:0] задаёт максимальную частоту, с которой может он переключаться.

Считать состояние входа можно с помощью Port input data register или коротко GPIOx_IDR, где x – название порта, может быть от A до G. Считать состояние любого вывода можно из 16 младших бит, старшие 16 бит не используются.

Если порт настроен на выход, управлять его состоянием можно с помощью регистра Port output data register или GPIOx_ODR. Значение, которое мы запишем в этот регистр, появится на соответствующих выводах порта. Для установки состояния порта, выделены 16 младших бит, старшие 16 бит не используются.

В STM32 возможно атомарно управлять отдельными битами порта с помощью регистров GPIOx_BSRR (Port Bit Set/Reset Register) и GPIOx_BRR (Port Bit Reset Register).
Для установки отдельного бита порта вручную, надо считать значение порта, изменить нужный бит с помощью маски и результат вернуть обратно в GPIOx_ODR. Так как действий целых три, то возникшее между ними прерывание, может подпортить данные. С помощью описанных выше регистров, это делается в одно действие.
Для сброса бита надо в нулевой бит GPIOx_BRR записать единичку, при этом в нулевой бит GPIOx_ODR запишется 0, для этой операции выделены младшие 16 бит, старшие 16 бит не используются.

С GPIOx_BSRR всё чуть интереснее, младшие 16 бит отвечают за установку 1, старшие 16 бит за сброс в 0. Чтобы установить 1 в нулевой бит, надо в нулевой бит GPIOx_BSRR записать 1. Чтобы установить 0 в нулевой бит, надо в 16 бит установить 1.

У STM32 есть возможность защитить конфигурацию порта от изменения, для этого выделен регистр GPIOx_LCKR. Младшие 16 бит используются для выбора вывода, который хотим заблокировать (выбор бита осуществляется установкой единицы), затем специальной последовательностью записей в 16 бит(LCKK) осуществляется блокировка.

Последовательность следующая: записать в LCKK 1 , записать 0 ,записать 1, затем из регистра LCKR считать 0, считать 1. Последняя считанная единица говорит о том, что вывод заблокирован. Разблокировка вывода произойдёт только после перезагрузки контроллера.

Для получения более подробной информации можно обратиться Reference Manual RM0008, к разделу General-purpose and alternate-function I/Os (GPIOs and AFIOs).

Программирование STM32. Часть 5: Порты ввода-вывода GPIO

В этой части мы разберемся с порами ввода-вывода GPIO микроконтроллера STM32F103C8 и напишем «Hello, World!» с мигающим светодиодом, а так же научимся читать состояние выводов микроконтроллера и использовать встроенный подтягивающий резистор. Предыдущая статья здесь, все статьи цикла можно посмотреть тут: http://dimoon.ru/category/obuchalka/stm32f1.

Введение

General-purpose input/output (GPIO) — важный компонент любого микроконтроллера, с помощью которого он взаимодействует с окружающим миром. В микроконтроллерах STM32 порты именуются буквами A, B, C и так далее: GPIOA, GPIOB, GPIOC... Каждый GPIO имеет 16 линий ввода/вывода, причем каждая линия может быть настроена независимо от других. Вот варианты настройки:

  • Input floating — вход с отключенными подтягивающими резисторами
  • Input pull-up — вход с подтяжкой к логической единице
  • Input-pull-down — вход с подтяжкой к логическому нулю
  • Analog — аналоговый вход (например, для АЦП)
  • Output open-drain — выход с открытым коллектором (записали 1 — выход в высокоимпедансном состоянии, записали 0 — выход прижат внутренним транзистором к земле)
  • Output push-pull — выход «тяни-толкай» (записали 1 — на выходе лог. 1, записали 0 — на выходе лог. 0)
  • Alternate function push-pull — альтернативная функция в режиме «тяни-толкай»
  • Alternate function open-drain — альтернативная функция в режиме открытого коллектора

Дам несколько пояснений по поводу режимов.

Режим Analog. Внутри микроконтроллера есть аналогово-цифровые преобразователи, которые, как известно, должны иметь аналоговые входы. Так вот, в режиме Analog ножка микроконтроллера подключается к аналоговому входу АЦП внутри микроконтроллера. Кроме того, отключается вся цифровая обвязка этой ножки для уменьшения цифрового шума и энергопотребления.

Alternate function. В этом режиме ножкой микроконтроллера управляет внутренняя цифровая периферия, например, модуль USART.

Регистры GPIO

Давайте рассмотрим регистры портов GPIO.

Port configuration register low (GPIOx_CRL)

Рис. 1. Регистр CRL

Это конфигурационный регистр для выводов порта с номерами от 0 до 7. Каждому выводу предоставлено 4-ре бита конфигурации: 2 бита MODEy и 2 бита CNFy.

MODEy[1:0]: Режим ножки порта, вход или выход. В режиме выхода нужно выбрать максимальную частоту переключения данной ножки, насколько понял это является оптимизацией энергопотребления порта.

  • 00: Вход (значение после сброса)
  • 01: Выход, максимальная частота 10 MHz.
  • 10: Выход, максимальная частота 2 MHz.
  • 11: Выход, максимальная частота 50 MHz.
Читайте также:  Частотомер - цифровая шкала

CNFy[1:0]: Конфигурация режима.

В режиме входа (MODEy[1:0]=00):

  • 00: Analog mode — аналоговый режим (подключен к АЦП или ЦАП-у)
  • 01: Floating input — вход с отключенными подтягивающими резисторами (значение после сброса)
  • 10: Input with pull-up / pull-down — вход с подтяжкой вверх или вниз
  • 11: Reserved — не используется

В режиме выхода (MODEy[1:0]>00):

  • 00: General purpose output push-pull — выход в режиме тяни/толкай
  • 01: General purpose output Open-drain — выход с открытым коллектором
  • 10: Alternate function output Push-pull — выход альтернативной функции режиме тяни/толкай
  • 11: Alternate function output Open-drain — выход альтернативной функции с открытым коллектором

Port configuration register high (GPIOx_CRH)

Рис. 2. Регистр CRH

Это конфигурационный регистр для выводов порта с номерами от 8 до 15. Тут все то же, что и для регистра GPIOx_CRL.

Port input data register (GPIOx_IDR)

Рис. 3. Регистр IDR

IDRy: в этих битах содержится входное значение соответствующего порта ввода-вывода.

Port output data register (GPIOx_ODR)

Рис. 4. Регистр ODR

ODRy: выходные данные порта.

Port bit set/reset register (GPIOx_BSRR)

Рис. 5. Регистр BSRR

С помощью этого регистра можно сбросить или установить любой бит регистра ODR без операций чтение-модификация-запись.

BRy: Сбросить бит у регистра ODR порта ввода-вывода (y= 0 .. 15)

  • 0: не оказывает влияние на соответствующий бит ODRx
  • 1: Сбрасывает в ноль соответствующий бит ODRx

BSy: Установить бит у регистра ODR порта ввода-вывода (y= 0 .. 15)

  • 0: не оказывает влияние на соответствующий бит ODRx
  • 1: Устанавливает в единицу соответствующий бит ODRx

Port bit reset register (GPIOx_BRR)

Рис. 6. Регистр BRR

С помощью этого регистра можно сбросить любой бит регистра ODR без операций чтение-модификация-запись.

BRy: Сбросить бит у регистра ODR порта ввода-вывода (y= 0 .. 15)

  • 0: не оказывает влияние на соответствующий бит ODRx
  • 1: Сбрасывает в ноль соответствующий бит ODRx

Port configuration lock register (GPIOx_LCKR)

Рис. 7. Регистр LCKR

Этот регистр используется для блокировки конфигурационных битов порта после записи корректной последовательности в 16 бит (LCKK) регистра. Значения битов [15:0] используется для блокировки конфигурации GPIO. Во время блокирующей последовательности в LCKK значения LCKR [15: 0] не должны меняться. Когда блокирующая последовательность была записана, конфигурация выбранных портов ввода/вывода может быть изменена только после сброса микроконтроллера. Каждый LCKy бит блокирует возможность изменения четырех битов конфигурации порта (CRL, CRH).

LCKK[16]: Ключ блокировки.

  • 0: Блокировка конфигурации порта не активна.
  • 1: Блокировка конфигурации порта активна. GPIOx_LCKR заблокирован до следующего сброса микроконтроллера.

Для блокировки необходимо выполнить следующую последовательность:

  • Записать 1
  • Записать 0
  • Записать 1
  • Прочитать 0
  • Прочитать 1 (эта операция чтения не является обязательной, а всего лишь подтверждает успешность установки блокировки)

LCKy: Эти биты могут быть прочитаны и записаны, но запись можно произвести только если бит LCKK равен нулю.

  • 0: Конфигурация пина номер y не заблокирована
  • 1: Конфигурация пина номер y заблокирована

Настройка порта GPIO

Итак, с регистрами разобрались, настало время практики. Все примеры в этой статье для микроконтроллера STM32F103C8. В моем распоряжении есть вот такая отладочная плата:

На ней установлен кварцевый резонатор на 8 МГц и светодиод на порту PB12. Вот с помощью этого светодиода мы и устроим Hello, World!

Задача ясна: настраиваем PB12 на выход в режиме push-pull и с помощью регистра ODR дергаем 12-й пин порта GPIOB туда-сюда! Но мы забыли об одной маленько детали: RCC. Дело в том, что по-умолчанию после сброса микроконтроллера все периферийные модули отключены от источника тактового сигнала, в том числе и GPIO. А подать тактирование можно с помощью регистров RCC. В 3-ей части я про это говорил. Для начала нужно определить, к какой шине у нас подключен GPIOB. Открываем даташит на микроконтроллер, ищем вот эту таблицу:

Рис. 8. Таблица шин и периферийных устройств

GPIOB у нас подключен к шине APB2. Идем в Reference manual, открываем раздел про RCC, переходим к пункту 7.3.7 APB2 peripheral clock enable register (RCC_APB2ENR). С помощью этого регистра можно подать тактовый сигнал на устройства шины APB2:

Рис. 9. Регистр RCC_APB2ENR

В регистре RCC_APB2ENR много флагов для разной периферии, в том числе и для нашего GPIOB, флаг называется IOPBEN. Перед началом инициализации PB12 нам надо установить этот бит в единицу.

Поехали программировать! За основу возьмем проект из 2-й части: https://github.com/DiMoonElec/stm32f103c8_empty_project. Создадим функцию инициализации порта:

Первым делом включаем тактирование порта GPIOB:

Далее настройка порта. Нам нужен пин PB12. Его конфигурационные биты находятся в регистре CRH:

Все Настройка завершена! Вот полный код функции:

Теперь управление. Для этого нам понадобится регистр ODR (рис. 4). Вот функция установки высокого уровня на PB12:

Ни чего сложного, почти как на AVR-ках! Однако, у нас все же более серьезный микроконтроллер, и у него есть некоторые фишки. Выражения вида GPIOB->ODR |= (1 Метки: CMSIS, IAR, STM32, Обучалка. Закладка Постоянная ссылка.

18 комментариев: Программирование STM32. Часть 5: Порты ввода-вывода GPIO

А почему мы не используем регистр BSRR для записи нуля а пользуемся BBR? Из тех же соображений что и ODR. И что будет если в него в двух позициях записать 1 и на установку 1 и на установку 0

Можно и BBR, разницы ни какой нет. Можно использовать и ODR, но в этом случае нужно выполнять операцию типа Чтение-Модификация-Запись, а для BSRR и BBR только запись — это быстрее и нет возможности возникновения нарушения атомарности операции

Что будет, если в BSRR записать единицы на установку и сброс одного и того же пина GPIO я без понятия, надо попробовать)) В документации такого вроде не попадалось

Нашел в даташите: If both BSx and BRx are set, BSx has priority.

Здравствуйте. у меня вопрос — в проекте для задержки между вкл. и выкл. светодиода используется цикл for.а как обстоят дела в стм32 насчет служебных ф-ий типа Delay_ms() как в GCC для 8-ми битных АВРок?

Сам использую компилятор от IAR, насколько знаю, для ARM-ов ни чего подобного нет, хотя для тех же AVR-ок есть функция __delay_cycles(). В реальных проектах если надо генерить сигнал с периодом больше 1ms и с не очень большой точностью поддержания периода, то реализую это на программных таймерах и конечных автоматах, если периоды меньше и/или нужна большая точность — то аппаратные таймеры. Если же нужно выдать короткий управляющий импульс для какой-то микры на плате — то использую задержку на for, что-то типа for(i=0; i Den пишет:

Нашел на просторах инета такой интересный код

Никаких таймеров, все быстро и компактно. Только у меня в include надо core_cm3.h вместо stm32f10x_tim.h. Использую STM32CubeIDE

и функцию delta желательно переписать с учетом переполнения счетчика, чтобы не получить непонятные глюки на граничных значениях

Здравствуйте. еще вопросик — например я затактировался от HSE через PLL x9. в итоге частота 72 Мгц. Далее например подключаю GPIOB : RCC->APB2ENR|=RCC_APB2ENR_IOPBEN; .Но ведь выход порта В я могу настроить только на макс. 50Мгц , Значит ли это что и делитель АРВ2 в этом случае настроить как минимум на HCLK/2 поскольку частота на этой шине 72 Мгц?

То, что настраивается в регистрах GPIO как максимальная скорость работы, как ни странно, не имеет ни какого отношения к тактированию. Этими битами настраивается максимальный потребляемый ток данного пина. Пример: если настроить пин на максимальную частоту 2 МГц, но при этом подать 72 МГц, то сигнал на этом пине будет больше похож на синус, чем на меандр. Если же настроить на 50 МГц, то в этом случае на выходе будет уже что-то более-менее похожее на меандр

Где-то обсуждали (ссылаясь на доки), что частота переключения пинов в STMках отражает на самом деле скорость нарастания/спада фронта, а значение частоты — это максимальная частота, при которой сумма времени нарастания и спада не более двух третей от стабильного уровня импульса. Быстрое переключение выводов может оказывать электромагнитное влияние на работу самого микроконтроллера. Поэтому, если нет необходимости в высоких частотах, предлагается устанавливать опцию более низкой частоты (т.е. более медленные изменения уровня сиглала на ножках) в целях более высокой помехоустойчивости. При этом, если повышенная частота нужна, то такая опция такая есть.

Рейтинг
( Пока оценок нет )
Загрузка ...
Adblock
detector