AVR vs STM32: як перейти і чому варто. Частина 4

Я починав з AVRок, а потім з’явилось Arduino зі своїми шильдами, датчиками, сенсорами. Це супер захопливо і дуже зручно, макетки, проводульки і майже нуль пайки. За 12 років знайомства перепробував купу усього, і є проєкти, які без упину працюють більше 10 років. Оскільки ця тема цікава, то зустрічав костильні кастомні рішення навіть на конвеєрах і ЧПУ.

Пам’ятаю, як в 2016 році створював радіоклуб і познайомився з чоловіком, який зібрав ЧПУ, на якому різбив ікони. Це було щось неймовірне. А ще один член нашого клубу робив дрони для контрабандістів, за допомогою яких через кордон до Європи переправляли цигарки. Робили радіоключі для відкривання авто і майстер-ключі для домофонів. Приблуди для зміни міри наливання бензину на колонках АЗС. Звісно, не все прямо на ардуїнках, але точно на AVR. Цікавий проєкт, цікаві часи.

Тож подивився я років надцять тому на STM32 і подумав, навіщо воно мені? Arduino працює, бібліотек купа, все просто. Але були проєкти, де тре було ну дуже економне енергоспоживання. У моєму випадку це датчик рівня газу, який встановлений у вибухово небезпечній зоні. Мав відповідати певним правилам, зокрема до нього не можна було тягнути проводульки, і він повинен був бути реалізованим у вибухозахищеному корпусі. В ідеалі така собі коробочка з батарейкою, яка передає дані на сервер раз чи два на добу по GSM. На практиці батарейку міняли раз на три роки.

Купив я плати розробника з stm32 на борту, декілька книжок, погуглив. Попробував китайську IDE для stm. Зробив кілька учбових проектів. Заробив гемарой Намучився і закинув. Забігаючи наперед скажу, що Ардуїно і avr для моїх проектів вистачало з головою, і вистачає до цих пір, і в нас взаємна любов. Та одного дня перебуваючи в глубокій духовній практиці, було виявлено незакритий гештальт, який значно фонив і мав негативний вплив на моє духовне прозріння.

Тому і вирішено було написати bare-metal код для STM32. І в цьому опусі поділюсь першими враженнями.

Ще раз зазначу, що це проміжна стаття серії, для тих хто знає AVR/Arduino і хоче зрозуміти STM32. Трохи вищого рівня ніж «ось бібліотека підключи і працює» — а що реально відбувається всередині і чому STM32 влаштований саме так. Погнали.

Перше здивування: де PORTB?

На AVR все просто:

// AVR ATmega328P — мигаємо PB5 (це D13 на Arduino Uno)

#include <avr/io.h>

int main(void) {
    DDRB |= (1 << PB5); // пін як вихід
    while (1) {
        PORTB ^= (1 << PB5); // toggle
        _delay_ms(500);
    }
}

Три рядки. DDRB, PORTB — просто змінні. Йопта невже чорна Магія?

На STM32:

// STM32F103 — мигаємо PC13 (вбудований LED на Blue Pill)

#include <stdint.h>

#define RCC_APB2ENR (*(volatile uint32_t *)0x40021018)
#define GPIOC_CRH (*(volatile uint32_t *)0x40011004)
#define GPIOC_ODR (*(volatile uint32_t *)0x4001100C)

int main(void) {
     RCC_APB2ENR |= (1 << 4); // тактування GPIOC
     GPIOC_CRH &= ~(0xF << 20); // очищаємо PC13
     GPIOC_CRH |= (0x2 << 20); // output push-pull 2MHz
     while (1) {
          GPIOC_ODR ^= (1 << 13);
          for (volatile int i = 0; i < 500000; i++);
     }
}

Більше коду. Магічні адреси. Незрозумілий RCC. Навіщо це все?

Чому на AVR простіше

ATmega328P (самий популярний на моїй пам’яті)— маленький мікроконтролер. 32 КБ Flash, 2 КБ SRAM, 23 GPIO. Периферії мало — UART один (є рішення як зробити три), SPI один, I2C один.

Регістри периферії на AVR — це буквально змінні в пам’яті даних. Компілятор знає де вони знаходяться і дає їм імена:

