RCC и GPIO: мигаем светодиодом
У STM32 после сброса тактирование почти всей периферии выключено, а каждый вывод — вход без подтяжки. Чтобы зажечь светодиод, нужно сначала включить порт в RCC, затем перевести вывод в режим выхода и только потом менять его уровень.
Обновлено Редакция GAW
STM32 с нуляурок 3 из 830 мин
Цель урока: Включать тактирование порта в RCC, настраивать режим вывода полями CNF и MODE регистров CRL и CRH, менять уровень через BSRR и мигать светодиодом PC13.
Светодиод на Blue Pill подключён к выводу PC13 — тринадцатому биту порта C — катодом: анод через резистор идёт к 3,3 В, и светодиод горит, когда на PC13 низкий уровень (см. страницу Blue Pill). Значит, нужно настроить PC13 выходом и менять его уровень. Для этого понадобятся два блока: RCC (Reset and Clock Control), который раздаёт тактовые сигналы периферии, и порт GPIOC.
Шаг 1. Включить тактирование порта
После сброса в регистре RCC_APB2ENR (смещение 0x18 от базы RCC 0x40021000, раздел 7.3.7 RM0008, с. 112) все биты нулевые: ни порты, ни USART1, ни АЦП не тактируются. Пока порт не тактируется, запись в его регистры не действует, а чтение, как предупреждает RM0008, может возвращать 0. Порты A, B и C сидят на шине APB2 и включаются битами IOPAEN (2), IOPBEN (3) и IOPCEN (4):
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; /* clock for GPIOC */
Регистр RCC_AHBENR после сброса равен 0x0000 0014 (раздел 7.3.6, с. 111): включены только тактирование SRAM и интерфейса флеш-памяти. Всё остальное — выключено, и это осознанное решение: блок без тактового сигнала почти не потребляет. Подробнее — в статье глоссария «Отключение тактирования».
Шаг 2. Режим вывода: CRL и CRH
У порта STM32F1 семь регистров (раздел 9.1): два регистра конфигурации CRL и CRH, входные данные IDR, выходные ODR, установка и сброс BSRR, сброс BRR и блокировка LCKR. Режим каждого вывода задают 4 бита: CNF[1:0] и MODE[1:0]. В CRL (смещение 0x00) — выводы 0–7, в CRH (смещение 0x04) — выводы 8–15. Для вывода n поле начинается с бита 4 × (n mod 8): у PC13 это биты 23:20 регистра CRH — MODE13 в битах 21:20, CNF13 в битах 23:22.
| MODE | Значение (табл. 21) |
|---|---|
| 00 | вход (состояние после сброса) |
| 01 | выход, до 10 МГц |
| 10 | выход, до 2 МГц |
| 11 | выход, до 50 МГц |
| CNF | Если MODE = 00 (вход) | Если MODE ≠ 00 (выход) |
|---|---|---|
| 00 | аналоговый вход | выход push-pull |
| 01 | плавающий вход (после сброса) | выход с открытым стоком |
| 10 | вход с подтяжкой вверх или вниз | альтернативная функция, push-pull |
| 11 | — (резерв) | альтернативная функция, открытый сток |
После сброса CRL и CRH равны 0x4444 4444 (раздел 9.2.1, с. 171): у каждого вывода 0100 — CNF = 01, MODE = 00, плавающий вход (раздел 9.1.1). Выводы JTAG — PA13, PA14, PA15 и PB4 — после сброса подтянуты, а PA13 и PA14 заняты SWD.
«Скорость» в поле MODE — это ограничение крутизны фронтов выходного каскада, а не тактовая частота порта. Для светодиода хватит 2 МГц, а для PC13 больше и нельзя: по примечанию 5 к таблице 5 DS5319 выводы PC13–PC15 питаются через ключ, пропускающий до 3 мА, как выходы они ограничены частотой 2 МГц при нагрузке до 30 пФ и не должны быть источником тока. Итак, для PC13: MODE = 10, CNF = 00 — выход push-pull, 2 МГц.
GPIOC->CRH = (GPIOC->CRH & ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13))
| (0x2u << GPIO_CRH_MODE13_Pos); /* MODE13 = 10, CNF13 = 00 */
Сначала маска стирает оба поля, потом вписывается нужное значение — остальные 7 выводов регистра не меняются. Регистры GPIO читают и пишут только целыми словами (раздел 9.2), поэтому обращение через GPIOC->CRH к 32-битному полю структуры — правильный способ. Посчитать маску или проверить готовое число поможет калькулятор битовых масок.
Шаг 3. Уровень вывода: ODR, BSRR и BRR
Уровень выхода задаёт бит регистра ODR, но менять его лучше через BSRR (раздел 9.2.5, с. 173). Это регистр только для записи: единица в бите n (поле BSn, биты 15:0) устанавливает бит n регистра ODR, единица в бите 16 + n (поле BRn, биты 31:16) — сбрасывает, нули ничего не меняют. Если в одной записи заданы и BSn, и BRn, побеждает BSn. Регистр BRR делает только сброс, его биты 15:0 — те же BRn.
GPIOC->BSRR = GPIO_BSRR_BR13; /* ODR13 = 0: PC13 low, LED on */
GPIOC->BSRR = GPIO_BSRR_BS13; /* ODR13 = 1: PC13 high, LED off */
Главное свойство BSRR — атомарность: RM0008 (раздел 9.1.2) прямо говорит, что запрещать прерывания при такой записи не нужно, потому что она меняет только выбранные биты за одно обращение по шине APB2. А GPIOC->ODR |= … — это три действия: чтение, изменение, запись. Если между чтением и записью сработает прерывание и изменит другой бит порта C, при записи его изменение пропадёт. Подробнее о таких гонках — в статье глоссария «Состояние гонки».
Программа
/* main.c, lesson 3: blink the Blue Pill LED on PC13 */
#include "stm32f1xx.h"
/* Crude busy-wait: the time depends on the clock and on the compiler */
static void delay(volatile uint32_t n)
{
while (n--) { }
}
int main(void)
{
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; /* 1. clock for GPIOC */
GPIOC->CRH = (GPIOC->CRH & ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13))
| (0x2u << GPIO_CRH_MODE13_Pos); /* 2. PC13: push-pull, 2 MHz */
for (;;) {
GPIOC->BSRR = GPIO_BSRR_BR13; /* 3. PC13 low: LED on */
delay(200000u);
GPIOC->BSRR = GPIO_BSRR_BS13; /* PC13 high: LED off */
delay(200000u);
}
}
Замените main.c из урока 1 этим файлом и выполните make flash — Makefile менять не нужно, пути к заголовкам CMSIS в нём уже есть. Светодиод замигает: после сброса STM32F103 работает от внутреннего RC-генератора HSI на 8 МГц, и пустой цикл на 200 000 итераций длится доли секунды. Точное время зависит от того, во что компилятор превратит цикл; параметр объявлен volatile, чтобы оптимизатор не выбросил цикл, который «ничего не делает». Задержку с точностью до миллисекунды сделаем на таймере SysTick в уроке 4.
Что прячется за RCC и GPIOC
RCC и GPIOC в stm32f103xb.h — это указатели на структуры, поля которых повторяют порядок регистров блока. Например, GPIOC — это ((GPIO_TypeDef *)GPIOC_BASE), где база порта C — 0x40011000, а поле CRH стоит вторым, со смещением 0x04. Запись GPIOC->CRH = x компилируется в одну команду записи слова по адресу 0x40011004. Поля объявлены volatile (через макрос __IO), поэтому компилятор не выбрасывает и не переставляет обращения к ним. Адреса и биты всех регистров GPIO и RCC серии с их значениями после сброса собраны на страницах атласа регистров GPIO STM32F1 и регистров RCC STM32F1.
На STM32F4
У STM32F411 на Black Pill порты сидят на шине AHB1, а режимы выводов разнесены по четырём регистрам. Ниже они по RM0368 для STM32F401 (разд. 8.4.1–8.4.4, с. 158–160); значения сброса MODER в RM0383 для F411 те же:
| Регистр | Биты на вывод | Значения |
|---|---|---|
MODER | 2 | 00 — вход, 01 — выход, 10 — альтернативная функция, 11 — аналог |
OTYPER | 1 | 0 — push-pull, 1 — открытый сток |
OSPEEDR | 2 | 00 low, 01 medium, 10 high, 11 very high |
PUPDR | 2 | 00 — без подтяжки, 01 — вверх, 10 — вниз |
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
GPIOC->MODER = (GPIOC->MODER & ~GPIO_MODER_MODER13) | GPIO_MODER_MODER13_0; /* 01: output */
GPIOC->BSRR = GPIO_BSRR_BR13; /* LED on */
BSRR у F4 устроен так же, как у F1. Значение сброса MODER у порта A — 0xA800 0000: выводы PA13, PA14 и PA15 сразу в режиме альтернативной функции для отладки, поэтому при записи в GPIOA->MODER целым числом легко отключить себе SWD. На Black Pill светодиод тоже на PC13 и тоже горит при нуле — по схеме WeAct MiniF4x1Cx V3.1 он подключён через резистор 1,5 кОм к 3,3 В (подробно — на странице Black Pill).
Задание
- Что станет с выводами PC8–PC15, если вместо строки с маской написать
GPIOC->CRH = 0x00200000;? - Подключите кнопку между PB12 и GND. Настройте PB12 входом с подтяжкой вверх и сделайте так, чтобы светодиод горел, пока кнопка нажата.
Ответ и решение
-
В поле PC13 запишется 0010 — нужный режим, но в остальные семь полей — 0000, то есть CNF = 00, MODE = 00: аналоговый вход. До записи они были плавающими входами (0100). На Blue Pill PC14 и PC15 подключены к часовому кварцу, а остальных выводов порта C на контактах платы нет, так что вреда не будет. Но на порту A или B такая запись сделала бы аналоговыми, например, вход приёмника USART: в этом режиме триггер Шмитта выключен, и IDR читается как 0 (RM0008, разд. 9.1.10). Привычка «стереть маской, потом вписать» защищает от этой ошибки.
-
Подтяжка вверх — CNF = 10, MODE = 00, а направление подтяжки задаёт бит ODR: 1 — вверх, 0 — вниз (табл. 20 RM0008):
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN;
GPIOB->CRH = (GPIOB->CRH & ~(GPIO_CRH_MODE12 | GPIO_CRH_CNF12))
| (0x2u << GPIO_CRH_CNF12_Pos); /* PB12: input with pull */
GPIOB->BSRR = GPIO_BSRR_BS12; /* ODR12 = 1: pull-up */
GPIOC->CRH = (GPIOC->CRH & ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13))
| (0x2u << GPIO_CRH_MODE13_Pos);
for (;;) {
if (GPIOB->IDR & GPIO_IDR_IDR12)
GPIOC->BSRR = GPIO_BSRR_BS13; /* released: LED off */
else
GPIOC->BSRR = GPIO_BSRR_BR13; /* pressed: LED on */
}
Что дальше
В уроке 4 переведём STM32F103 с 8 МГц HSI на 72 МГц от кварца через PLL и заведём системный таймер SysTick для точных задержек. Все режимы выводов, токи и выводы, допускающие 5 В, разобраны в статье «GPIO STM32», а схемы выходных каскадов — в статьях глоссария push-pull и «Открытый сток». Готовый код инициализации выводов в стиле регистров, LL или HAL сгенерирует генератор инициализации STM32.
Частые вопросы
Почему вывод не переключается, хотя регистры GPIO записаны?
Скорее всего, не включено тактирование порта в RCC_APB2ENR. Пока бит IOPxEN равен нулю, порт не тактируется, запись в его регистры не действует, а чтение по RM0008 может возвращать 0. Включайте тактирование порта первой строкой, до любой записи в его CRL, CRH или BSRR.
Чем BSRR лучше записи в ODR?
Строка GPIOC->ODR |= (1 << 13) — это чтение, изменение и запись: если между чтением и записью прерывание изменит другой бит того же порта, его изменение потеряется. Запись в BSRR меняет только биты, где стоят единицы, одной операцией, поэтому её не нужно защищать от прерываний (RM0008, разд. 9.1.2).
Можно ли подключить светодиод к PC13 анодом, чтобы он горел от единицы?
Нет. По примечанию 5 к таблице 5 DS5319 выводы PC13–PC15 питаются через ключ на 3 мА и не должны работать источником тока — например, зажигать светодиод. Поэтому на Blue Pill светодиод подключён к PC13 катодом и горит при нуле. Для своих светодиодов берите другие выводы, например PA0–PA7, PB0, PB1 или PB5–PB15. PB3 и PB4 после сброса заняты JTAG и освобождаются только записью SWJ_CFG в AFIO_MAPR (RM0008, разд. 9.3.5), а PB2 на Blue Pill служит выводом BOOT1 и подключён к перемычке.
Источники
- STMicroelectronics. RM0008 Rev 21. Reference manual STM32F101xx–STM32F107xx — разд. 7.3.6 (с. 111): RCC_AHBENR, смещение 0x14, сброс 0x0000 0014; разд. 7.3.7 (с. 112): RCC_APB2ENR, смещение 0x18, сброс 0x0000 0000, при выключенном тактировании регистры периферии могут читаться как 0; разд. 9.1 (с. 161): у порта CRL, CRH, IDR, ODR, BSRR, BRR и LCKR; разд. 9.1.1: после сброса выводы — плавающие входы (CNF = 01, MODE = 00), JTAG-выводы с подтяжками; разд. 9.1.2: запись в BSRR и BRR меняет биты ODR одной атомарной записью; табл. 20 и 21 (с. 161): режимы CNF/MODE, подтяжка вверх или вниз по биту ODR, скорость 10, 2 и 50 МГц; разд. 9.2 (с. 171): регистры GPIO — только словами; разд. 9.2.1: CRL, сброс 0x4444 4444; разд. 9.1.10: в аналоговом режиме триггер Шмитта выключен, IDR читается как 0; разд. 9.2.5 (с. 173): BSRR, BRy в битах 31:16, BSy в битах 15:0, при обоих единицах приоритет у BSx
- STMicroelectronics. DS5319 Rev 20. STM32F103x8, STM32F103xB datasheet — табл. 5, примечание 5: PC13–PC15 питаются через ключ, который пропускает до 3 мА; как выходы — не выше 2 МГц при нагрузке до 30 пФ, источником тока (например, для светодиода) быть не должны; разд. 5.3.13, I/O port characteristics, Output driving current: остальные выводы — до ±8 мА, с ослабленными VOL/VOH — до ±20 мА, PC13–PC15 — до ±3 мА
- STMicroelectronics. cmsis-device-f1 v4.3.5: Include/stm32f103xb.h — RCC_APB2ENR_IOPCEN, GPIO_CRH_MODE13 и GPIO_CRH_CNF13 (позиции 20 и 22), GPIO_BSRR_BS13, GPIO_BSRR_BR13; GPIOC по адресу 0x40011000, RCC — 0x40021000
- STMicroelectronics. RM0368 Rev 6 (STM32F401) и RM0383 Rev 4 (STM32F411); cmsis-device-f4 v2.6.11, stm32f411xe.h — RM0368, разд. 8.4.1–8.4.4 (с. 158–160): MODER (00 вход, 01 выход, 10 альтернативная функция, 11 аналог; сброс 0xA800 0000 у порта A, 0x0000 0280 у порта B), OTYPER, OSPEEDR, PUPDR; RM0383, с. 158 — те же значения сброса MODER; в заголовке F411 — RCC_AHB1ENR_GPIOCEN, GPIO_MODER_MODER13_0
- Исходная схема Blue Pill (vcc-gnd.com, 26.01.2016), опубликована STM32-base — пользовательский светодиод подключён к PC13 катодом и горит при низком уровне
- WeAct Studio. WeActStudio.MiniSTM32F4x1 (коммит 05380f5): схема MiniF4x1Cx_V31 — на Black Pill V3.1 синий светодиод — на PC13 через резистор 1,5 кОм от 3,3 В, горит при низком уровне
Нашли ошибку?
Смотрите также
- GPIO STM32Режимы выводов, регистры F1 и F4, BSRR, AF, скорость, токи, 5 В, код
- STM32 Blue PillSTM32F103C8T6: функции выводов, 5 В-выводы, питание, загрузка
- Включение тактирования периферииБиты RCC, без которых периферия STM32 не работает
- Двухтактный выходВыход push-pull: оба уровня формирует сам, без подтяжки
- Битовые маскиПоле регистра: маска, сдвиг, чтение и запись, код на C