Переход с Arduino на STM32

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

Переход с Arduino на STM32

Введение

Все разговоры о высоком входном пороге придуманы теми, кто не смог его преодолеть. Да, это сложно, но ведь любую задачу можно декомпозировать.

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


Ключевые отличия

В этом блоке будем рассматривать только классические, примитивные платы Arduino, построенные на микроконтроллерах AVR. Например ATMega328, 2560.

Философия

Arduino как платформа создавалась именно для упрощения работы с МК. Это симбиоз готовых отладочных плат, стандартизации плат расширений, а также программных инструментов. Таким образом, любой, не погружённый в тематику человек, мог создать готовое устройство “from scratch”.

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

Поэтому, в обществе начало формироваться негативное отношение к Arduino, транслируемое и на остальной embedded.
А трушные эмбеддеры начали пренебрежительно-оскорбительно называть Arduino-программистов “ардуинщиками”, сродни “питонистам”.

Причиной этому обернулась и та самая простота разработки. Программисту сделали лишний слой абстракции и отобрали возможность в него заглянуть. Из-за этого сильно упало качество кода, у людей перестал развиваться скилл оптимизации.

У кого-то опускаются руки, кто-то ищет ответы с помощью других плат семейства. Но, настоящий выход — переход на нормальную платформу — STM32.
Сам микроконтроллер и его окружение тоже создавались с упрощенным взаимодействием. Но, в данном случае, хоть иногда приходится включать голову, что способно привести к более высоким достижениям.

Архитектура

Общее начало двух этих семейств — система команд RISC.

В Arduino исторически использовалась архитектура AVR. (Alf and Vegard’s RISC)
Эта архитектура древняя, разработанная в конце 90-х.

STM32 построены на архитектуре ARM. (Advanced RISC Machine)
Ядра Cortex-M. Первые МК появились в 2007.

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

Главное различие же в том, что AVR — архитектура 8-битная, а ARM32-битная.

Что есть разрядность?
Вспомним информатику 9-го класса школы.
8-битное число имеет всего 28 = 256 вариаций.
А 32-битное число: 232 = 4’294’967’296.

Этим исчисляется количество элементарных ячеек (байт) памяти, которые может адресовать (увидеть) контроллер ОЗУ. Поэтому, например, в младших PIC16 размер RAM не более 256 байт.
Безусловно, в таких контроллерах ограничения обходятся мультиплексированием или расширением шины, но не более 16 бит, что есть всего лишь 64 КБайт.

В STM32 пространство памяти общее, с максимальным размером в 4 ГБайт. Поэтому можно подключить внешнюю SRAM и хранить, например, буферы дисплеев. Подробнее про память описано у других авторов.
Гипотетически архитектура ARM поддерживает ширину внутренней шины до 1024 бит.

Но, разрядность определяет не только адресное пространство, ширину командного слова.
Если очень упрощать, то 32-битному процессору требуется кратно меньше инструкций на обработку большого числа, чем 8-битному. Это позволяет достичь более высокой точности в вычислениях при равных временных затратах.

Тактирование

Процессор работает последовательно, каждый раз вызывая очередную инструкцию из памяти. Их выполнение занимает определённый промежуток времени, который измеряется в тактах. Пример для Cortex-M4.

Временной интервал одного такого промежутка задаёт система тактирования. Иными словами, тактовая частота процессора — количество тактов в секунду.

В ранних AVR эта система очень примитивная, поддерживает максимальную частоту 16…20 МГц.

В STM32 используется более сложная схема. В качестве базового источника используется внешний или внутренний осциллятор. Он может задавать частоту как напрямую, так и передать её на PLL (ФАПЧ), который обеспечивает разгон вплоть до двух сотен мегагерц.

Аппаратные блоки и периферия

