ARM для Ардуїнщиків, які прагнуть чогось більшого
Від архітектури ядра до реального заліза на столі. Це ввідна стаття серії уроків STM32 з нуля без HAL: що під капотом Blue Pill · ST-Link v2 · Linux · arm-none-eabi-gcc
Як пише Ю. Ревич у вступі до книги «Занимательная електроника», — «як відомо кожен сходить з розуму по своєму. Є люди, здвинуті на збиранні сірникових етикеток чи монет, є ті хто стрибає з парашутом». Один з різновидів подібних психічних здвигів — радіолюбителі до яких зокрема і відносяться усілякі распберіПіЩики, ардуїнЩики, stmЩики, espШніки та інші Щики і Шніки цієї категорії.
Тож якщо ти, як і я входиш до цієї категорії або вже намагався світлодіодом на Arduino, підключав DHT22 через бібліотеку і загалом розумієш навіщо потрібен pull-up резистор тоді, ця стаття якраз для тебе. Сьогодні поговоримо про ARM: що це таке насправді, чому половина заліза на твоєму столі на ньому і побудована, і як взагалі орієнтуватись у цьому зоопарку чіпів.
Пишу з особистого досвіду: у мене на столі одночасно живуть Raspberry Pi Pico, Luckfox Pico Pro, STM32F103, Esp32 і купа периферії. Всі вони в якомусь сенсі «ARM» — але написати прошивку для одного і запустити на іншому без змін неможливо. Чому? Давай розбиратись.
ARM це не процесор. Це бізнес-модель
Перший факт, який ламає мозок новачкові: Arm Holdings не виробляє жодного фізичного чіпа. Взагалі жодного. Вони продають ліцензії на право використовувати розроблену ними архітектуру процесорного ядра.
Схема виглядає так: Arm розробляє ядро (наприклад, Cortex-M3), описує його в специфікаціях та RTL-коді, а компанії типу STMicroelectronics, Raspberry Pi Ltd, Espressif і ще кількасот інших платять за право це ядро вставити у свій чіп і додати власну периферію: таймери, UART, SPI, ADC, Wi-Fi стеки тощо.
Саме тому STM32F103 і Raspberry Pi Pico обидва є ARM, але вони несумісні на рівні прошивки. Однакове ядро, але різна периферія, різне відображення пам’яті, різні SDK і HAL-бібліотеки.
Станом на 2026 рік ARM-архітектура присутня у більш ніж 95% смартфонів, більшості embedded-мікроконтролерів і активно заходить у серверний сегмент — AWS Graviton4, Apple M4, Qualcomm Oryon. RISC-V наступає знизу, але в embedded Cortex-M поки тримає позиції впевнено.
Три сімейства: Cortex-A, R і M
Arm ділить свої ядра на три великих сімейства. Якщо ти займаєшся embedded то тобі потрібне переважно щось одне, але знати про решту корисно, бо вони іноді зустрічаються в одному і тому ж проекті.
Cortex-A — там, де є Linux
Application-процесори. Тут живуть Android-смартфони, Raspberry Pi, роутери, одноплатники. Головна фіча — MMU (Memory Management Unit), тобто апаратна підтримка віртуальної пам’яті. Саме вона дозволяє запускати повноцінні ОС з ізольованими процесами.
Актуальна лінійка: Cortex-A55 (ефективне ядро у більшості Android SoC), Cortex-A78/X2 (продуктивні ядра), Cortex-A720 (2023+). На відміну від статті 2019 року, сьогодні «Cortex-A15 для флагманів» — це вже музейний експонат.
- Наш приклад: Luckfox Pico Pro на базі RV1106 — Cortex-A7 @ 1.2 ГГц. Ми на ньому крутимо Buildroot Linux, Go HTTP-сервер і RTSP відеострім. Все на чіпі розміром з ніготь.
Cortex-R — real-time для серйозних дядьків
Realtime-процесори з жорсткими часовими гарантіями та підвищеною відмовостійкістю. Живуть у ABS-системах, жорстких дисках, SSD-контролерах, промисловій автоматиці. Детермінований час відповіді — головна фішка.
В домашніх поробках embedded ці ядра не зустрінеш, але в automotive або industrial, вони точно є.
Cortex-M — наш мікроконтролерний бродяга
Microcontroller-процесори. Саме тут живе більшість embedded-розробки: від датчиків до складних приблуд. Немає MMU але є детермінований час реакції, мало жере і норм ціна. Ключові представники:
- Cortex-M0/M0+: мінімальне ядро,
2-ступінчастий конвейер, тільки Thumb-2. Raspberry Pi Pico (RP2040) — два ядра M0+ @ 133 МГц. - Cortex-M3:
3-ступінчастий конвейер, апаратне ділення, bit-banding. STM32F103 мабуть класика жанру, 72 МГц. - Cortex-M4: додається DSP-інструкції та опційний FPU одинарної точності. STM32F4 серія.
- Cortex-M7:
6-ступінчастий суперскалярний конвейер, FPU подвійної точності, кеш. На2025–2026 роки на думку гуглШІ STM32H7 залишається «королем» серед класичних мікроконтролерів (MCU), але контекст «топовості» трохи змістився через появу нових гравців. - Cortex-M33/M85: нові ARMv8-M ядра з TrustZone для безпечних застосунків.
Cortex-M зсередини: що варто знати
Всі Cortex-M ядра мають схожу внутрішню організацію. І варто зазначити, що embedded на ARM відчувається інакше ніж на AVR.
Thumb-2: один набір інструкцій
Cortex-M використовує виключно Thumb-2 — змішаний набір 16 і
NVIC: переривання
Nested Vectored Interrupt Controller вбудований прямо в ядро контролер переривань. Підтримує до 240 зовнішніх переривань з 256 рівнями пріоритетів. Головнае тут автоматичне збереження стану: 8 регістрів пушаться апаратно при вході в ISR, без жодної інструкції пролога.
Саме тому FreeRTOS так добре живе на STM32 бо переключення контексту відбувається через PendSV переривання, а NVIC забезпечує передбачувані латентності. На STM32F103 при 72 МГц час входу в переривання — ~12 циклів (≈167 нс).
SysTick: системний таймер
Bit-banding
Технологія атомарного доступу до окремих бітів через аліасний регіон пам’яті (є в M3/M4, немає в M0). Кожен біт в 1 МБ зоні відображається на окреме
На практиці в сучасному коді з HAL/LL-бібліотеками STM32 bit-banding майже не потрібен — бібліотеки використовують SET_BIT/CLEAR_BIT через атомарні операції або критичні секції. Але знати про нього треба, бо в легасі-коді зустрічається.
Наші герої: залізо на столі
Raspberry Pi Pico — RP2040, Cortex-M0+
RP2040 — перший власний чіп Raspberry Pi Ltd (2021),як на мене дуже цікавий. Два ядра Cortex-M0+ @ 133 МГц, 264 КБ SRAM, Flash зовнішній через QSPI — і PIO (Programmable I/O), якого немає більше ніде.
PIO — це вісім програмованих стейт-машин з власним набором інструкцій, які виконуються незалежно від CPU. Можна реалізувати WS2812, UART на нестандартній швидкості, VGA-сигнал, I2S — все без завантаження процесора. Мабуть, найоригінальніша фіча у low-end ARM-чіпах за останні роки.
У нашому проекті PiPicoSim800: RP2040 тягне MQTT 3.1.1 стек (написаний руками без бібліотек), двоядерну архітектуру (core0 — бізнес-логіка, core1 — комунікація з SIM800L через UART), 74HC595 для розширення GPIO на реле, BMP180 через I2C, EEPROM через SPI, XOR-шифрування з динамічною сіллю на основі ADC-шуму.
Cortex-M0+ — найпростіше ядро лінійки: немає FPU, немає DSP,
STM32F103 — Cortex-M3, класика жанру
STM32F103 — мабуть, найпоширеніший ARM-мікроконтролер у DIY-просторі. Cortex-M3 @ 72 МГц,
Cortex-M3 — перше ядро з повноцінним ARMv7-M ISA. Саме з F103 починалась епоха «ARM для всіх» на початку
У нашому проекті Автобот: Pi Pico — платформа для RC-ровера з маніпулятором. Маємо живий досвід з PX4: виявилось, що PX4 офіційно не підтримує MPU6050 через I2C (драйвер MPU6000 на SPI, а MPU9250 I2C відкидає WHO_AM_I=0×68). Купили MPU9250 — проблему вирішено, і це стало темою для статті.
ESP32 — не ARM, але сусід по столу
Окремо скажемо про ESP32, бо він є мало не у кожного, хто прийшов з Arduino. ESP32 — це не ARM. Класичний ESP32 (ESP32-D0/S2/S3) використовує Xtensa LX6/LX7 — власну архітектуру Tensilica/Cadence. ESP32-C3, C6, H2 — вже RISC-V, ще одна відкрита альтернатива.
Але підхід до розробки дуже схожий: Arduino-фреймворк, FreeRTOS всередині esp-idf, Flash через UART, GPIO/SPI/I2C периферія, OTA оновлення. Якщо ти прийшов з ESP32 — у тебе вже правильний майндсет. Просто архітектура ядра інша, і низькорівневі деталі будуть різнитись.
Конкуренція ARM vs RISC-V у low-end embedded — одна з головних тем
Luckfox Pico Pro — Cortex-A7, Linux у мініатюрі
Тут ми вже в іншому світі. RV1103 від Rockchip — це Cortex-A7 @ 1.2 ГГц з Mali-G52 GPU, 256 МБ DDR3L на борту і окремим NPU для нейромереж. Розмір — як USB-флешка.
Cortex-A7 підтримує ARMv7-A: MMU, NEON SIMD, VFPv4 FPU. Це дозволяє запускати Python, Go, Node.js і TensorFlow Lite без особливого болю. Принципова відмінність від Cortex-M: є ОС, є процеси, є файлова система. Але й складність зростає — замість простого HAL_GPIO_WritePin() у тебе /sys/class/gpio/ або /dev/mem через devmem2.
У нашому стрімінговому проекті: RTSP з камери MIS5001 → ffmpeg → Python HTTP-проксі з ThreadingHTTPServer (окремий ffmpeg-процес на клієнта, з retry-логікою) → браузерний дашборд. Go-сервер для температурного API і syslog-ендпоінту. Автостарт через /etc/init.d/S9x скрипти з sleep-затримками для правильного порядку залежностей.
Порівняння: що у нас є і навіщо
|
Параметр |
Pi Pico (RP2040) |
STM32F103 |
ESP32 (не ARM!) |
Luckfox (RV1103) |
|
Ядро |
2× Cortex-M0+ |
Cortex-M3 |
Xtensa LX6 |
Cortex-A7 |
|
Частота |
133 МГц |
72 МГц |
240 МГц |
1.2 ГГц |
|
SRAM |
264 КБ |
|
520 КБ |
256 МБ DDR3L |
|
Flash |
2 МБ (QSPI) |
|
|
MicroSD |
|
FPU |
Немає |
Немає |
Є |
VFPv4 |
|
ОС |
Bare-metal / FreeRTOS |
Bare-metal / FreeRTOS |
FreeRTOS / Arduino |
Linux (Buildroot) |
|
Wi-Fi/BT |
Немає (Pico W — є) |
Немає |
Wi-Fi + BT вбудований |
SoC з Ethernet |
|
Ціна, $ |
~4 |
~2—5 |
~3—8 |
~15—20 |
|
Наш проект |
PiPicoSim800 IoT / Автобот |
навчальний стенд |
— |
MJPEG стрімінг |
Інструменти: з чим реально працюємо
STM32CubeIDE — офіційна IDE від ST, заснована на Eclipse. Вбудований HAL-генератор через CubeMX, дебагер через ST-Link, профайлер. Безплатна. Важка як танк, але працює.
PlatformIO — якщо хочеш VSCode замість Eclipse і підтримку купи платформ (STM32, RP2040, ESP32, AVR) в одному місці. Файл platformio.ini замість купи
OpenOCD + GDB — для тих, хто хоче розуміти що відбувається. Відкриває ARM CoreSight debug через ST-Link, J-Link або CMSIS-DAP. На Linux — просто ставиться, на Windows — потребує драйверів.
picotool — утиліта для RP2040: перегляд бінарників, flash через USB в режимі BOOTSEL, інформація про UF2-образи.
arm-none-eabi-gcc — cross-компілятор для всього ARM bare-metal. Однаковий тулчейн для STM32 і Pi Pico, що зручно.
Що вибрати для свого проекту
Без зайвого маркетингу — практична шпаргалка:
- GPIO / I2C / SPI, мінімум коду, бюджет важливий → STM32F103 або Pi Pico. Cortex-M0+/M3 справляться з 99% задач.
- Нестандартні протоколи або паралельна логіка без CPU → Pi Pico з PIO. Окрема магія, серйозно.
- Wi-Fi + BT вбудовані, не принципово ARM чи ні → ESP32. Найпростіший старт для IoT, величезна спільнота.
- RTOS з жорсткими real-time гарантіями, FPU потрібен → STM32F4 (Cortex-M4) або STM32H7 (Cortex-M7). Бюджет відповідний.
- Linux, камера, мережевий стек, Python/Go потрібні → Luckfox або Raspberry Pi. Cortex-A7+ відкриває інший рівень.
- TinyML на мікроконтролері → Pi Pico + Edge Impulse або STM32 + STM32Cube.AI. Cortex-M4/M7 з DSP помітно швидші за M0+.
Практика: мигаємо LED без HAL за 272 байти
Всі ці теорії про регістри і memory map — це добре. Але краще один раз побачити в терміналі. Ось що відбувається коли пишеш під STM32 без жодної бібліотеки.
Структура проекту
Нам потрібно рівно чотири файли — і жодного HAL, жодного CubeMX, жодного XML:
- src/startup.c — таблиця векторів переривань і Reset_Handler
- src/main.c — наш код
- ld/stm32f103.ld — лінкер скрипт з memory map
- Makefile — збірка через arm-none-eabi-gcc
Лінкер скрипт — це і є ARM memory map
Перший файл який пишемо — лінкер скрипт. Саме він описує де живе Flash і SRAM нашого чіпа:
MEMORY
{
FLASH (rx) : ORIGIN = 0×08000000, LENGTH = 64K
SRAM (rwx) : ORIGIN = 0×20000000, LENGTH = 20K
}
Ці дві адреси — 0×08000000 і 0×20000000 — не вигадані. Вони прописані в datasheet STM32F103 і є частиною ARM Cortex-M memory map. Після reset процесор завжди стартує з 0×08000000 і читає звідти першу інструкцію.
Reset_Handler — що відбувається після увімкнення
Перше що робить Cortex-M3 після reset — читає два
Reset_Handler копіює .data секцію з Flash у SRAM (там глобальні змінні з початковими значеннями), обнуляє .bss (неініціалізовані змінні), і викликає main(). Саме цей код виконується ще до першої строчки твого main — на AVR це робив компілятор, тут ти бачиш це явно.
main.c — тільки регістри
Весь код керування GPIO — це три макроси і три рядки в main. Ніяких HAL_GPIO_WritePin(), ніяких #include «stm32f1xx_hal.h»:
// вмикаємо тактування порту C через RCC RCC_APB2ENR |= RCC_APB2ENR_IOPCEN; // PC13 — вихід push-pull 2MHz (біти [23:20] в CRH) GPIOC_CRH &= ~(0xF << 20); GPIOC_CRH |= (0×2 << 20); // toggle PC13 в циклі GPIOC_ODR ^= GPIO_PIN_13;
PC13 на Blue Pill інвертований — LOW = LED горить. І він підтягнутий до 3.3V через резистор, тому при старті без коду LED теж горить. Це не баг плати, це особливість схеми.
Результат збірки
Збираємо одною командою make і флашимо через make flash через st-flash:
text data bss dec hex filename 272 0 0 272 110 blink.elf
272 байти. Для порівняння — порожній HAL-проект з CubeMX на тому ж F103 важить ~3-4 КБ тільки на ініціалізацію. Ми зробили те саме за 272 байти тому що знаємо що відбувається на кожному кроці.
Flash written and verified! jolly good! — і зелений LED на Blue Pill швидко мигає. Cortex-M3, 72 МГц, наші власні 272 байти коду. Ось це і є ARM зсередини.
У наступних частинах серія Уроків STM32 з нуля без HAL: що під капотом Blue Pill · ST-Link v2 · Linux · arm-none-eabi-gcc
Сподобалась стаття? Підписуйтесь на автора, щоб отримувати сповіщення про нові публікації на пошту.
7 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів