Перейти к содержанию

Генератор кода инициализации периферии STM32

Выберите микроконтроллер с корпусом, источник тактирования и нужные блоки — генератор подберёт PLL, посчитает USART_BRR, PSC и ARR таймера, проверит, что скорость и частота достижимы, а выводы не заняты дважды, и выдаст файл на C в стиле регистров CMSIS, LL или HAL. Имена регистров, битов, функций и обработчиков сверены с заголовками ST.

Исходные данные

Тактирование
Источник SYSCLK
МГц

4–16 МГц, обычно 8

МГц

до 72 МГц; делители PLL — как в калькуляторе тактирования

USART
Работа
бод
Таймер
Режим
Гц
%
Выводы GPIO
GPIOA
GPIOB
GPIOC
GPIOD

out — двухтактный выход, od — открытый сток, in — вход без подтяжки, pu и pd — вход с подтяжкой к питанию и к земле. Рамкой отмечены выводы, занятые USART и таймером.

Результат

SYSCLK
72 МГцPLL: HSE ÷ 1 × 9; PCLK1 36 МГц, PCLK2 72 МГц; таймеры APB1 72 МГц, APB2 72 МГц; ожидание флеш 2
USART1: USART_BRR
0x0271115200 бод, ошибка 0 %; fCK 72 МГц
TIM2: PSC, ARR, CCR
1, 35999, 180001 кГц, заполнение 50 % на PA0, 15,1 бит; TIMxCLK 72 МГц
Обработчики прерываний
USART1_IRQHandler

Выводы

  • PA9 — USART1_TX
  • PA10 — USART1_RX
  • PA0 — TIM2_CH1
  • PC13 — GPIO: выход

Карточка и цоколёвка STM32F103C8 / CB · Регистры STM32F1: RCC, GPIO, AFIO, USART, TIM

Код на C

Стиль
/* STM32F103C8 / CB (LQFP48): peripheral init, CMSIS registers.
 * Generated by https://gaw.ru/tools/stm32-init/ — names checked against the ST headers
 * (stm32f103xb.h of cmsis-device-f1, stm32f1xx-hal-driver), the code itself was not compiled.
 * Build with -DSTM32F103xB.
 * SYSCLK 72 MHz, HCLK 72 MHz, PCLK1 36 MHz, PCLK2 72 MHz, timers on APB1 72 MHz, on APB2 72 MHz.
 */

#include "stm32f1xx.h"

/* Receive ring buffer: the interrupt writes rx_head, the main loop writes rx_tail. */
#define RX_SIZE 64u                                  /* power of two, at most 128 */
#define COMPILER_BARRIER() __asm volatile ("" ::: "memory")
static uint8_t rx_data[RX_SIZE];
static volatile uint8_t rx_head;
static volatile uint8_t rx_tail;

/* STM32F103 (performance line): SYSCLK 72 MHz, HCLK 72 MHz, PCLK1 36 MHz, PCLK2 72 MHz (RM0008 Rev 21) */
static void clock_init(void)
{
    RCC->CR |= RCC_CR_HSEON;
    while (!(RCC->CR & RCC_CR_HSERDY)) {}
    /* 2 wait state(s) before raising the clock */
    FLASH->ACR = (FLASH->ACR & ~FLASH_ACR_LATENCY) | FLASH_ACR_PRFTBE | 2U;
    while ((FLASH->ACR & FLASH_ACR_LATENCY) != 2U) {}
    RCC->CFGR = 0x001D8400; /* prescalers and PLL, SYSCLK still HSI */
    RCC->CR |= RCC_CR_PLLON;
    while (!(RCC->CR & RCC_CR_PLLRDY)) {}
    RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | 2U;
    while ((RCC->CFGR & RCC_CFGR_SWS) != 0x00000008) {}
    SystemCoreClock = 72000000U;
}

static void gpio_init(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
    (void)RCC->APB2ENR;            /* read back: the clock runs before the first access */
    GPIOC->BSRR = GPIO_BSRR_BR13;  /* PC13: low before the mode change */
    GPIOC->CRH = (GPIOC->CRH & ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13)) | GPIO_CRH_MODE13_1;  /* PC13: GPIO output, push-pull, 2 MHz */
}

/* USART1: 8N1, 115200 baud (+0 %), TX PA9, RX PA10, fCK 72 MHz (PCLK2) */
static void usart1_init(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN;
    (void)RCC->APB2ENR;                /* read back: the clock runs before the first access */
    GPIOA->CRH = (GPIOA->CRH & ~(GPIO_CRH_MODE9 | GPIO_CRH_CNF9)) | GPIO_CRH_MODE9 | GPIO_CRH_CNF9_1;  /* PA9: USART1_TX, AF push-pull 50 MHz */
    GPIOA->BSRR = GPIO_BSRR_BS10;      /* ODR = 1: pull-up */
    GPIOA->CRH = (GPIOA->CRH & ~(GPIO_CRH_MODE10 | GPIO_CRH_CNF10)) | GPIO_CRH_CNF10_1;  /* PA10: USART1_RX, input with pull-up */
    USART1->CR1 = 0;                   /* UE = 0 while configuring (the order of HAL_UART_Init) */
    USART1->CR2 = 0;                   /* 1 stop bit */
    USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;  /* 8N1 */
    USART1->CR3 = 0;                   /* no flow control */
    USART1->BRR = 0x0271U;             /* USARTDIV 39.0625 = 72 MHz / (16 * 115200) -> 115200 baud */
    NVIC_SetPriority(USART1_IRQn, 5);  /* 4 priority bits: 0 is the highest, 15 the lowest */
    NVIC_EnableIRQ(USART1_IRQn);
    USART1->CR1 |= USART_CR1_UE;
}