И так высокую скорость работы можно ещё увеличить, для этого в Cortex используются вспомогательные аппаратные блоки.
Например, блок FPU (Floating Point Unit) для работы с дробными числами.
В некоторых сериях есть расширение инструкций DSP (Digital Signal Processing) для быстрой цифровой обработки (аналоговых) сигналов.
Везде есть контроллер DMA (Direct Memory Access) для обмена данных периферии и памяти без участия процессора.
В старших МК используют различные ускорители, кодеки, а также кэш-память L1.

Для проверки данных везде есть блок CRC. Для защиты данных бывает MPU (Memory Protection Unit), а также блоки криптозащиты, реализующие алгоритмы AES, MD5 и др.

Микроконтроллеры STM32 богаты периферией. Помимо стандартных SPI, I2C, UART, в некоторых МК присутствуют: USB, SDIO, Quad-SPI, I2S, SPDIF а также специфические: FSMC, CAN(-FD), HDMI-CEC, и так другие…

Устанавливаются: 12-битный АЦП, 12-битный ЦАП, встроенные аппаратные компараторы и операционные усилители.

Большое количество таймеров, как 16-битных, так и 32-битных. В некоторых сериях есть высокоточный таймер для применения, например, в высокочастотных DC-DC преобразователях.

В большинстве МК есть RTC (Real Time Clock), содержащий часы, календарь и будильник.

Отладка

Далеко не во всех AVR есть блок отладки. А там, где есть, он очень примитивный. А в Arduino IDE ещё и бесполезный: такой функционал там не предусмотрен.

В отличие от AVR, отладка есть во всех STM32. Он позволяет: отслеживать выполнение команд в реальном времени, добавлять точки останова, просматривать все переменные и регистры. Происходит это с помощью интерфейсов JTAG или SWD.

Корпуса

Выбор корпусов очень широк.

  • Классические, с ножками: LQFP, TSSOP
  • Без ножек: QFN, LGA
  • На шарах: BGA, WLCSP

Количество лап варьируется от 8 до 240.

Как и в AVR, используется топология “Порт-пин”.
Например: Port A Pin 8PA8.
На пин можно назначить как GPIO (с подтяжками вверх и вниз), так и альтернативную функцию (периферию). Некоторые ноги мультиплексируются. К примеру TIM2_CH2 можно назначить как на PA1, так и на PB2.

Есть интересная особенность, касаемая корпусов. Для разных серий МК, назначение ног может быть частично или полностью совместимо. (AN3364)


Железо

Остались ли теперь сомнения для перехода? После того, как убедились в массе преимуществ STM32 над Arduino, надо понять, из чего выбирать.

Переход с Arduino на STM32
Бегите, глупцы!

Обзор семейств

Вся линейка микроконтроллеров использует Cortex-M.

Её делят различные семейства, которые ориентированы на использование в конкретных системах. Например, F1 предназначен для управления двигателями, а G4DC-DC преобразователями.

Рассмотрим отличия в таблице. Столбцы выстроены по ядрам, а строки по кейсу использования.

High PerformanceF2
120 MHz M3
F4
180 MHz M4F
H7
550 MHz M7F
+ 240 MHz M4F
F7
216 MHz M7
MainstreamG0
64 MHz M0+
F1
72 MHz M3
G4
170 MHz M4F
— G4 и F3 оптимизированы для смешанных сигналов
(цифровые + аналоговые)
F0
48 MHz M0
F3
72 MHz M4F
Low-powerL0
32 MHz M0+
L1
32 MHz M3
L4+
120 MHz M4F
U5
160 MHz M33
L4
80 MHz M4F
L5
110 MHz M33
WirelessWL (LoRa)
48 MHz M4F (Main)
48 MHz M0+ (Radio)
WB (BT)
64 MHz M4F (Main)
32 MHz M0+ (Radio)

