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

Программирование встраиваемых систем

Раздел о том, как писать прошивки: особенности языка C на 8- и 32-битных микроконтроллерах, работа с регистрами и битами, фиксированная точка, прерывания и общие данные, конечные автоматы, код запуска и скрипты компоновщика, кольцевые буферы и протоколы обмена, сторожевой таймер, защита от переполнения стека, логирование и модульные тесты. Статьи опираются на стандарт C11, документацию компиляторов, архитектуры ARMv7-M и справочные руководства производителей.

Прошивка микроконтроллера — программа без операционной системы, которая сама настраивает тактирование и периферию, работает с регистрами по фиксированным адресам и обслуживает прерывания. Язык почти всегда C, но условия заметно отличаются от программирования для компьютера: 16-битный int на AVR, отсутствие блока плавающей точки у многих ядер, несколько килобайт ОЗУ, данные, которые меняются в обработчиках прерываний.

Статьи раздела

  1. Язык C для микроконтроллеров — размеры типов на AVR и ARM и типы stdint.h, volatile и атомарность, доступ к регистрам в avr-libc и CMSIS, константы во Flash, плавающая точка.
  2. Битовые операции — маски, установка, сброс и проверка битов, поля регистров, ловушки продвижения типов и сдвигов, атомарность на AVR и STM32.
  3. Арифметика с фиксированной точкой — формат Q, сложение и умножение с округлением и насыщением, деление, типы q15 CMSIS-DSP и _Fract в avr-gcc.
  4. Файлы прошивки: HEX, BIN, ELF и UF2 — секции ELF, VMA и LMA, записи Intel HEX и S-record, BIN и UF2, objcopy и вывод size, что принимают программаторы.
  5. Скрипты компоновщика GNU ld — MEMORY и SECTIONS, VMA и LMA, KEEP и PROVIDE, шаблон ST для STM32F103 и стандартный скрипт avr-gcc, map-файл, ошибки переполнения, расчёт свободного ОЗУ под стек.
  6. Прерывания и общие данные — вход в обработчик на AVR и Cortex-M, volatile и барьеры, ATOMIC_BLOCK, PRIMASK и BASEPRI, LDREX/STREX, критические секции, кольцевой буфер.
  7. Конечные автоматы — состояния, события и переходы, автоматы Мура и Мили, switch-case, таблица переходов и функции-состояния, таймауты без delay, очередь событий из прерываний, тест таблицы на компьютере.
  8. Код запуска — что делает ядро Cortex-M при сбросе, таблица векторов, Reset_Handler и SystemInit, копирование .data и обнуление .bss, VTOR и переход из загрузчика, включение FPU, секции .init0–.init9 avr-libc.
  9. Кольцевой буфер для UART — буфер на один писатель и один читатель с маской, приём и передача по прерываниям на ATmega328P и STM32F103, флаги DOR и ORE, расчёт размера, сборка строк, приём через DMA, тест.
  10. Сторожевой таймер — WDT ATmega328P, IWDG и WWDG STM32F103, расчёт таймаута с разбросом LSI, окно, контроль задач, причина сброса, отладчик и загрузчик.
  11. Переполнение стека и ошибки памяти — оценка стека по -fstack-usage, раскраска ОЗУ, защитная область MPU, разбор HardFault, куча и malloc.
  12. Логирование и трассировка — printf через UART в avr-libc и newlib, ITM и SWO, SEGGER RTT, уровни журнала, метки времени по счётчику тактов DWT.
  13. Модульное тестирование прошивки — отделение логики от железа, Unity, подмена регистров и времени, санитайзеры, тесты на плате.
  14. Реализация протокола обмена — граница кадра по паузе, длине или разделителю, 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».