// AVR — DDRB це просто адреса 0x24 в пам'яті
// але avr/io.h ховає це від тебе

DDRB = 0xFF; // виглядає як звичайна змінна

Плюс в тому, що на AVR немає тактування периферії. Вмикаєш живлення і все вже працює. Не треба думати про RCC.

AVR простіший бо мабуть скромніше. Менше периферії → менше регістрів → менше налаштувань.

Чому на STM32 складніше але краще

STM32F103 (моя перша платка і мабуть теж дуже популярна, у мене є коробка плат десятирічної витримки в ідеальних умовах, так до слова) це зовсім інший рівень. 64 КБ Flash, 20 КБ SRAM, 37 GPIO, 3 UART, 2 SPI, 2 I2C, 7 таймерів, ADC, USB, CAN.

На правах реклами: ви можете придбати в мене одну з плат дуже задорого (100 долларів США). Отримавши при цьому плату десятирічної витримки, яка пройшла езотеричний обряд очищення та заряджання кремнієвими духами. Одна її присутність у вашій лабораторії чи майстерні гарантує Благість, Удачу, Присутність Кремнієвого духу, оберіг від КЗ, втоми та поганого настрою, а найголовніше вона захистить вас від зайвих 100 баксів, які ви точно мали витрати на пиво, блуд чи цигарки 😀😀😀

1. Карта адрес (Memory Map)

На AVR регістри периферії живуть в окремому I/O просторі. На STM32 — все в одному 32-бітному адресному просторі:

0×08000000 Flash (твій код)
0×20000000 SRAM (твої змінні)
0×40000000 Периферія APB1 (таймери, I2C, UART2/3)
0×40010000 Периферія APB2 (GPIO, SPI1, UART1, ADC)
0xE0000000 Системна периферія (NVIC, SysTick)

Це означає що будь-який модуль — DMA, відладчик, Linux через UART може читати і писати в будь-який регістр периферії напряму.

2. Тактування (RCC)

На AVR периферія завжди тактується. На STM32 — за замовчуванням вимкнена. Економія енергії.

// STM32: спочатку вмикаємо тактування
RCC_APB2ENR |= (1 << 4); // GPIOC on
// тільки після цього регістри GPIOC реагують на запис

Забув тицьнути в RCC і периферія мовчить. І ніхто не підкаже чому. Думаю це найпопулярніша помилка новачків на STM32.

3. Більше можливостей GPIO

AVR: пін або вхід або вихід. STM32: вісім режимів — input floating, pull-up, pull-down, output push-pull 2/10/50MHz, open-drain, alternate function, analog.

// input floating: 0×4
// input pull-up: 0×8
// output push-pull 2MHz: 0×2
// AF push-pull 50MHz: 0xB ← для UART TX, SPI
// AF open-drain 50MHz: 0xF ← для I2C

Порівняння: UART

AVR ATmega328P

void uart_init(uint32_t baud) {
     uint16_t ubrr = F_CPU / 16 / baud - 1;
     
     UBRR0H = (ubrr >> 8);
     UBRR0L = ubrr;
     UCSR0B = (1 << TXEN0) | (1 << RXEN0);
     UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // 8-bit
}

STM32F103

void uart_init(uint32_t baud) {
    RCC_APB2ENR |= (1 << 14); // USART1 clock
    // PA9 TX → AF push-pull 50MHz

    GPIOA_CRH &= ~(0xF << 4);
    GPIOA_CRH |= (0xB << 4);
    USART1_BRR = 8000000UL / baud; // простіше ніж на AVR!
    USART1_CR1 = (1<<13)|(1<<3)|(1<<2); // UE+TE+RE
}

BRR на STM32 простіший — просто ділимо частоту на baud. На AVR формула складніша і залежить від режиму.

Порівняння: переривання

AVR — переривання через макрос

ISR(INT0_vect) { // макрос приховує все
   // твій код
}

int main(void) {
    EICRA |= (1 << ISC01); // falling edge
    EIMSK |= (1 << INT0); // увімкнути INT0
    sei(); // глобальні переривання
}

STM32 — переривання через таблицю векторів