Сводка особенностей Cortex-M:

  • Cortex-M0 — ARMv6-M
    Самый простой и дешёвый, поддержка только базовых инструкций. (Часть Thumb-1,2)
    Трёхуровневый конвейер.
  • Cortex-M0+ — ARMv6-M
    Оптимизированное ядро M0.
    Двухуровневый конвейер для уменьшения энергопотребления.
  • Cortex-M3 — ARMv7-M
    Расширенный набор инструкций. (Thumb-1,2, Divide)
    Трёхуровневый конвейер с прогнозированием ветвлений.
  • Cortex-M4 — ARMv7E-M
    Расширение ядра M3: добавление инструкций DSP.
    В модификации M4F добавлен блок FPU (вычислений с плавающей запятой) одинарной точности.
  • Cortex-M33 — ARMv8-M
    Концептуально похож на M4. Отличие в наличии инструкций TrustZone — защищённой зоны исполнения.
  • Cortex-M7 — ARMv7E-M
    Шестиуровневый суперскалярный конвейер с предсказанием ветвлений. В 2 раза энергоэффективнее, чем M4.
    64-битная шина данных.
    FPU двойной точности.
    Опциональный кэш.

МК на базе M0(+) призваны заменить 8-битные МК.
Ядро M3 предназначено для простых цифровых применений: работа с цифровыми шинами, генерация ШИМ-сигнала, и т.д.
M4 необходимо использовать в тех устройствах, где раскроется потенциал DSP: анализ/синтез цифровых и аналоговых сигналов, фильтрация, преобразование напряжения.
М7 рационально только в сверхсложных системах с огромным количеством вычислений.

Нейминг

Поначалу крайне легко запутаться в многообразии всех МК. Научимся читать по примеру:

STM32F401RET6TR

  • STM32 — общее для всех МК (есть ещё STM8)
  • F401 — Семейство F4, серия 401
  • R — префикс корпуса: кол-во пинов. Тут 64 ноги
  • E — объём памяти, здесь 512 КБ
  • T — постфикс корпуса: исполнение. LQFP-64 в данном случае
  • 6Temperature Grade: температурный диапазон
  • TR — опционально, упаковка Tape&Reel (бобинная лента). Если отсутствует, то Tray (лоток россыпью)

Мы рассмотрели закупочную запись (order code). Обычно это описываются в конце даташита. Во всей документации и справочниках такой МК будет прописан кратко: STM32F401RE. То есть без указания конкретного корпуса, так как кристалл одинаковый.

Переход с Arduino на STM32

Поиск плат

Во избежание проблем на первых этапах, новичку стоит обратить внимание на фирменные отладочные платы от ST. Они представлены в двух вариантах: Discovery и Nucleo.

Платы Nucleo содержат необходимый минимум для запуска микроконтроллера: обвязку, систему питания с защитами, отладчик. Все ножки МК выведены на гребёнки, соответствующие единому стандарту распиновки.
Платы бывают разного размера:
32 ножки: формат Arduino Nano.
64 ножки: чуть больше, чем Arduino Uno, поддержка всех её шильдов.
144 ножки.

Переход с Arduino на STM32

Discovery же, вдобавок перечисленному выше, обладают периферией для ознакомления. Это могут быть инерциальные сенсоры, микрофоны, датчики окружающей среды, референс-дизайны (например, для DC/DC), дисплеи.

Переход с Arduino на STM32

Другие производители тоже изготавливают свои платы. Например, серия Waveshare Core.

Переход с Arduino на STM32

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

Одна из популярных плат называется BluePill, на которой установлен МК STM32F103C8T6.
Но, в текущих условиях дефицитов, при своей цене, она потеряла актуальность и рациональность. Слишком бедная периферия, сравнительно небольшой объём памяти, ошибки в схемотехнике, шанс нарваться на подделку.

Переход с Arduino на STM32

Новый тренд на рынке — плата BlackPill. Сравнение с BluePill. В ней используется F401CCU или F411CEU. За небольшую доплату получаем кратный прирост памяти и тактовой частоты, расширенный набор периферии и таймеров, а также порт USB-C с функцией OTG. То есть способный выполнять роль как Device, так и Host, что может помочь в реализации множества идей.
Оригинальный репозиторий.

