Программирование встраиваемых систем
Раздел о том, как писать прошивки: особенности языка C на 8- и 32-битных микроконтроллерах, работа с регистрами и битами, фиксированная точка, прерывания и общие данные, конечные автоматы, код запуска и скрипты компоновщика, кольцевые буферы и протоколы обмена, сторожевой таймер, защита от переполнения стека, логирование и модульные тесты. Статьи опираются на стандарт C11, документацию компиляторов, архитектуры ARMv7-M и справочные руководства производителей.
- C для микроконтроллеровТипы, stdint, volatile, атомарность, регистры, константы во Flash
- Битовые операции в CМаски, сдвиги, установка и проверка битов, ловушки стандарта C
- Фиксированная точкаФормат Q, умножение со сдвигом, округление, насыщение, q15 и _Fract
- Файлы прошивки: HEX, BIN, ELFELF, Intel HEX, S-record, BIN и UF2: адреса, секции, objcopy, size
- Скрипт компоновщика GNU ldMEMORY, SECTIONS, VMA и LMA, KEEP, стек и куча, map-файл, переполнение
- Прерывания и общие данныеISR на AVR и Cortex-M, атомарность, критические секции, кольцевой буфер
- Конечные автоматы на Cswitch-case, таблица переходов, функции-состояния, таймауты, очередь событий
- Код запускаТаблица векторов, Reset_Handler, .data и .bss, VTOR, FPU, .initN avr-libc
- Кольцевой буфер UARTБуфер SPSC с маской, ISR приёма и передачи на AVR и STM32, ORE и DOR, размер
- Сторожевой таймерWDT AVR, IWDG и WWDG STM32, таймаут, окно, контроль задач, причина сброса
- Переполнение стека и памятьОценка стека, раскраска ОЗУ, защитная область MPU, HardFault, куча
- Логирование и трассировкаprintf через UART, ITM и SWO, SEGGER RTT, уровни журнала, метки времени
- Модульное тестирование прошивкиТесты на ПК, Unity, подмена регистров и времени, санитайзеры, тесты на плате
- Реализация протокола обменаКадры по паузе, длине и разделителю, COBS, CRC-16, таймауты, разбор потока
Прошивка микроконтроллера — программа без операционной системы, которая сама настраивает тактирование и периферию, работает с регистрами по фиксированным адресам и обслуживает прерывания. Язык почти всегда C, но условия заметно отличаются от программирования для компьютера: 16-битный int на AVR, отсутствие блока плавающей точки у многих ядер, несколько килобайт ОЗУ, данные, которые меняются в обработчиках прерываний.
Статьи раздела
- Язык C для микроконтроллеров — размеры типов на AVR и ARM и типы
stdint.h,volatileи атомарность, доступ к регистрам в avr-libc и CMSIS, константы во Flash, плавающая точка. - Битовые операции — маски, установка, сброс и проверка битов, поля регистров, ловушки продвижения типов и сдвигов, атомарность на AVR и STM32.
- Арифметика с фиксированной точкой — формат Q, сложение и умножение с округлением и насыщением, деление, типы q15 CMSIS-DSP и
_Fractв avr-gcc. - Файлы прошивки: HEX, BIN, ELF и UF2 — секции ELF, VMA и LMA, записи Intel HEX и S-record, BIN и UF2, objcopy и вывод size, что принимают программаторы.
- Скрипты компоновщика GNU ld — MEMORY и SECTIONS, VMA и LMA, KEEP и PROVIDE, шаблон ST для STM32F103 и стандартный скрипт avr-gcc, map-файл, ошибки переполнения, расчёт свободного ОЗУ под стек.
- Прерывания и общие данные — вход в обработчик на AVR и Cortex-M, volatile и барьеры, ATOMIC_BLOCK, PRIMASK и BASEPRI, LDREX/STREX, критические секции, кольцевой буфер.
- Конечные автоматы — состояния, события и переходы, автоматы Мура и Мили, switch-case, таблица переходов и функции-состояния, таймауты без delay, очередь событий из прерываний, тест таблицы на компьютере.
- Код запуска — что делает ядро Cortex-M при сбросе, таблица векторов, Reset_Handler и SystemInit, копирование .data и обнуление .bss, VTOR и переход из загрузчика, включение FPU, секции .init0–.init9 avr-libc.
- Кольцевой буфер для UART — буфер на один писатель и один читатель с маской, приём и передача по прерываниям на ATmega328P и STM32F103, флаги DOR и ORE, расчёт размера, сборка строк, приём через DMA, тест.
- Сторожевой таймер — WDT ATmega328P, IWDG и WWDG STM32F103, расчёт таймаута с разбросом LSI, окно, контроль задач, причина сброса, отладчик и загрузчик.
- Переполнение стека и ошибки памяти — оценка стека по -fstack-usage, раскраска ОЗУ, защитная область MPU, разбор HardFault, куча и malloc.
- Логирование и трассировка — printf через UART в avr-libc и newlib, ITM и SWO, SEGGER RTT, уровни журнала, метки времени по счётчику тактов DWT.
- Модульное тестирование прошивки — отделение логики от железа, Unity, подмена регистров и времени, санитайзеры, тесты на плате.
- Реализация протокола обмена — граница кадра по паузе, длине или разделителю, SLIP и COBS, выбор CRC-16, разборщик с повторной синхронизацией, таймауты и повторы.
Где ещё искать
Особенности конкретных ядер и периферии — в разделе «Микроконтроллеры»: системы команд AVR, 8051 и Thumb-2, таймеры, режимы сна, прошивка. Программы для сборки и загрузки прошивки — компиляторы, PlatformIO, avrdude, esptool — в разделе «Программы». Расчёты, которые нужны при написании прошивки, — предделители таймеров, скорости UART, CRC, таблицы функций — в разделе «Инструменты».
Готовятся к публикации
FreeRTOS · DMA: шаблоны использования · Обработка ошибок
Частые вопросы
С чего начать программирование микроконтроллеров на C?
С отличий от «обычного» C: размеров типов на конкретной платформе, квалификатора volatile, работы с регистрами через маски и сдвиги. Затем — с периферии одного семейства: портов, таймеров, прерываний. Примеры этого раздела написаны для AVR и STM32, а особенности самих микроконтроллеров собраны в разделе «Микроконтроллеры».
Какой язык выбрать для прошивки: C, C++ или что-то ещё?
C остаётся основным: на нём написаны заголовки производителей, CMSIS, avr-libc и большинство примеров. C++ используют там, где компилятор и библиотеки его поддерживают, — например, часть ядра Arduino для AVR, в том числе Tone.cpp, написана на C++. Знание C нужно в любом случае: без него трудно читать документацию и чужой код.
Нужен ли ассемблер, если пишешь на C?
Писать на нём приходится редко, а читать — полезно: по листингу видно, во что компилятор превратил код, сколько тактов занимает обработчик прерывания и атомарна ли операция. Системы команд разобраны на страницах «Система команд AVR», «Система команд 8051» и «Thumb-2».
Смотрите также
- Код запускаТаблица векторов, Reset_Handler, .data и .bss, VTOR, FPU, .initN avr-libc
- Кольцевой буфер UARTБуфер SPSC с маской, ISR приёма и передачи на AVR и STM32, ORE и DOR, размер
- Реализация протокола обменаКадры по паузе, длине и разделителю, COBS, CRC-16, таймауты, разбор потока
- Модульное тестирование прошивкиТесты на ПК, Unity, подмена регистров и времени, санитайзеры, тесты на плате
- Конечные автоматы на Cswitch-case, таблица переходов, функции-состояния, таймауты, очередь событий
- Прерывания и общие данныеISR на AVR и Cortex-M, атомарность, критические секции, кольцевой буфер
- Скрипт компоновщика GNU ldMEMORY, SECTIONS, VMA и LMA, KEEP, стек и куча, map-файл, переполнение
- Файлы прошивки: HEX, BIN, ELFELF, Intel HEX, S-record, BIN и UF2: адреса, секции, objcopy, size
- C для микроконтроллеровТипы, stdint, volatile, атомарность, регистры, константы во Flash
- Битовые операции в CМаски, сдвиги, установка и проверка битов, ловушки стандарта C
- Фиксированная точкаФормат Q, умножение со сдвигом, округление, насыщение, q15 и _Fract
- МикроконтроллерыAVR, ARM Cortex-M, ESP32, PIC, MSP430: архитектура и выбор
- ПрограммыСАПР плат, симуляторы схем, среды и утилиты прошивки МК
- Калькулятор CRCCRC-8, CRC-16, CRC-32, Modbus, блок CRC STM32, код на C