Stm32f405: прошить 400кб за 10 секунд или быстрый uart-загрузчик заточенный под usb-uart, размером менее 4 килобайт

Code-Snippet for STM32

When you generate the code in STM32, the main.c file will have the following structure. You will need to add code in whichever section as per requirements.

/*License Declaration*/// Header File#include "main.h"// User Defined Header// Global Variable Declaration (Section 1)// Peripheral Initialization -> Handled by CubeMXint main(){  // Program Initialization (Section 2)  while(1){    // Looping Code (Section 3)  }  // Handle End of Run (Section 4)}

This the general template you will see when the code is generated. The variables declared in Section 1, will act as global variables. Now, we can sub-divide the project into the following tasks:

  • Create Structure (I will make one for collection of accelerometer data since STM32F4 has one builtin. You can program that and use the actual data but for this tutorial I will generate the data).
  • Make a Random Data Generator Function which returns a number within a given range. (Similar to the data a sensor might return)
  • Create a function to handle UART Transmission

Define Structure

(Section 1)/* * @brief Structure to hold and receive accelerometer data * @param x,y,z axes data * @size float -> 4B => x,y,z = 12B per instance of struct */struct XL_Data{  float x,y,z}tx_data;

Random-Data-Generator function

(Section 1)/** * @brief Function to Generate Random Data * @param float min, float max */float genXLvals(float min, float max){  return ((rand() % ((max-min+1)) + min);}

This function will return a value which lies in between the min and max values.

UART and HAL Libraries in STM32

The UART operation is a very complex procedure, no matter which micro-controller you are using. Fortunately, STM32 has libraries called LL and HAL. HAL stands for High Abstraction Layer and as the name implies, these libraries handle the entire bit-wise operations and the user only has to pass the right data to the functions.

When we select USART in CubeMX, it will add the corresponding HAL library to our projects and we can directly call those function from our code.

(Section 1)/* * @brief Function to convert and send data over UART * @param XL_Data, UART Handle Typedef */void sendData(struct XL_Data * data, UART_HandleTypeDef * huart){// UART can only send unsigned int  // Thus we need to convert our struct data  char buffer; // Create a char buffer of right size// Copy the data to buffer  memcpy(buffer, &data, sizeof(data)); // Copy and convert the data  // Ideally buffer will be 12B long, 4B for each axes data  // Now we can finally send this data  HAL_UART_Transmit(huart, (uint8_t *)buffer, sizeof(buffer), 50);// The last param is timeout duration in ms}

The Main Code

Now that we have all our basic functions covered, we need to setup the while loop to send the data continuously.

(Section 3)// Indicate Start of Sequence with "S"HAL_UART_Transmit(&huart, (uint8_t*)"S", sizeof("S"), 50);// Populate the Accelerometer Structuretx_data.x = genXLvals(0, 1024);tx_data.y = genXLvals(0, 1024);tx_data.z = genXLvals(0, 1024);// Send the Data over UARTsendData(&tx_data, &huart2); // huart2 is auto-generated for USART2// Indicate End of Sequence with "Z"HAL_UART_Transmit(&huart, (uint8_t*)"Z", sizeof("Z"), 50);HAL_Delay(100); // Delay for 100ms

Первая программа


Выполняем пункт меню Project -> New

Указываем имя проекта:

Выбираем Чип:

В репозитории выбираем какие именно модули мы будем использовать:

Открываем main.c і набираем следующий код программы:

Компилируем (Project->Build)

При первой компиляции IDE может запросить указать местонахождение компилятора.

Надо корректно указать место, куда был установлен GCC.

После удачной компиляции заливаем программу в микроконтроллер. Эта программа будет мигать светодиодом на плате. Как залить программу в микроконтроллер мы рассматривали в предыдущей статье.

Если Вы будете заливать прошивку через UART с помощью UART-USB переходника, файл для заливки найдете в директории:

Если у Вас есть установленный ST-Link программатор, программу в микроконтроллер можно залить прямо с IDE (Flash -> Program Download).

Если при этом возникла ошибка «Error: Flash driver function execute error» Рекомендуется:

  1. Запустить STM32 ST-LINK Utility и выполнить Frimware update.
  2. Скопировать файл STLinkUSBDriver.dll из папки
    C:\Program Files\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility
    в папку
    после чего перезапустить CooCox IDE


A separate directory is included that contains a short test program for the UART: it opens a serial port, reads the current parameters, writes a string and receives it 10 times in a loop, then closes the port. The open/write/read/close cycle is repeated 10 times before the program exits.

Obviously, in order to function, you must short the RxD and TxD signals of your UART.

For the VCP there is too a simple test program: this one opens the VCP and echoes back all the characters it receives. You can try it with a terminal program by typing characters that should be echoed back. More elaborate testing can be done by means of a script or a small program written in your preferred language for your computer, that sends blocks of data and checks them when (and if) it receives them back.

Examples for UART + DMA RX

Polling for changes

  • DMA hardware takes care to transfer received data to memory
  • Application must constantly poll for new changes in DMA registers and read received data quick enough to make sure DMA will not overwrite data in buffer
  • Processing of received data is in thread mode (not in interrupt)
  • P: Easy to implement
  • P: No interrupts, no consideration of priority and race conditions
  • P: Fits for devices without USART IDLE line detection
  • C: Application takes care of data periodically
  • C: Not possible to put application to low-power mode (sleep mode)

Polling for changes with operating system

  • Same as polling for changes but with dedicated thread in operating system to process data
  • P: Easy to implement to RTOS systems, uses single thread without additional RTOS features (no mutexes, semaphores, memory queues)
  • P: No interrupts, no consideration of priority and race conditions
  • P: Data processing always on-time

    Unless system has higher priority threads

    with maximum delay given by thread delay, thus with known maximum latency between received character and processed time

  • P: Fits for devices without UART IDLE line detection
  • C: Application takes care of data periodically
  • C: Uses memory resources dedicated for separate thread for data processing
  • C: Not possible to put application to low-power mode (sleep mode)

UART IDLE line detection + DMA HT&TC interrupts

  • Application gets notification by IDLE line detection or DMA TC/HT events
  • Application has to process data only when it receives any of the interrupts
  • P: Application does not need to poll for new changes
  • P: Application receives interrupts on events
  • P: Application may enter low-power modes to increase battery life (if operated on battery)
  • C: Data are read (processed) in the interrupt. We strive to execute interrupt routine as fast as possible
  • C: Long interrupt execution may break other compatibility in the application

Processing of incoming data is from 2 interrupt vectors, hence it is important that they do not preempt each-other. Set both to the same preemption priority!

USART Idle line detection + DMA HT&TC interrupts with RTOS

  • Application gets notification by IDLE line detection or DMA TC/HT events
  • Application uses separate thread to process the data only when notified in one of interrupts
  • P: Processing is not in the interrupt but in separate thread
  • P: Interrupt only informs processing thread to process (or to wakeup)
  • P: Operating system may put processing thread to blocked state while waiting for event
  • C: Memory usage for separate thread + message queue (or semaphore)

Что у меня получилось

Я решил по-максимуму задействовать возможности периферии микроконтроллера, но вместе с тем не впадать в пучину предварительных оптимизаций. Читаемость и поддерживаемость кода для меня гораздо важнее, чем незначительный прирост производительности. Тем более, что с производительностью и так все вышло очень хорошо.

Что реализовано:

  • три независимых последовательных порта;
  • поддержка аппаратного контроля потока (RTS/CTS) на двух из трех портов;
  • поддержка управляющих сигналов DSR/DTR/DCD/RI;
  • поддержка 7 и 8-битной длины слова;
  • поддержка контроля четности;
  • 1, 1.5 и 2 стоповых бита;
  • совместимость со стандартными драйверами Linux, macOS и Windows;
  • подписанный INF файл для Windows XP, 7 и 8;
  • поддержка произвольных скоростей (более 2 Мбит/с);
  • сигнал TXA для управления трансиверами RS-485 (DE, /RE);
  • DMA на передачу и прием данных USART;
  • встроенный командный интерпретатор для конфигурации;
  • нет зависимостей от сторонних библиотек кроме CMSIS;
  • проект с открытым исходным кодом, лицензия MIT;

Командный интерпретатор позволяет настраивать следующие параметры:

  • тип выхода: двухтактный, открытый сток;
  • тип подтяжки входных линий: вверх, вниз, плавающая;
  • инверсия для управляющих сигналов: активный высокий/низкий;

Командный интерпретатор активируется на первом CDC порту при подключении пина PB5 к земле, поддерживает часть управляющих последовательностей ANSI (стрелочки, backspace), и принимает вполне дружелюбные на вид команды:

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

Распиновка вышла следующей:

Signal Direction UART1 UART2 UART3

Пины, выделенные жирным шрифтом, являются толерантными к 5 В.

Сигнал TXA (TX Active) служит для управления микросхемами трансиверов RS-485 (DE, /RE). TXA активен во время передачи данных и переключается в неактивное состояние не более чем за 0.6 мкс после завершения передачи. Это соответствует спецификациям RS-485 на скоростях до 920 кБод c почти двукратным запасом по времени переключения.

К сожалению, реализовать RTS/CTS на UART1 не вышло из-за того, что соответсвующие пины заняты сигналами USB. Можно было вывести RTS на какой-нибудь другой пин, поскольку RTS управляется программно, в зависимости от степени заполнения кольцевых буферов на прием, но порт c RTS и без CTS мне показался странной штукой и я решил, что так делать не надо.

Проект написан на языке C, и подразумевает использование arm-none-eabi-gcc для сборки. Я использовал специфичный для GCC синтаксис атрибутов и расширения языка С. Совместимость проекта с проприетарными компиляторами меня не интересует, но если кто-то считает это важным, то я готов принять соответствующий пул-реквест.

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

Прошивка STM32 с помощью USB-Uart переходника под Windows


Подключаем RX и TX выходы к соответствующим выводам USART1 микроконтроллера. RX переходника подключаем к TX микроконтроллера (A9). TX переходника подключаем к RX микроконтроллера (A10). Поскольку USART-USB имеет выходы питания 3.3В подадим питания на плату от него.

Чтобы перевести микроконтроллер в режим программирования, надо установить выводы BOOT0 и BOOT1 в нужное состояние и перезагрузить его кнопкой Reset или выключить и включить питание микроконтроллера. Для этого у нас есть перемычки. Различные комбинации загоняют микроконтроллер в различные режимы. Нас интересует только один режим. Для этого у микроконтроллера на выводе BOOT0 должно быть логическая единица, а на выводе BOOT1 — логический ноль. На плате это следующее положение перемычек:

После нажатия кнопки Reset или отключения и подключения питания, микроконтроллер должен перейти в режим программирования.

Обработка ошибок на уровне пакетов и таймаутов

  • Если код команды не соответствует проверочному инверсному коду, то начало пакета не засчитывается, и поиск новой команды начинается со следующих байт.
  • Если принят пакет с размером дополнительной информации больше чем внутренний буфер, то пакет игнорируется, и поиск новой команды начинается со следующих после размера байт.
  • Если принятая в теле пакета CRC32 не равна фактически расчётной, то содержимое пакета игнорируется и поиск новой команды начинается с следующих после CRC32 байт.
  • Если приходят байты, но сигнатура начала пакета не задетектирована. То эти байты считать отладочными текстовыми сообщениями и накапливать до кода 13 (перевод строки), а после этого кода выводить в отладочную консоль.
  • Если с момента приёма последнего пакета прошло более 500мс, то загрузчик сбрасывается в изначальное состояние. Пакет, который не успел приняться до конца, игнорируется и так-же сбрасывается. О таймауте Устройство сообщает пакетом с специальным кодом команды «таймаут».
  • При запуске загрузчика генерируется другой пакет со специальным кодом «перезагрузка».


The method is implemented and demonstrated on a 32L476G Discovery kit equipped with a STM32L476VG MCU . The on-board ST-Link provides an USB VCP (Virtual COM Port) to UART interface for the microcontroller. The UART lines are connected to PD5 and PD6 pins of the MCU. The DMA controller is initialized to receive data from this UART line. In this demonstration, the USB peripheral of the MCU is initialized in CDC VCP mode, therefore the received data is forwarded back to the PC via USB. The demonstration software uses the official HAL library of ST and is compiled with IAR EWARM.

Figure 1: System overview

Buffers selection

Both receive and transmit sections need decent buffers to properly operate. The buffer’s size depends on your application. You can either provide two static buffers, or null pointers. In the later case the driver will dynamically allocate the buffers.

In general, for slow typed input and output, buffers of several tens of bytes are sufficient; it is important to test the result of the and functions to be sure all characters have been sent, or if you received the expected frame in its entirety.

However, if you implement a serial protocol, then the buffers should be sized according to the typical frame length of the protocol. Small buffers will still do, but the efficiency will decrease and at high speeds the driver might even lose characters.

Источники питания

STM32W108 содержит три системы источников питания. Всегда включенный высоковольтный источник питания обеспечивает работу GPIO и функционирование критических блоков микросхемы. Остальные блоки микросхемы питаются от низковольтных стабилизаторов. Низковольтные источники питания можно отключить при переходе в спящий режим, что дополнительно уменьшает энергопотребление. Внутренние стабилизаторы обеспечивают получение напряжений питания 1,25 В и 1,8 В из нерегулируемого напряжения питания микросхемы. Выход стабилизатора напряжения 1,8 В имеет внешний фильтр и может использоваться внешними аналоговыми блоками, RAM и flash-памятью. Выход стабилизатора напряжения 1,25 В имеет внешний фильтр и используется для питания ядра микропроцессора.

Режимы пониженного энергопотребления

STM32W108 имеет сверхнизкое энергопотребление в режиме глубокого сна с возможностью выбора способа тактирования. Таймер выхода из состояния бездействия можно тактировать или от внешнего кварцевого резонатора на частоту 32,768 кГц, или от сигнала частотой 1 кГц, полученного делением частоты 10 кГц от внутреннего RC-генератора. Для режима с наименьшим энергопотреблением все тактовые генераторы можно выключить, т.к. микросхема будет пробуждаться только внешними событиями с выводов GPIO. STM32W108 обладает быстрым временем пробуждения (типичное значение — 100 мкс) из состояния глубокого сна до момента выполнения первой инструкции ARM Cortex-M3.

Средства разработки и отладки

Для создания приложений на базе STM32W108 можно использовать широкий набор сред разработки и отладки, а также операционных систем реального времени (OS и RTOS), предназначенных для работы с ARM-микроконтроллерами, и предлагаемых многими ведущими производителями программного и аппаратного обеспечения. Для создания прикладных программ для STM32W108 можно использовать интегрированную среду разработки Keil RealView Microcontroller Development Kit (MDK) совместно с семейством USB-JTAG адаптеров Keil ULINK или IAR Embedded Workbench for ARM совместно с адаптером IAR J-Trace for Cortex-M3.

Отличительной особенностью STM32W108 является наличие аппаратной поддержки модуля трассировки пакетов, который обеспечивает многоуровневую отладку на уровне пакетов. Этот блок является необходимым компонентом для интегрированной среды разработки InSight Desktop компании Ember и при использовании специального адаптера InSight компании Ember обеспечивает возможность расширенной сетевой отладки.

Перечень проектов

Example_First_Programm — GPIO. Первая программа. Мигание светодиодом

Example_GPIO — GPIO. Пример работы с входами и выходами

Example_StepMotor — GPIO. Пример работы с шаговым двигателем 28BYJ-48

Example_Nokia5110 — GPIO. Remap. Пример работы с выходами

Example_WG12864A — GPIO. Пример работы с LCD дисплеем WG12864A (KS0108/KS0107)

Example_ADC — ADC. Простой пример работы с АЦП

Example_ADC_DMA — ADC. Работа с АЦП с использованием DMA

Example_ADC_Injected — ADC. Работа с АЦП с настройкой Injected каналов

Example_ADC_Temperature — ADC. Использование встроенного термометра

Example_ADC_Watchdog — ADC. Аналоговый Watchdog

Example_Sonar — EXTI. Пример работы с сонаром HC-SR04

Example_USART1 — USART. Пример простого терминала

Example_USART_DMA — USART. Отправка данных через последовательный порт с помощью DMA

Example_DFPlayerMini — USART. Пример работы с MP3 плеером DFPlayer Mini. Функция произнесения числа

Example_SysTick — Таймер. Системный таймер SysTick. Задержка на SysTick

Example_TIM_CLK — Таймер. Генерирование прерывания через равные промежутки времени

Example_TIM_Time — Таймер. Измерение времени между двумя событиями

Example_PPM — Таймер. Захват сигнала

Example_Encoder — Таймер. Работа с энкодером

Example_Encoder_IT — Таймер. Работа с энкодером

Example_PWM_LED — Таймер. PWM. Управление яркостью светодиода

Example_PWM_RGB — Таймер. PWM. Управление цветом RGB светодиода

Example_PWM_Servo — Таймер. PWM. Управление сервоприводом

Example_PWM_Sound — Таймер. PWM. Генерирование звука

Example_RTC — RTC. Пример работы с часами реального времени

Example_BKP — BKP. Пример работы с регистрами Backup registers

Example_FLASH — FLASH. Пример сохранения настроек во FLASH память

Example_Watchdog — Watchdogs. Пример использование IWDG и WWDG

Example_I2C_Master — I2C. Работа с шиной I2C на примере датчика атмосферного давления BMP280

Example_I2C_Slave — I2C. Работа с шиной I2C в качестве Slave устройства

Example_BMP280 — I2C. Пример работы с датчиком атмосферного давления BMP280

Example_MS5611 — I2C. Пример работы с датчиком атмосферного давление MS5611

Example_USB_Virtual_Com_Port — USB. Пример работы с USB. Виртуальный последовательный порт

Example_USB_Keyboard — USB. Пример работы с USB. Эмуляция клавиатуры и мышки

Example_USB_Mass_Storage — USB. Пример работы с USB. STM32F103 в качестве Mass Storage Device

Example_PWR_Sleep — PWR. Использование энергосберегающего режима SLEEP

Example_PWR_Stop — PWR. Использование энергосберегающего режима STOP

Example_PWR_Standby — PWR. Энергосберегающий режим Standby. Пробуждение от Wake Up Pin

Example_PWR_Standby_RTC — PWR. Энергосберегающий режим Standby. Пробуждение от RTC

Example_Bootloader — Bootloader. Пример собственного загрузчика

Example_BLDC — Управление бесколлекторным двигателем с датчиками Холла (Sensored Brushless)

Example_PMSM — Управление PMSM с датчиками Холла с помощью STM32

Смотри также:

  • 1. STM32. Программирование STM32F103. Тестовая плата. Прошивка через последовательный порт и через ST-Link программатор
  • 2. STM32. Программирование. IDE для STM32
  • 3. STM32. Программирование STM32F103. GPIO
  • 4. STM32. Программирование STM32F103. Тактирование
  • 5. STM32. Программирование STM32F103. USART
  • 6. STM32. Программирование STM32F103. NVIC
  • 7. STM32. Программирование STM32F103. ADC
  • 8. STM32. Программирование STM32F103. DMA
  • 9. STM32. Программирование STM32F103. TIMER
  • 10. STM32. Программирование STM32F103. TIMER. Захват сигнала
  • 11. STM32. Программирование STM32F103. TIMER. Encoder
  • 12. STM32. Программирование STM32F103. TIMER. PWM
  • 13. STM32. Программирование STM32F103. EXTI
  • 14. STM32. Программирование STM32F103. RTC
  • 15. STM32. Программирование STM32F103. BKP
  • 16. STM32. Программирование STM32F103. Flash
  • 17. STM32. Программирование STM32F103. Watchdog
  • 18. STM32. Программирование STM32F103. Remap
  • 19. STM32. Программирование STM32F103. I2C Master
  • 20. STM32. Программирование STM32F103. I2C Slave
  • 21. STM32. Программирование STM32F103. USB
  • 22. STM32. Программирование STM32F103. PWR
  • 23. STM32. Программирование STM32F103. Option bytes
  • 24. STM32. Программирование STM32F103. Bootloader
  • STM32. Скачать примеры
  • System Workbench for STM32 Установка на Ubuntu
  • Keil uVision5 – IDE для STM32
  • IAR Workbench – IDE для STM32
  • Управление бесколлекторным двигателем постоянного тока (BLDC) с помощью STM32
  • Управление PMSM с помощью STM32

Регистры USART

Status register (USART_SR) — регистр статуса

TXE: регистр передатчика пуст. Этот бит устанавливается аппаратно, когда содержимое регистра передатчика TDR (TDR не доступен напрямую из программы, но туда попадают данные при записи в USART_DR) было передано в сдвиговой регистр. Если в USART_CR1 был установлен бит разрешения прерывания TXEIE, то в этот момент генерируется запрос прерывания USART. TXE сбрасывается при записи значения в регистр данных USART_DR.

TC: передача завершена. Этот бит устанавливается аппаратно, если UART завершил передачу данных, при этом бит TXE установлен в единицу. Этот бит может быть полезен для реализации интерфейса RS485 для переключения направления драйвера RS485. Если в регистре USART_CR1 установлен бит TCIE, то генерируется прерывание USART при установке бита TC. Бит TC сбрасывается следующей программной последовательностью: чтение регистра USART_SR с последующей записью в регистр USART_DR. Кроме того, бит TC можно сбросить записью в него значения 0, но это рекомендуется производить только в режиме совместной работы с DMA.

RXNE: регистр приемника не пуст. Этот бит устанавливается в единицу, когда содержимое сдвигового регистра приемника передается в регистр данных USART. Если в регистре USART_CR1 установлен бит RXNEIE, то генерируется запрос прерывания USART. Бит RXNE сбрасывается при чтении регистр данных USART_DR. Кроме того, RXNE можно сбросить записью в него значение 0, но это рекомендуется производить только в режиме совместной работы с DMA.

ORE: ошибка переполнения. Устанавливается в 1, если данные в сдвиговом регистре приемника готовы к передаче в регистр данных, но при этом установлен бит RXNE. Иными словами, мы уже получили очередной байт по USART, но еще не прочитали предыдущий. Если в регистре USART_CR1 установлен флаг RXNEIE, то генерируется запрос прерывания USART. Бит ORE сбрасывается следующей программной последовательностью: чтение регистра USART_SR с последующим чтением регистра USART_DR.

Data register (USART_DR) — регистр данных

DR: данные. Этот регистр содержит 2 теневых регистра: TDR и RDR. При чтении из DR будет прочитано значение регистра данных приемника RDR, при записи в DR значение будет записано в регистр данных передатчика TDR. Если используется контроль четности (бит PCE в регистре USART_CR1 установлен в 1), то при записи в DR значение старшего бита будет игнорироваться, так как при передаче он будет заменен битом четности. При приеме с включенным контролем четности старший бит будет содержать бит четности.

Baud rate register (USART_BRR) — регистр скорости передачи данных USART

Регистр BRR содержит коэффициент деления, который задает скорость передачи данных по USART.

BRR = (uint16_t)(BUS_FREQ / BAUD)

где BUS_FREQ — частота шины, на которой висит данный USART

BAUD — желаемая скорость передачи данных.

Control register 1 (USART_CR1) — регистр конфигурации 1

UE: включить USART.

  • 0: предделители USART и его выходы отключены
  • 1: USART включен

M: длина слова данных. Этот бит определяет длину передаваемых данных. Устанавливается и очищается программно.

  • 0: 1 старт-бит, 8 бит данных, n стоп-бит
  • 1: 1 старт-бит, 9 бит данных, n стоп-бит

PCE: разрешить контроль четности. Устанавливается и очищается программно

PS: выбор типа контроля четности. Этот бит выбирает вариант контроля четности, если установлен бит PCE. Устанавливается и очищается программно.

  • 0: Even
  • 1: Odd

TXEIE: разрешить прерывание при опустошении буфера передатчика. Если установлен в 1, то генерируется запрос прерывания USART при установке бита TXE регистра USART_SR.

TCIE: разрешить прерывания окончания передачи. Если 1, то генерируется запрос прерывания USART при установке флага TC в регистре USART_SR.

RXNEIE: разрешить прерывание при появлении данных в регистре приемника. Если 1, то генерируется запрос прерывания USART при установке флага RXNE или ORE в регистре USART_SR.

TE: включить передатчик USART

RE: включить приемник USART

Control register 2 (USART_CR2) — регистр конфигурации 2

STOP: количество STOP-битов

  • 00: 1 стоп-бит
  • 01: 0.5 стоп-бита
  • 10: 2 стоп-бита
  • 11: 1.5 стоп-бита

0.5 и 1.5 стоп-бита не доступны для UART4 и UART5 (UART4  и UART5  отсутствуют в микроконтроллере STM32F103C8)

Настройка DMA


DMA_PeripheralBaseAddr – адрес периферийного устройства
DMA_MemoryBaseAddr – адрес памяти
DMA_DIR – напрвыление передачи. Данные могут передаваться с периферии в память и наоборот, из памяти в периферию (DMA_DIR_PeripheralDST | DMA_DIR_PeripheralSRC)
DMA_BufferSize – размер  буфера даних
DMA_PeripheralInc — указывает надо ли инкрементировать адреса данных в периферии (DMA_PeripheralInc_Enable | DMA_PeripheralInc_Disable)
DMA_MemoryInc – указывает надо ли инкрементировать адреса данных в памяти (DMA_MemoryInc_Enable | DMA_MemoryInc_Disable)

Если вернуться к примеру работы АЦП через DMA, то мы увидим, что в настройках DMA
DMA_MemoryInc = Enable
DMA_PeripheralInc = Disable
Это потому, что мы раскладываем данные АЦП в массив и нам нужно включить инкрементация адресов в памяти. Чтобы данные из разных каналов записывались на свои места. А выходной регистр в АЦП один, и нам следует выключить инкрементация на периферии.

DMA_PeripheralDataSize – размер единицы данных для переферии
DMA_MemoryDataSize – размер единицы данных для памяти

Эти поля могут принимать следующие значения:


DMA_Mode – режим работи канала DMA (DMA_Mode_Circular | DMA_Mode_Normal)
DMA_Priority – приоритет канала DMA (DMA_Priority_VeryHigh | DMA_Priority_High | DMA_Priority_Medium | DMA_Priority_Low)
DMA_M2M – передача память > память (DMA_M2M_Enable | DMA_M2M_Disable)

Setting Up the Project

In this tutorial, we will be creating a structure of randomly generated values and transmit that via the UART port of the STM32. So, first off, you need to set up your project. I have illustrated the steps needed to do this in another tutorial (

The only thing to keep in mind, is that we need to enable the UART port in CubeMX pin configuration. In my project I select the UART2 port. (This step is essential and mentioned in the tutorial above). UART option is available under the Connectivity Section. Set the USART2 Mode to Asynchronous Mode. You can also set the baud rate. In this case, I leave it at 9600 bits/s.

Порядок работы со стороны хоста

  1. Получаем информацию с устройства: размер флеша, ChipID, размер буфера приёма, адрес старта, версия загрузчика и чипа.
  2. Даём команду стирания либо всей прошивки, либо части указав размер стираемой области.
  3. По завершению стирания начинаем непрерывно отправлять команды записи блоками друг за другом, проверяя что текущая записанная позиция в устройстве увеличивается.
  4. Если позиция перестала увеличиваться (приняли два ответа на команду «запись» с одинаковым адресом), то скорректировать адрес на Хосте, сбросить буферы отправки и начать передавать с нового скорректированного адреса.
  5. По завершению записи подать команду «Старт» передав CRC32 всей прошивки, в ответ Устройство сообщит фактическое CRC32.
  6. Если фактическое CRC32 равно расчётному, то загрузка успешно закончена и прошивка запущена.


Implementing DMA for peripherals (e.g. UART) can significantly boost performance while reducing workload on the MCU (microcontroller) core , therefore configuring the DMA controller in circular mode can be straightforward for peripherals. However, in time-critical systems or hard real-time systems it is crucial to perform the required actions within specified deadlines. A DMA controller is only able to issue interrupts when its buffer is either full or halfway full, however considering UART communication, in most cases the received amount of data is not known in advance and the end of transfer cannot be detected. Consequently, when a transmission from a peripheral ends with a partially filled DMA buffer, and no further data is received over a certain period, a DMA timeout has to be implemented in order to process the remaining data. A DMA timeout means that a detectable event (e.g. interrupt) is generated when the following conditions are met: 1) DMA buffer is not full, and 2) no further data is received after a certain period.

ST suggests two methods for implementing DMA timeout in Section 2 of AN3019 . The first method utilizes a timer in input capture mode. While this method is effective, it requires an available hardware timer and additional wiring. The second method requires no hardware changes and additional peripherals, instead it uses the system timer and utilizes the UART receive interrupt. The drawback of this method is that the UART interrupt service routine is called often during transmission, especially when the configured timeout period is short. This adds significant overhead to the system and affects performance and efficiency negatively.

In this demonstration, a more efficient idea is presented to implement DMA timeout. The UART peripheral can be configured to generate an interrupt when the UART module detects an idle line (end of transmission). After generating an idle line interrupt, it is not generated again until there is new data received. (For more information about how idle line detection and interrupt generation works, please refer to .) After detecting an idle line, a software timer is started with user-defined period. If no DMA transfer complete interrupt is generated within this period, a DMA timeout event is generated and new data in DMA buffer can be processed. This method provides an efficient way to implement DMA timeout and minimizing overhead by generating a single additional interrupt (UART idle line interrupt) after the end of transmission.

Прошивка STM32 с помощью ST-Link программатора под Windows

При использовании программатора ST-Link выводы BOOT0 и BOOT1 не используются и должны стоять в стандартном положении для нормальной работы контроллера.

Качаем с сайта Утилиту STM32 ST-LINK Utility. Устанавливаем ее.  С ней должен быть установлен и драйвер для ST-Link. Если нет, качаем и устанавливаем драйвера ST-Link: Подключаем ST-Link в USB- разъем компьютера, а соответствующие выводы программатора подключаем к выводам тестовой платы согласно маркировки.

Запускаем программу STM32 ST-LINK Utility

Выполняем пункт меню Target -> Connect

Выполняем пункт меню Target -> Erase Chip

Выполняем пункт меню File -> Open file…
Выбираем файл для загрузки в микроконтроллер.

Выполняем пункт меню Target -> Programm & Verify…

После завершения прошивки и проверки, загруженная программа автоматически запустится.

1.3 CAN интерфейс

Установленные на плате микросхемы SN65HVD230 отвечают за преобразование уровней встроенного в микроконтроллер приемопередатчика шины CAN. Структурная схема подключения CAN интерфейса отображена на рисунке ниже. Для подключения согласующего резистора R устанавливается перемычка S.

На рисунке ниже показано направление нумерации выводов разъема XT3 и XT4. Для подключения согласующих резисторов устанавливаются перемычки на штыри X15, X16.

Установкой перемычек на штыри X13 и X14 определяет режим работы микросхемы CAN – трансивера.

Если перемычка установлена так, как показано на рисунке:

используется высокоскоростной режим работы.

Если установлена:

микросхема работает в режиме хранения.


В общем и целом перед поставленной задачей товарищи студенты справились.

При включенном принудительном inline, весь код проекта занимает 1600 байт без оптимизации. Сделаны две команды: запись и чтение 12 параметров во Flash микроконтроллера. В проекте, можно настроить драйвер, чтобы он работал в синхронном режиме, можно в асинхронном. Можно подключать любое количество подписчиков, к любому UART. Собственно все задачи были выполнены и работа тянет на отлично 🙂

Да, затрачено на кодирование было 2 целых дня (думаю часов 20 в сумме). Полагаю, из-за того, что архитектура мною уже была разработана на практических занятиях, а реализация — это дело уже не таке сложное.

Код был проверен мною в PVS-Studio. Изначально были найдены 4 предупреждения.
Все предупреждения уже не помню, отчет не сохранил: но точно были V2516 и V519, ошибки не критичные, но точно так делать не надо было 🙂 Все исправлено, кроме V2516, он указывает на код, который используется для отладки, там поставил FIXME:.