Переход с Arduino на STM32

Подборка плат для покупки

Программаторы

Способов прошить микроконтроллер существует великое множество.

Все МК имеют аппаратный bootloader, управляемый физическими пинами BOOT. Он позволяет загружать прошивку с различных периферийных шин. На всех МК для этого по умолчанию доступен UART. Поэтому, в качестве программатора может выступать любой USB-RS232 преобразователь.

Другой вариант — программный bootloader. Это небольшой кусок программы, который по внешним признакам может подменять основную прошивку. Напрмер, для обёртки STM32Duino используют DFU, который обеспечивает загрузку через USB.

Это всё про загрузку. А как же обещанная полноценная пошаговая отладка?
Для этого уже необходимо специальное дополнительное устройство, именуемое дебаггером. Именно он и является мостиком между железом и IDE.

Дебаггер/отладчик принимает команды GDB и преобразует их в команды шины отладки: JTAG или SWD.

Переход с Arduino на STM32
Схема взаимодействия

ST-Link — фирменный отладчик от производителя. Его существует 3 версии:
v1устаревшая. На базе F103C8
v2устаревшая. На базе F103CB/RB
v2.1полу-устаревшая. Программная доработка v2. Возможности: режим SWD, режим SWIM (для STM8), канал SWO, адаптер UART (VCP), возможность загрузки прошивки в режиме “флешки” (Mass Storage Device).
v3актуальная. На базе F723. Все функции v2.1, повышенная частота SWD, режим моста для SPI/UART/I2C/CAN/GPIO.

Переход с Arduino на STM32

ST-Link установлен на платах Nucleo и Discovery. Посмотреть версию можно в Product Selector: Nucleo, Discovery. v2 можно отломить от Nucleo и получить отдельную плату отладчика.

Переход с Arduino на STM32

Схема этого программатора из Nucleo была размещена в каком-то из даташитов, а прошивку давно сумели скопировать.
Поэтому, можно изготовить собственный ST-Link v2.1. Есть готовое устройство у Голинского Константина.

Переход с Arduino на STM32

Или можно приобрести примитивный свисток у китайцев. Я начинал именно с такого. Статья про переделку.

Переход с Arduino на STM32

Эту же прошивку можно использовать для превращения BluePill в полноценный отладчик.

Переход с Arduino на STM32

Существует множество других отладчиков. Индустриальным стандартом считается Segger J-Link. Он имеет свои преимущества, но все они уничтожаются неподъёмной для хоббиста ценой. (более 300-500 евро)

Переход с Arduino на STM32

Но, на самом деле, отладочные интерфейсы у ARM хорошо задокументированы. Поэтому, при желании, можно реализовать свой Host-отладочный интерфейс, разработать, например, что-то сугубо проприетарно-корпоративное.

По этому принципу был создан open-source отладчик BlackMagic Probe. Платы уже на руках, а статья про него выйдет в начале-середине февраля.

Переход с Arduino на STM32

Софт и прошивка

Вся логика работы микроконтроллера описывается в прошивке. Она представляет из себя набор последовательно выполняемых команд. Чаще всего для этого используют языки Си или С++. Компиляция происходит через специализированный GNU Embedded Toolchain. Отладка через стандартный GDB.
Всё как для настольных платформ, только инструменты свои.

Взаимодействие с периферией осуществляется с помощью библиотеки CMSIS. Это есть низшая прослойка между железом и программным кодом. Сама по себе она предоставляет удобный доступ ко всем процессорным и периферийным регистрам.

Родные инструменты

Освоить CMSIS с ходу довольно сложно. Поэтому производители (вендоры) изобретают некоторые “обёртки” вокруг этого низкого уровня. Конкретно у ST это LL (Low-Layer) и HAL (High Abstraction Level). Они не только упрощают работу, но и обеспечивают переносимость кода между разными МК.