/* TIM2: PWM 1 kHz, duty 50 % on PA0 (CH1); TIMxCLK 72 MHz (APB1) */
static void tim2_init(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
    (void)RCC->APB2ENR;           /* read back: the clock runs before the first access */
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
    (void)RCC->APB1ENR;           /* read back: the clock runs before the first access */
    GPIOA->CRL = (GPIOA->CRL & ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0)) | GPIO_CRL_MODE0_1 | GPIO_CRL_CNF0_1;  /* PA0: TIM2_CH1, AF push-pull 2 MHz */
    TIM2->PSC = 1U;               /* 72 MHz / 2 = 36 MHz */
    TIM2->ARR = 35999U;           /* PWM 1 kHz */
    TIM2->CCR1 = 18000U;          /* duty 50 % */
    TIM2->CCMR1 = (TIM2->CCMR1 & ~(TIM_CCMR1_OC1M | TIM_CCMR1_CC1S)) | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE;  /* PWM mode 1 (110), CCR preload */
    TIM2->CCER |= TIM_CCER_CC1E;  /* output on, active high */
    TIM2->CR1 = TIM_CR1_ARPE;     /* ARR preload, up-counting */
    TIM2->EGR = TIM_EGR_UG;       /* update event: load PSC, ARR and CCR now */
    TIM2->CR1 |= TIM_CR1_CEN;     /* start */
}

void uart_putc(char c)
{
    while (!(USART1->SR & USART_SR_TXE)) {}  /* wait for an empty transmit register */
    USART1->DR = (uint8_t)c;
}

void uart_puts(const char *s)
{
    while (*s) uart_putc(*s++);
}

static void rx_put(uint8_t byte)
{
    uint8_t head = rx_head;
    if ((uint8_t)(head - rx_tail) == RX_SIZE)
        return;                                      /* full: the byte is dropped */
    COMPILER_BARRIER();
    rx_data[head & (RX_SIZE - 1u)] = byte;
    COMPILER_BARRIER();                              /* store the byte before publishing it */
    rx_head = (uint8_t)(head + 1u);
}

/* Next received byte, or -1 when the buffer is empty; does not wait. */
int uart_getc(void)
{
    uint8_t tail = rx_tail;
    if (rx_head == tail)
        return -1;
    COMPILER_BARRIER();                              /* see the new head before reading the byte */
    uint8_t byte = rx_data[tail & (RX_SIZE - 1u)];
    COMPILER_BARRIER();                              /* read the byte before freeing the slot */
    rx_tail = (uint8_t)(tail + 1u);
    return byte;
}

void USART1_IRQHandler(void)
{
    uint32_t sr = USART1->SR;
    uint8_t byte = (uint8_t)USART1->DR;  /* reading SR then DR clears RXNE and ORE */
    if (sr & USART_SR_RXNE)
        rx_put(byte);
}

int main(void)
{
    clock_init();
    gpio_init();
    usart1_init();
    tim2_init();
    uart_puts("hello\r\n");
    for (;;) {
        int c = uart_getc();
        if (c >= 0)
            uart_putc((char)c);                      /* echo */
    }
}

Расчёт выполнен по формулам и данным из источников, приведённых на этой странице, и не заменяет проверку: параметры компонентов у разных производителей и даже партий различаются. Перед применением сверяйте результат с документацией на конкретные детали.

Генератор пишет код настройки периферии 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 МГц
96000x1D4C (0 %)0x0EA6 (0 %)0x222E (0 %)0x28B1 (−0,003 %)
115 2000x0271 (0 %)0x0139 (−0,16 %)0x02D9 (+0,023 %)0x0364 (+0,006 %)
921 6000x004E (+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ЗаданиеPSCARR
TIM2, STM32F10372 МГцШИМ 1 кГц или период 1 мс135 999
TIM2, STM32F10372 МГцпериод 1 с112463 999
TIM3, STM32F40184 МГцШИМ 50 Гц (сервопривод)2759 999
TIM2, STM32F40184 МГцпериод 1 с083 999 999
TIM1, STM32F411100 МГцШИМ 20 кГц04999

В режиме ШИМ канал работает в режиме 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 и шинточно не получить — предупреждение с ближайшей частотой; превышение пределов шин — ошибка
Скорость USARTBRR вне допустимого (меньше 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.

Источники

  1. 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
  2. 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) — допуск приёмника на расхождение частот
  3. 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) — допуск приёмника
  4. STMicroelectronics. UM1724 Rev 17. STM32 Nucleo-64 boards (MB1136) — 7.9.1 (с. 25): по умолчанию HSE платы — сигнал MCO 8 МГц от микроконтроллера ST-LINK на OSC_IN, то есть режим HSE bypass
  5. 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) и обработчиков; тест сверяет с ними каждое имя в коде
  6. 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
  7. STMicroelectronics. STM32_open_pin_data (GitHub, BSD-3-Clause) — выводы корпусов, номера альтернативных функций F4 и ремапы F1 — те же данные, что в карточках микроконтроллеров атласа
  8. 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>

Обновлено .

Нашли ошибку в расчёте?