Генератор пишет код настройки периферии STM32 так, как его пишут по справочному руководству: включить тактирование шины, настроить выводы, записать регистры периферии и в последнюю очередь — бит включения. Все числа он считает сам и сразу проверяет: делители PLL и шин — по правилам калькулятора тактирования, делитель USART — по формуле RM0008 и RM0368 с ошибкой скорости, предделитель и период таймера — как калькулятор таймера. Выводы и альтернативные функции берутся из данных атласа — тех же, по которым нарисованы карточки STM32F103C8 и STM32F411CE.
Коротко
- USART: скорость = fCK / (8 · (2 − OVER8) · USARTDIV); в USART_BRR — 12 бит целой части и 4 бита дробной (3 бита при OVER8 = 1, только у F4).
- fCK: USART1 (и USART6 у F4) — от PCLK2, остальные — от PCLK1: при 72 МГц у STM32F103 это 72 и 36 МГц.
- Таймер: f = TIMxCLK / ((PSC + 1) · (ARR + 1)); TIMxCLK = PCLK, если делитель APB равен 1, иначе 2 · PCLK.
- ШИМ, режим 1: выход активен, пока CNT < CCR, заполнение = CCR / (ARR + 1).
- TIM1 и TIM8: без бита MOE в TIMx_BDTR выходы не работают.
Что генерирует инструмент
Один файл .c: подключение заголовка (stm32f1xx.h, заголовков LL или stm32f1xx_hal.h), функция тактирования clock_init() (в стиле HAL — SystemClock_Config()), gpio_init(), usartN_init(), timN_init(), вспомогательные uart_putc(), uart_puts(), uart_getc(), обработчики прерываний с именами из стартового файла ST и main(), который вызывает всё по порядку и в цикле отвечает эхом на принятые байты. При приёме по прерыванию обработчик кладёт байты в кольцевой буфер на 64 байта, а uart_getc() забирает их без ожидания — по схеме «один писатель, один читатель» из статьи о прерываниях и общих данных. Прерывание таймера увеличивает счётчик timN_ticks — от него удобно отсчитывать время в основном цикле.
Каждая функция включает тактирование своей периферии и своих портов одной записью на шину и читает регистр обратно — так делают макросы __HAL_RCC_xxx_CLK_ENABLE(), чтобы тактирование гарантированно включилось до первого обращения. Выводы настраиваются в том же месте, где периферия: сначала уровень выхода, тип, скорость и подтяжка, последним — режим в MODER (у F4) или CNF и MODE (у F1), чтобы вывод не побывал выходом с непредсказуемым уровнем.
Стиль выбирается над кодом: регистры CMSIS, LL или HAL. Чем они различаются и когда что брать, рассказано в статье HAL, LL и регистры. Код в стиле HAL похож на то, что выдаёт STM32CubeMX, и рассчитан на проект из STM32CubeIDE: если в нём уже есть SysTick_Handler(), уберите его копию из файла.
Тактирование
Источник SYSCLK — внутренний HSI (8 МГц у F1, 16 МГц у F4, без кода — так микроконтроллер работает после сброса), кварц HSE напрямую или PLL от HSI либо HSE. Вместо кварца на OSC_IN можно подать готовый тактовый сигнал — режим HSE bypass (бит HSEBYP, RM0008 с. 95, RM0368 с. 96): так тактируются платы Nucleo-64, где сигнал 8 МГц приходит с MCO отладчика ST-LINK (UM1724, 7.9.1). Для PLL генератор берёт лучший вариант калькулятора тактирования STM32: ближайшую к заданной частоту, минимальные делители шин в пределах справочного руководства и такты ожидания флеш-памяти. Типичные результаты: STM32F103 с кварцем 8 МГц — HSE × 9 = 72 МГц, APB1 делится на 2 (36 МГц), таймеры на APB1 всё равно получают 72 МГц; STM32F401 с кварцем 25 МГц — 84 МГц, STM32F411 — 100 МГц с масштабом регулятора 1. От HSI у F103 больше 64 МГц не получить: на вход PLL идёт HSI / 2 = 4 МГц, а множитель не больше 16, — генератор об этом предупредит. Такты ожидания флеш-памяти у F401 и F411 взяты для питания 2,7–3,6 В (RM0368 табл. 6, RM0383 табл. 5): при более низком напряжении их нужно больше, об этом напоминает комментарий в коде. В стиле HAL код начинается с проверки _Static_assert(HSE_VALUE == …): HAL считает частоты шин и делитель USART от HSE_VALUE проекта, а в шаблонах ST там стоит 8 или 25 МГц.
USART: делитель, ошибка и OVER8
Делитель USARTDIV записывается в USART_BRR как число с фиксированной точкой: старшие 12 бит — целая часть, младшие 4 — дробная в шестнадцатых. Поэтому BRR = fCK / скорость, округлённое до целого. Генератор берёт ближайшее значение и показывает фактическую скорость с ошибкой. В таблице — значения для стиля регистров.
| Скорость, бод | USART1 при 72 МГц | USART2 при 36 МГц | USART1 STM32F401 при 84 МГц | USART1 STM32F411 при 100 МГц |
|---|---|---|---|---|
| 9600 | 0x1D4C (0 %) | 0x0EA6 (0 %) | 0x222E (0 %) | 0x28B1 (−0,003 %) |
| 115 200 | 0x0271 (0 %) | 0x0139 (−0,16 %) | 0x02D9 (+0,023 %) | 0x0364 (+0,006 %) |
| 921 600 | 0x004E (+0,16 %) | 0x0027 (+0,16 %) | 0x005B (+0,16 %) | 0x006D (−0,45 %) |
Значения для 72 и 36 МГц совпадают с таблицей 192 RM0008, для 8 и 12 МГц тесты сверяют результат с таблицами 74 и 75 RM0368. Скорость 115 200 бод от 36 МГц — пограничный случай: 36 000 000 / 115 200 = 312,5, и BRR = 312 и 313 дают одинаковые ±0,16 %. Генератор в стиле регистров берёт 313, а HAL и LL — 312, как в таблице RM0008.
В стилях LL и HAL делитель считает сама библиотека (LL_USART_SetBaudRate, HAL_UART_Init), и генератор показывает её результат. Её макросы сначала отбрасывают всё, что меньше сотых долей USARTDIV, и только потом округляют дробную часть, поэтому на высоких скоростях значение иногда на единицу отличается от ближайшего: 921 600 бод от 42 МГц дают у HAL 0x002D (+1,27 %) вместо 0x002E (−0,93 %), от 100 МГц — 0x006C (+0,47 %) вместо 0x006D (−0,45 %). В стиле регистров записывается ближайшее значение.
У STM32F4 есть бит OVER8: 8 выборок на бит вместо 16 удваивают предельную скорость (до fPCLK / 8), но уменьшают допуск приёмника на расхождение частот. Шаг делителя при этом не меняется, поэтому в режиме «авто» генератор включает OVER8 только тогда, когда скорость с 16 выборками недостижима. Приёмник USART работает, пока сумма ошибки передатчика, округления делителя, расхождения кварцев и искажений линии меньше его допуска (RM0008 27.3.5, RM0368 19.3.5). Допуск зависит от бита M, OVER8 и того, есть ли у делителя дробная часть: при 16 выборках — 3,75 % (M = 0) и 3,41 % (M = 1) с нулевой дробной частью и 3,33 и 3,03 % с ненулевой; при OVER8 = 1 — 2,5 и 2,27 % или 2 и 1,82 % (RM0368 табл. 84 и 85, у F1 — RM0008 табл. 193 и 194 для 16 выборок). Если ошибка скорости не меньше допуска, генератор сообщает об ошибке; если больше половины допуска — предупреждает: на вторую сторону и линию остаётся мало (это правило генератора, а не руководства). Запас по кадру подробнее считает калькулятор скорости UART. Подробнее о самом интерфейсе — в статье об UART у STM32.
Порядок записи — как в HAL_UART_Init: модуль выключен (UE = 0), затем стоп-биты в CR2, формат кадра и включение приёмника и передатчика в CR1, CR3, делитель BRR, разрешение прерывания в NVIC и последним — UE. Бит M выбирает 8 или 9 бит вместе с битом чётности, поэтому кадр 8E1 — это M = 1 и PCE = 1, а 7E1 — M = 0 и PCE = 1. При 7 битах данных принятый бит чётности оказывается в старшем разряде DR (RM0008 27.6.2), и код обнуляет его маской 0x7F, как это делает HAL. Кадров с 9 битами данных без чётности генератор не предлагает: вспомогательные функции работают с байтами, а HAL при таком кадре читает и пишет 16-битные слова.
Таймер: ШИМ и период
Генератор перебирает предделитель PSC от 0 до 65 535 и для каждого берёт ближайший ARR. Из вариантов с наименьшей ошибкой выигрывает меньший PSC: тогда ARR больше и шаг заполнения ШИМ мельче. У STM32F401 и F411 таймеры TIM2 и TIM5 32-битные, и ARR может быть больше 65 535.
| Таймер | TIMxCLK | Задание | PSC | ARR |
|---|---|---|---|---|
| TIM2, STM32F103 | 72 МГц | ШИМ 1 кГц или период 1 мс | 1 | 35 999 |
| TIM2, STM32F103 | 72 МГц | период 1 с | 1124 | 63 999 |
| TIM3, STM32F401 | 84 МГц | ШИМ 50 Гц (сервопривод) | 27 | 59 999 |
| TIM2, STM32F401 | 84 МГц | период 1 с | 0 | 83 999 999 |
| TIM1, STM32F411 | 100 МГц | ШИМ 20 кГц | 0 | 4999 |
В режиме ШИМ канал работает в режиме 1 (OCxM = 110) с предзагрузкой CCR и ARR: новые значения вступают в силу на следующем событии обновления, без рваных периодов. Перед запуском генератор записывает бит UG в TIMx_EGR — так PSC, ARR и CCR загружаются сразу, как требует RM0008 (с. 317). Событие UG взводит флаг UIF, поэтому перед разрешением прерывания флаг сбрасывается — иначе первое прерывание пришло бы сразу после запуска. Для TIM1 и TIM8 генератор ставит бит MOE.
В режиме «период» таймер генерирует прерывание обновления с заданным периодом; по желанию вывод канала переключается на каждом периоде (OCxM = 011), и на нём получается меандр половинной частоты. У TIM1 в STM32F401, F411 и STM32F103xF/xG прерывание обновления делит вектор с TIM10 (TIM1_UP_TIM10_IRQHandler), обработчик проверяет флаг своего таймера. Приоритет прерываний — 5 из 16; как он раскладывается на группу и подгруппу, считает калькулятор приоритетов NVIC. О режимах таймеров подробно — в статье о таймерах STM32.
Выводы, ремап и отладка
У STM32F1 нет мультиплексора альтернативных функций: вывод периферии фиксирован, а перенести его можно только целой группой через регистр AFIO_MAPR — например, USART1 с PA9/PA10 на PB6/PB7 или USART3 на PC10/PC11. Генератор показывает в списке выводов только реальные варианты корпуса с подписью ремапа и сам пишет нужное поле. Поле SWJ_CFG в том же регистре только для записи и при чтении возвращает что угодно, поэтому запись делается так же, как в HAL: SWJ_CFG = 111 («нет изменений») или 010, когда нужны PA15, PB3 или PB4. Режим вывода у F1 задают поля CNF и MODE в GPIOx_CRL и GPIOx_CRH, а подтяжка входа выбирается битом ODR: 1 — к питанию, 0 — к земле. Подробно об этом — в статье о GPIO STM32 и на странице регистров AFIO.
У STM32F4 альтернативная функция выбирается номером AF в регистрах AFRL и AFRH: USART1 и USART2 — AF7, USART6 — AF8, TIM1 и TIM2 — AF1, TIM3–TIM5 — AF2, TIM9–TIM11 — AF3. Генератор берёт номер из данных выбранного корпуса, поэтому TX и RX можно выбрать на разных разрешённых выводах.
| Проверка | Что сообщает генератор |
|---|---|
| Частота SYSCLK и шин | точно не получить — предупреждение с ближайшей частотой; превышение пределов шин — ошибка |
| Скорость USART | BRR вне допустимого (меньше 16 шагов или больше 4095,9) — ошибка; ошибка скорости не меньше допуска приёмника по таблицам RM — ошибка, больше половины допуска — предупреждение; OVER8 = 1 — пояснение о меньшем допуске |
| Период и частота таймера | меньше двух тактов или длиннее, чем PSC = 65 535 и ARR = 65 535, — ошибка; неточная частота и разрешение ШИМ меньше 6 бит — предупреждение |
| Выводы | один вывод у двух блоков, GPIO на PA13/PA14 у F1, вывод кварца при тактировании от HSE — ошибка; PA13/PA14 у F4 — предупреждение; PA15, PB3, PB4 — пояснение |
Код построен по данным регистров и проверен по именам, но не скомпилирован на сайте, поэтому перед прошивкой соберите его в своём проекте и сверьте с руководством. Для классических AVR есть такой же генератор кода инициализации AVR; обзор линеек — в разделах STM32F1 и STM32F4, о прерываниях и NVIC — в статье о прерываниях STM32.
Частые вопросы
Какие микроконтроллеры поддерживает генератор?
STM32F103 всех объёмов памяти (от F103x4 до F103xG) и STM32F401, STM32F411 — 39 корпусов из атласа сайта, включая платы Blue Pill (STM32F103C8T6) и Black Pill (STM32F401CC, STM32F411CE). Для каждого корпуса генератор знает, какие USART и таймеры в нём есть и на какие выводы они выходят. Другие семейства (F0, G0) пока не поддерживаются: у них другой блок USART и другие регистры.
Код компилируется?
Сайт этот код не компилировал. Каждое имя в нём — регистр, бит, функция LL или HAL, константа, номер прерывания и имя обработчика — тест сверяет со списками из заголовков ST (cmsis-device-f1 v4.3.5, cmsis-device-f4 v2.6.11, драйверы HAL/LL v1.1.10 и v1.8.5) на тысячах сочетаний настроек. Для сборки нужен проект с этими заголовками и макросом устройства (например, -DSTM32F103xB), для HAL — ещё файл stm32f1xx_hal_conf.h или stm32f4xx_hal_conf.h. Перед прошивкой соберите код и проверьте на своей плате.
Чем отличаются стили CMSIS, LL и HAL?
CMSIS — прямые записи в регистры с именами битов из заголовка устройства: самый короткий код, по нему видно, что происходит в железе. LL — тонкие встроенные функции ST поверх тех же регистров. HAL — структуры инициализации и функции вроде HAL_UART_Init, как в коде STM32CubeMX; HAL сам считает делитель USART и частоты шин — от HSE_VALUE из файла stm32f1xx_hal_conf.h или stm32f4xx_hal_conf.h, поэтому код проверяет при сборке, что HSE_VALUE равен частоте кварца, — и требует HAL_Init и таймер SysTick. Значения регистров во всех трёх стилях одни и те же, кроме округления USART_BRR (см. раздел об USART).
Почему ШИМ на TIM1 не появляется на выводе?
У расширенных таймеров TIM1 и TIM8 выходы дополнительно разрешает бит MOE в регистре TIMx_BDTR: пока он равен нулю, выводы в неактивном состоянии, даже если канал включён битом CCxE (RM0008, с. 359). Генератор ставит MOE для TIM1 и TIM8 во всех стилях; HAL_TIM_PWM_Start делает это сам.
Зачем генератор выключает JTAG?
PA15, PB3 и PB4 после сброса принадлежат JTAG. У STM32F1 они станут обычными выводами (или выходами TIM2 и TIM3 после ремапа) только после записи SWJ_CFG = 010 в AFIO_MAPR — JTAG выключается, а SWD на PA13 и PA14 продолжает работать, так что отладчик ST-Link не теряет связь. Выводы PA13 и PA14 генератор не отдаёт: тогда пропала бы и отладка. У STM32F4 SWJ_CFG нет — вывод просто переводится в другой режим через MODER. PA13 и PA14 у F4 генератор отдаёт с предупреждением: после этой записи отладчик теряет связь, а после сброса выводы снова работают как SWD (RM0368, 8.3.1), поэтому для повторного подключения может понадобиться отладчик с подключённым выводом NRST.
Источники
- STMicroelectronics. RM0008 Rev 21. Reference manual: STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx — с. 95 и 99 — HSE bypass (внешний сигнал до 25 МГц), бит HSEBYP; с. 94 — удвоение частоты таймеров при делителе APB ≠ 1; табл. 20 и 21 (с. 161), 9.2.1 (с. 171) — CNF и MODE в GPIOx_CRL/CRH, подтяжка через ODR; табл. 22–24 (с. 166–167) — режимы выводов таймеров и USART; 9.3, табл. 36–53 (с. 175–180) и 9.4.2 AFIO_MAPR (с. 184–186) — ремапы и SWJ_CFG; с. 317–318 — ШИМ, OCxPE, ARPE, UG; с. 359 — MOE; 27.3.4 и табл. 192 (с. 798–799) — USARTDIV и USART_BRR; 27.3.5, табл. 193 и 194 (с. 800) — допуск приёмника; 27.6.2 (с. 820) — бит чётности в старшем разряде DR; 27.6.4 (с. 821) — M, PCE, PS
- STMicroelectronics. RM0368 Rev 6. Reference manual: STM32F401xB/C and STM32F401xD/E — с. 95 — TIMxCLK; табл. 24 (с. 147–148) и 8.4.1–8.4.9 (с. 158–162) — MODER, OTYPER, OSPEEDR, PUPDR, AFRL/AFRH, состояние выводов отладки после сброса; с. 46, табл. 6 — такты ожидания флеш-памяти по напряжению питания; с. 96 и 104 — HSE bypass, бит HSEBYP; с. 316 — 32-битные TIM2 и TIM5; 19.3.4 (с. 519–521) — формула скорости с OVER8, примеры BRR; табл. 74 и 75 (с. 521–522) — эталон тестов; с. 526 — USART1 и USART6 на PCLK2; 19.3.5, табл. 84 и 85 (с. 529–530) — допуск приёмника на расхождение частот
- STMicroelectronics. RM0383 Rev 4. Reference manual: STM32F411xC/E — сверка с RM0368: с. 45, табл. 5 — такты ожидания флеш-памяти; с. 95 — TIMxCLK; с. 96 — HSE bypass; с. 148 и 158 — выводы отладки и сброс MODER; с. 313 — 32-битные TIM2 и TIM5; с. 515–517 — USART_BRR и OVER8; с. 522 — USART1 и USART6 на PCLK2; табл. 83 и 84 (с. 525–526) — допуск приёмника
- STMicroelectronics. UM1724 Rev 17. STM32 Nucleo-64 boards (MB1136) — 7.9.1 (с. 25): по умолчанию HSE платы — сигнал MCO 8 МГц от микроконтроллера ST-LINK на OSC_IN, то есть режим HSE bypass
- STMicroelectronics. cmsis-device-f1 v4.3.5 и cmsis-device-f4 v2.6.11 (GitHub, Apache-2.0) — заголовки stm32f103x6/xb/xe/xg.h, stm32f401xc/xe.h, stm32f411xe.h и стартовые файлы startup_*.s: имена регистров, битов, прерываний (IRQn) и обработчиков; тест сверяет с ними каждое имя в коде
- STMicroelectronics. stm32f1xx-hal-driver v1.1.10 и stm32f4xx-hal-driver v1.8.5 (GitHub, BSD-3-Clause) — функции и константы LL и HAL; макросы __LL_USART_DIV_SAMPLING16/8 и UART_BRR_SAMPLING16/8 — второй источник для USART_BRR; порядок записи в UART_SetConfig и HAL_UART_Init; AFIO_REMAP_ENABLE и AFIO_REMAP_PARTIAL — запись SWJ_CFG; HAL_TIM_PWM_Start включает MOE у TIM1 и TIM8
- STMicroelectronics. STM32_open_pin_data (GitHub, BSD-3-Clause) — выводы корпусов, номера альтернативных функций F4 и ремапы F1 — те же данные, что в карточках микроконтроллеров атласа
- Arm. CMSIS_5 5.9.0: core_cm3.h, core_cm4.h (GitHub, Apache-2.0) — NVIC_SetPriority, NVIC_EnableIRQ, __disable_irq
Встроить калькулятор на свой сайт
Скопируйте код и вставьте его в HTML страницы, статьи или вики. Виджет бесплатный, без рекламы, счётчиков и cookie. Условие одно — ссылка на GAW под рамкой остаётся на месте. Подробнее о виджетах
<iframe src="https://gaw.ru/embed/stm32-init/" title="Генератор кода инициализации периферии STM32" width="100%" height="640" style="border:1px solid #e3e5e9;border-radius:8px" loading="lazy" allow="clipboard-write"></iframe>
<p style="margin:6px 0 0;font-size:14px">Калькулятор: <a href="https://gaw.ru/tools/stm32-init/">Генератор кода инициализации периферии STM32</a> — GAW.ru</p>Автоподстройка высоты рамки
Если сайт разрешает скрипты, добавьте этот код один раз в любом месте страницы: рамка будет менять высоту вместе с результатом расчёта.
<script>window.addEventListener("message",function(e){if(e.origin!=="https://gaw.ru"||!e.data||e.data.type!=="gaw:embed-height")return;var f=document.querySelectorAll('iframe[src^="https://gaw.ru/embed/"]');for(var i=0;i<f.length;i++)if(f[i].contentWindow===e.source)f[i].style.height=e.data.height+"px"})</script>Обновлено .
Нашли ошибку в расчёте?