Ранее был SPL, но более он не поддерживается.

Переход с Arduino на STM32
Схема взаимодействия слоёв

Все эти библиотеки объединяет программный пакет STM32Cube. Он включает в себя API и периферийные драйверы для микроконтроллеров, а также инструменты разработки и отладки.

Одна из таких утилит — CubeMX. Это кроссплатформенный графический редактор конфигурации микроконтроллера и генератор начального кода.

Переход с Arduino на STM32
Скриншот интерфейса CubeMX
Нажмите для увеличения

CubeMX включен в состав CubeIDE, бесплатной среды разработки на базе Eclipse.
Это полностью независимый инструмент для создания и отладки прошивок на все доступные МК STM32.

Переход с Arduino на STM32
Скриншот интерфейса CubeIDE
Нажмите для увеличения

У ST для ST-Link есть свой GDB-сервер. Его работа описана в другой статье.

Переход с Arduino на STM32
CLI GDB-сервера

Сторонние инструменты

Самое глупое, что можно использовать — фреймворк STM32Duino. Это тупиковая веточка, такое не уважаем.

Переход с Arduino на STM32

Следующий по сложности — ARM Mbed. Это разработка ARM преимущественно для IoT-устройств. Ориентирована, в основном, на Nucleo.

Те, кому не нравится Eclipse (CubeIDE), используют другие IDE.
Есть специфические для embedded: Keil от ARM, IARMikroC, и т.д.
Для Visual Studio есть плагин: Visual GDB.
Для VS Code существуют такие плагины: плагин1, плагин2. [Инструкция]

При этом используют сторонний GDB-сервер: OpenOCD.

Переход с Arduino на STM32
CLI OpenOCD

Я использую платную IDE CLion, в которой присутствуют инструменты для embedded, в связке с родным GDB-сервером. Подробнее про это можно почитать тут.

Переход с Arduino на STM32

Использование библиотек

В языке Си под библиотеками обычно подразумеваются скомпилированные статические/динамические .a/.so файлы.

Но терминология, пришедшая из Arduino, предлагает называть так обычную пару .h/.c файлов. Так как вся работа в основном с периферией, то я обычно называю это драйверами.

В любом случае, что библиотека, что драйвер, содержат заголовочный .h файл, который нужно скормить линкеру. Т.е. недостаточно просто сделать #include, как в Arduino.

В Arduino была культура создания готовых драйверов стиля “подключил и пошёл”.
С STM32 всё не так. Можно брать как ардуиновские наработки и переписывать всё взаимодействие с периферией под платформу, так и искать чужой код на GitHub или в примерах/уроках, переделывать их под свой стиль.
Либо же писать свои, с нуля, по даташитам.

Правила хорошего тона — создавать отдельный слой абстракции, платформонезависимые методы обращения к шинам, для их вызова в других методах. Таким образом, при смене платформы/обёртки, потребуется поменять всего несколько строк кода.
Например:

static inline void USER_SPI_Read(uint8_t *data, uint16_t len, uint8_t register){
     // Можно написать под HAL 
     HAL_SPI_Read(data, len, register, timeout);
     // Или под LL
     LL_SPI_Read(...);
     // Или под CMSIS
     .....
}

void SensorCollect(uint16_t *out_data){
     uint8_t buf;
     USER_SPI_Read(out_data, 1, 0xAFU);
     *out_data = .....;
}

Если используется HAL, то достаточно закинуть .h-файлы в Inc, а .c-файлы в Src. Но, этот вариант не только слишком простой, но и засоряющий визуальную структуру файлов приложения.
Для всех внешних ресурсов удобнее создать отдельную папку. Например, Libs.

В Eclipse подключить директории можно аж тремя способами.

1. “Add/remove include path..” в контекстном меню — самый удобный.

Переход с Arduino на STM32
Нажмите для увеличения

2. “Paths & Symbols” в Properties проекта.
Обратите внимание на написание директории, по умолчанию туда добавляются лишние верхние уровни.

Переход с Arduino на STM32
Нажмите для увеличения

3. В “Settings” билдера.

Переход с Arduino на STM32
Нажмите для увеличения

Результат должен быть таким:

Переход с Arduino на STM32
Нажмите для увеличения

В CLion используется система CMake, поэтому директории хэдеров там прописываются вручную. Ничего сложного в этом нет, IDE всё сама подскажет. Вносятся они в файл CMakeLists.txt, а после теста ­— в _template, чтобы изменения после регенерации не затёрлись.

Переход с Arduino на STM32
Нажмите для увеличения

Поиск информации

Первичный источник знаний ­— официальные документы. Даташиты, reference и programming мануалы, application notes. Есть удобная подборка.

Помимо этого, есть множество статей и уроков. Вот моя подборка:

Каналы на YouTube:


Заметки

Для embedded-систем есть целый стандарт написания кода. Называется он MISRA. Это свод правил для обеспечения читаемости и безопасности кода.
Проверка на MISRA работает, например, в IAR и CLion. Также можно использовать статические анализаторы. PVS-Studio, например.

Одно из этих правил касается запрета динамического выделения памяти. Например, Arduino одобряет использование таких структур для представления строк. Это хоть и удобно, но всегда убивает скорость и безопасность. Поэтому, для строк лучше использовать классический массив char[].

То же касается и использования C++. Его использование оправдано только в сверх-сложных системах для создания одинаковых объектов с разными свойствами. Например, опроса десятка датчиков.
Но, в любом случае можно обойтись структурным подходом. А так как поначалу будет использоваться HAL, написанный на структурах, то не стоит создавать кашу из абстракций.

Также MISRA обязывает использовать типы данных определённого размера, согласно stdint.h.
Вместо int int16_t. Вместо unsigned intuint16_t.
Есть лайфхак, взятый из kernel. Для того, чтобы меньше печатать, следует использовать алиасы для этих типов.
Например:

#include <stdint.h>
typedef uint8_t u8_t; // формат: typedef имя псевдоним
typedef int8_t  i8_t;

Ещё один лайфхак касается HAL. Дело в том, что очень тяжело работать с громоздкими файлами, которые генерирует CubeMX. Куча визуального мусора, есть риск промахнуться мимо USER CODE и потерять строки при регенерации.
Поэтому, я создаю отдельную пару файлов app_main и работаю с ней. В ней размещается новый главный метод main_app, который и вызывается из сгенерированного кубиком кода.

Переход с Arduino на STM32
Переход с Arduino на STM32

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

Переход с Arduino на STM32

Вывод

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

Этот путь довольно тернист, но в конечном итоге уровень всех навыков повысится.
Можно не ограничиваться STM32, а после прыгнуть на другие ARM-микроконтроллеры, работа со всеми ними на самом деле очень похожа.

Начать можно с переноса своих или чужих Arduino-проектов на STM. Или же создать какое-то устройство, полезное в быту. Так изучение будет наиболее оправданным и мотивированным.

Если задача изучения нацелена не только на хобби, но и на трудовую деятельность, то вакансии можно начать искать уже примерно через год практики. В основном все требуют хорошего знания HAL, LL и опыта работы с цифровыми шинами. Также важно иметь проекты в портфолио.

Самое главное — верить в себя, не сдаваться и не опускать руки. Всё получится! Стоит только захотеть.

Если статья была полезной, помогла что-то понять, есть специальный раздел для оказания благодарности.

Комментарии всегда открыты для вопросов и дискуссий.

Реферальные ссылки на покупку железок на AliExpress. Цена остаётся неизменной, а блог получит небольшой бонус.

Подписаться
Уведомить о
guest
1 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Рамиль
Рамиль
7 месяцев назад

Спасибо!