void EXTI1_IRQHandler(void) { // точне ім'я з RM0008
    if (EXTI_PR & (1 << 1)) {
        // твій код
        EXTI_PR = (1 << 1); // скидаємо прапорець
    }
}

int main(void) {
    AFIO_EXTICR1 &= ~(0xF << 4); // Port A для EXTI1
    EXTI_FTSR |= (1 << 1); // falling edge
    EXTI_IMR |= (1 << 1); // unmask
    NVIC_ISER0 |= (1 << 7); // IRQ7 = EXTI1
}

На STM32 видно весь ланцюжок: GPIO → AFIO → EXTI → NVIC → ISR. Ця архітектура однакова на будь-якому Cortex-M — STM32, nRF52, LPC, SAMD. Вивчив один і розумієш всі.

Де AVR виграє

Та без перебільшення думаю є речі де AVR зручніший:

1. Простота старту. П’ять рядків і LED мигає.
2. Менше документації. Datasheet ATmega328P — 450 сторінок. RM0008 — 1136 сторінок.
3. Передбачуваність тактування. AVR завжди запускається без налаштувань.
4. Програматори дешевші. USBasp — $2. ST-Link v2 — $3-5.

Де STM32 виграє

1. Продуктивність. 16MHz 8-bit vs 72MHz 32-bit. В 10-20 разів більше обчислень.
2. Периферія. Три UART, два SPI, два I2C, USB, CAN — на одному чіпі.
3. Ціна. Blue Pill — $2-3. ATmega328P окремо — $2-4 тільки за чіп.
4. Переносимість знань. Вивчив Cortex-M3 — розумієш Cortex-M4, Cortex-A (Raspberry Pi, Android). Вивчив AVR — знаєш тільки AVR.
5. Промислове застосування. ARM домінує в embedded. Вакансій набагато більше.

Покроковий план переходу

Крок 1 — Середовище (1 день): встановити arm-none-eabi-gcc, купити Blue Pill + ST-Link v2.
Крок 2 — Перший LED (1 день): написати мигання без бібліотек. Зрозуміти RCC, CRH, ODR.
Крок 3 — UART (1 день): вивести текст в термінал. Зрозуміти BRR, CR1, Alternate Function.
Крок 4 — Переривання (2-3 дні): EXTI від кнопки. Таблиця векторів, NVIC, AFIO. Це найважче.
Крок 5 — Периферія (1-2 тижні): SysTick, TIM2, PWM, SPI, I2C, ADC. По одному протоколу на день.
Крок 6 — Власний HAL (1 тиждень): загорнути все в зручний API. Тепер розумієш що роблять ST HAL і CubeMX.

Крок 7 (необов’язково, можна пропустити)— Зрозуміти, що то геморно складно і повернутись на Arduino.

Крок 8 — продовжити читати цю серію статей, або розпочати свою.

Порівняльна таблиця

ПараметрAVR ATmega328PSTM32F103C8T6
ЯдроAVR 8-bitARM Cortex-M3 32-bit
Частота16 MHzдо 72 MHz
Flash32 KB64 KB
SRAM2 KB20 KB
GPIO2337
UART13
SPI12
I2C12
Таймери37
ADC10-bit, 6 каналів12-bit, 10 каналів
USBнемаєє (FS)
CANнемаєє
Ціна платиArduino Uno ~$5-25Blue Pill ~$2-3
Документація450 стор1136 стор
Складність стартунизькасередня
Переносимістьтільки AVRвесь ARM світ

Головна відмінність — рівень абстракції

Arduino — це digitalWrite(13, HIGH). Зручно. Але що під капотом — невідомо.
AVR bare-metal — це PORTB |= (1 << PB5). Вже краще. Але I/O простір прихований.

STM32 bare-metal — це *(volatile uint32_t *)0×4001100C |= (1 << 13). Бачиш все. Адреса, розмір, volatile — нічого не приховано.

І це не недолік STM32. Це перевага для розуміння.

Якщо знаєш AVR — знаєш Arduino. Якщо знаєш STM32 bare-metal — знаєш як працює будь-який мікроконтролер на ARM. А ARM — це 90% embedded ринку.

Код на GitHub: github.com/pipicosim800-maker/stm32F103

Серія «STM32 з нуля без HAL» на DOU.ua

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось6
До обраногоВ обраному2
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Десь з 2007 по 2008 року фірма ST безкоштовно розсилала ( по підписці) свою плату STM32F100B-Discovery. Я отримав цю плату разом посилання на ресурси для програмування,
найбільш повним виявився Keil. Він містив приклади ініціалізації і запуску практично всіх узлів мікроконтролера і чудовий дебаггер. Зараз , по моєму, найкращим пакетом для роботи є VS Code, до якого можна під’єднати як Keil, IAR, так і практично все інше.

Я embedded-панк
За вікіпедією Панк — це молодіжна субкультура, що виникла в середині 1970-х у США та Великій Британії, заснована на панк-рок музиці, ідеології анархії, особистій свободі та протесті проти соціальних норм. Панки вирізняються епатажним стилем (ірокези, шкіряні куртки, шпильки) та принципом DIY («Зроби сам»).

Звичайно, набагато простіше переказати з розумним видом своїми словами фірмовий мануал на чіп, так і стаття набігає і якісь скілли добавляються, заодно і по новому велосипед можна
винайти. На рахунок вірусів, то потрібно скачувати з Keil.com, а не російських торрентів

Чому Кeil (free 32KB) а не ІAR(free 32KB or 30 days)?
Це при тому, що є рідний Куб, і при бажанні можна прикрутити VScode

Звичайно, набагато простіше

звиздіти, а не мішки тягати та обливати помиями інших

Лабай статтю, з радістю обкладем пісюнами: а що «так понубськи, ти чьо школоло а не чоткий пацан», «чому ріжеш гланди через задній прохід а не як нормальні люде», «даташіт і дурний прочитає і з розумним виглядом блінк зробе»

Такого типу коментарі — показник вашого IQ і відсутності модерації на DOU

Просто відзеркалення вашого внутрішнього стану. За що боролись на то і напоролись. Показник IQ відносний і те, що ви до нього апелюєте означає лише одне, ви не знаєте навіщо його створили і що насправді він визначає

Судячи з вашого коментаря ви не читали ні цю серію статей ні мануал. Як людина, яка багато часу присвятила самопізнанню і вивченю психології, я розумію що ваші коментарі направлені на обезцінення моєї праці. Чому? Ну ви краще знаєте відповідь. Якщо не знаєте, то я відповім, — ви просто заздрите бо теж хотіли б написате про це і навіть спробували та Ваш єдиний топік-переказ мануала нікого не зацікавив. Я запросив би вас на інтенсиви Архітектура тіні де працюю з такими як ви та він вже тиждень як стартував ;)

І що цікаво під вашим топіком хтось написав, що у кожного embedded розробника я б дещо перефразував «embedded панка» є своя саморобочка 😀

Для ARM Cortex M0, M0+ можливо найти безкоштовний Keil (не старіше за v$.74, вищі версії урізані) з прикладами, Знаючи С не становииме проблеми розібратися в роботі ARM

можливо найти безкоштовний Keil

з бешкоштовними вірусами і бекдорами та іншим спайваре

А хіба не цікаво пройти шлях і розібратись з самих основ. Побути дослідником — розібрати і спробувати скласти чи створити щось своє?

Є книга по stm32 зараз не пам’ятаю назви (в мен десь була в pdf) там інженер робить, щось схоже як я тільки бере файли з st hal. Теж наглядно і досить цікаво. Тож це поширений спосіб навчання

Взагалі не дуже розумію, нащо користувати той самий кеіл, коли є купа безкоштовних середовищ, і у кожного вендора своє. Куб, середовища на базі екліпса, середовиша на базі візуалки, середовища на баз теї, вскод.

Крок 7 (необов’язково, можна пропустити)— Зрозуміти, що то геморно складно і повернутись на Arduino.

Відкопати стюардесу

Крок 8 — продовжити читати цю серію статей, або розпочати свою.

Закопати знову і продовжити страждати як справжній мужик

Складно щось додати чи спростувати 😀😀😀😀

Підписатись на коментарі