В последнее время на хабре появилось много статей по STM32 (здесь). В комментариях неоднократно упоминается сложность STM32 по сравнению с AVR. Эта тема особенно влияет на новичков, которые хотят начать изучение микроконтроллеров, и, видя такое мнение, выбирают для изучения AVR. Давайте разберемся, так ли сложен этот зверь — STM32?
Для этого выберем недорогой вариант платы и напишем прошивку в десяток-другой байт (да-да, мигание светодиодом в 2 килобайта сродни «Hello world» в сотни килобайт x86 для неумех). Также научимся писать программы на любом языке программирования для STM32.

Какой тип микроконтроллеров изучать? Этот вопрос, по-моему, аналогичен вопросам типа «Какой язык программирования изучать?», «Какой иностранный язык учить?». ИМХО, изучать нужно тот, который нужнее в данную минуту, для данной задачи. Когда знаешь что-то одно, изучение второго дастся намного легче, а на счет третьего и не задумаешься.
Итак, в чем же сложность STM32? Наиболее часто звучит мнение о сложности программирования его периферии. Количество и тип периферии STM32 и AVR примерно одинаков. Конфигурирование ее также не сильно отличается. Так в чем же сложность? В микроконтроллерах STM32 всю периферию нужно предварительно включать. Вот и вся сложность.
Я сравниваю AVR с общественными зданиями: все двери нараспашку, везде мониторы сверкают рекламой и свет горит, а STM32 с личным домом: хочешь телевизор посмотреть — включи сначала, потом переключай каналы, захотел пи-пи — открой дверь и включи там свет, руки помыть — открой воду, и так далее. Не верите? Убедимся вместе.
Я выбрал самую дешевую плату из предложенных на aliexpress (рисунок выше). Чуть дороже $2, 180 рублей в декабре 2015. На борту минимальная обвязка: два кварцевых резонатора — высокочастотный на 8МГц и часовой на 32.768Гц, кнопка «сброс», два джампера выбора режима загрузки, пара светодиодов — на питание и на ножке PC13 и набор разъемов: microUSB, отладочный, две гребенки для всех выводов микроконтроллера.
Дешевле только купить все детали, сделать самому плату и спаять. Чем шить и отлаживать? Если есть ST-LINK, то лучше им, нет — не беда, есть еще несколько вариантов, например через USB-USART переходник, нет и его — можно напрямую через USB, правда нужно самому написать драйвер для такого случая, никто пока не озаботился. ST-LINK достаточно дешев, да и входит во все платы серии DISCOVERY. Вот и я воспользовался таким.

Подключаем питание, светодиод весело мигает, плата исправна. Скачиваем и устанавливаем программу-программатор (масло-масляное) «STM32 ST-LINK Utility» (все программы и документы берем на сайте производителя). Пытаемся считать прошивку… Программа защищена от чтения. Видимо, недаром все говорят о сложности написания программ для STM32, даже китайцы защитили эту сверхсложную программу от взлома. Или там спрятана закладка-вирус? Разбираться не будем, снимаем защиту и получаем девственно чистый микроконтроллер STM32F103C8T6.
Давайте тоже помигаем светодиодом, сделаем, так сказать, реверс-инжиниринг в уме родной прошивки. Чем? Чтобы не городить споры по выбору среды разработки, я это сделаю в родной Visual Studio Community. Мне кажется, для Windows лучше для мужчины нет.
Как там программа мигания для ардуины? Конфигурируем ножку на выход и в цикле переключаем ее с нуля на единицу и обратно.
А как будет выглядеть она же для STM32? Намного сложнее. Сначала включим свет в комнате конфигурации ножек микроконтроллера, а затем «Конфигурируем ножку на выход и в цикле переключаем ее с нуля на единицу и обратно». Я понимаю, сложно… Но мы справимся.
В документе «RM0008. Reference Manual» на наш микроконтроллер посмотрим карту памяти для нужных нам регистров.
1. Включим тактирование порта C (наш светодиод висит на ножке 13 порта C). Смотрим документ. Нужный нам регистр RCC_ABP2ENR (переводим: регистр сброса и тактирования — вторая низкоскоростная шина периферии). Адрес порта — 0x40021018, нужный бит IOPCEN (порт ввода-вывода C — бит разрешения) четвертый — 0x00000010.
2. Сконфигурируем ножку на вывод. Смотрим документ. Нужный нам регистр GPIOC_CRH (переводим: регистр порта ввода-вывода C — конфигурационный регистр для старшей половины ножек). Адрес порта — 0x40011004, за конфигурацию каждой ножки отвечают 4 бита, значение для переключения ножки на выход — 0001b, для ножки 13 значение — 0x00100000.
3. Как переключить логическое значение на ножке. Смотрим документ. Нужный нам регистр GPIOC_ODR (переводим: регистр порта ввода-вывода C — регистр вывода данных). Адрес порта — 0x4001100С, его значение напрямую выводится в ножки микроконтроллера, для ножки 13 значение — 0x00002000. Все готово для написания программы (не забыть выложить проект на github):
С векторами прерываний, надеюсь все понятно? Мы используем только два из них, поэтому незачем занимать память пустышками. Все остальные прерывания включаются программно, не включали — значит они никогда не сработают. Исключение — третий вектор HardFault, если случилось — микроконтроллер неисправен или сбоит, для простых проектов (не космос-авиация, не медицина) можно не обрабатывать.
Это учебный проект, конечно следует оформить все адреса как символические константы в отдельный h-файл с большим количеством дефайнов, как это сделано в CMSIS. Можно взять их и приспособить для своих нужд. Для компиляции использую gcc, прошивка с помощью «STM32 ST-LINK Utility». Прошивка заняла 56 байт (привет, ассемблер).
Вроде много получилось, тогда на сегодня все.
Во второй половине расскажу о программировании STM32 на любом языке программирования.
Для этого выберем недорогой вариант платы и напишем прошивку в десяток-другой байт (да-да, мигание светодиодом в 2 килобайта сродни «Hello world» в сотни килобайт x86 для неумех). Также научимся писать программы на любом языке программирования для STM32.

Вступление
Какой тип микроконтроллеров изучать? Этот вопрос, по-моему, аналогичен вопросам типа «Какой язык программирования изучать?», «Какой иностранный язык учить?». ИМХО, изучать нужно тот, который нужнее в данную минуту, для данной задачи. Когда знаешь что-то одно, изучение второго дастся намного легче, а на счет третьего и не задумаешься.
Итак, в чем же сложность STM32? Наиболее часто звучит мнение о сложности программирования его периферии. Количество и тип периферии STM32 и AVR примерно одинаков. Конфигурирование ее также не сильно отличается. Так в чем же сложность? В микроконтроллерах STM32 всю периферию нужно предварительно включать. Вот и вся сложность.
Я сравниваю AVR с общественными зданиями: все двери нараспашку, везде мониторы сверкают рекламой и свет горит, а STM32 с личным домом: хочешь телевизор посмотреть — включи сначала, потом переключай каналы, захотел пи-пи — открой дверь и включи там свет, руки помыть — открой воду, и так далее. Не верите? Убедимся вместе.
Обзор платы
Я выбрал самую дешевую плату из предложенных на aliexpress (рисунок выше). Чуть дороже $2, 180 рублей в декабре 2015. На борту минимальная обвязка: два кварцевых резонатора — высокочастотный на 8МГц и часовой на 32.768Гц, кнопка «сброс», два джампера выбора режима загрузки, пара светодиодов — на питание и на ножке PC13 и набор разъемов: microUSB, отладочный, две гребенки для всех выводов микроконтроллера.
Дешевле только купить все детали, сделать самому плату и спаять. Чем шить и отлаживать? Если есть ST-LINK, то лучше им, нет — не беда, есть еще несколько вариантов, например через USB-USART переходник, нет и его — можно напрямую через USB, правда нужно самому написать драйвер для такого случая, никто пока не озаботился. ST-LINK достаточно дешев, да и входит во все платы серии DISCOVERY. Вот и я воспользовался таким.
Подключаем питание, светодиод весело мигает, плата исправна. Скачиваем и устанавливаем программу-программатор (масло-масляное) «STM32 ST-LINK Utility» (все программы и документы берем на сайте производителя). Пытаемся считать прошивку… Программа защищена от чтения. Видимо, недаром все говорят о сложности написания программ для STM32, даже китайцы защитили эту сверхсложную программу от взлома. Или там спрятана закладка-вирус? Разбираться не будем, снимаем защиту и получаем девственно чистый микроконтроллер STM32F103C8T6.
Первая программа
Давайте тоже помигаем светодиодом, сделаем, так сказать, реверс-инжиниринг в уме родной прошивки. Чем? Чтобы не городить споры по выбору среды разработки, я это сделаю в родной Visual Studio Community. Мне кажется, для Windows лучше для мужчины нет.
Как там программа мигания для ардуины? Конфигурируем ножку на выход и в цикле переключаем ее с нуля на единицу и обратно.
А как будет выглядеть она же для STM32? Намного сложнее. Сначала включим свет в комнате конфигурации ножек микроконтроллера, а затем «Конфигурируем ножку на выход и в цикле переключаем ее с нуля на единицу и обратно». Я понимаю, сложно… Но мы справимся.
В документе «RM0008. Reference Manual» на наш микроконтроллер посмотрим карту памяти для нужных нам регистров.
— Пойдем простым и логическим ходом.
— Пойдем вместе.
1. Включим тактирование порта C (наш светодиод висит на ножке 13 порта C). Смотрим документ. Нужный нам регистр RCC_ABP2ENR (переводим: регистр сброса и тактирования — вторая низкоскоростная шина периферии). Адрес порта — 0x40021018, нужный бит IOPCEN (порт ввода-вывода C — бит разрешения) четвертый — 0x00000010.
Отступление
У микроконтроллеров все как у взрослых процессоров. Есть высокоскоростная шина AHB aka «Северный мост» и низкоскоростная APB aka «Южный мост». Сам процессор микроконтроллера умеет все для ускорения работы: имеет предвыборку команд, конвейер выполнения команд. Нет кеша, но процессор не намного быстрее памяти, и чтение-запись в память успевает выполняться за один такт. Так что, можно сказать, вся память микроконтроллера — это один большой кеш. Ладно-ладно, не один и не большой. Два маленьких кеша.
Вся периферия отображена (маппирована) на адресное пространство. По сравнению с x86 нет команд in-out, но и Intel оставил их только для совместимости, сейчас они практически не используются.
Вся периферия отображена (маппирована) на адресное пространство. По сравнению с x86 нет команд in-out, но и Intel оставил их только для совместимости, сейчас они практически не используются.
2. Сконфигурируем ножку на вывод. Смотрим документ. Нужный нам регистр GPIOC_CRH (переводим: регистр порта ввода-вывода C — конфигурационный регистр для старшей половины ножек). Адрес порта — 0x40011004, за конфигурацию каждой ножки отвечают 4 бита, значение для переключения ножки на выход — 0001b, для ножки 13 значение — 0x00100000.
3. Как переключить логическое значение на ножке. Смотрим документ. Нужный нам регистр GPIOC_ODR (переводим: регистр порта ввода-вывода C — регистр вывода данных). Адрес порта — 0x4001100С, его значение напрямую выводится в ножки микроконтроллера, для ножки 13 значение — 0x00002000. Все готово для написания программы (не забыть выложить проект на github):
int main(void)
{
*((int*)0x40021018) = 0x00000010; // RCC_APB2ENR = RCC_APB2ENR_IOPCEN
*((int*)0x40011004) = 0x00100000; // GPIOC_CRH = MODER_OUTPUT_13
while(1)
{
*((volatile int*)0x4001100C) ^= 0x00002000; // GPIOC_ODR ^= BIT_13
int i; for (i=1000000; i>0; i--) ;
}
}
extern int _eram;
__attribute__ ((section(".isr_vector")))
int g_pfnVectors[] =
{
(int)&_eram, // начальное значение стека
(int)main // Reset Handler
};
С векторами прерываний, надеюсь все понятно? Мы используем только два из них, поэтому незачем занимать память пустышками. Все остальные прерывания включаются программно, не включали — значит они никогда не сработают. Исключение — третий вектор HardFault, если случилось — микроконтроллер неисправен или сбоит, для простых проектов (не космос-авиация, не медицина) можно не обрабатывать.
Это учебный проект, конечно следует оформить все адреса как символические константы в отдельный h-файл с большим количеством дефайнов, как это сделано в CMSIS. Можно взять их и приспособить для своих нужд. Для компиляции использую gcc, прошивка с помощью «STM32 ST-LINK Utility». Прошивка заняла 56 байт (привет, ассемблер).
Еще отступление
Еще одно утверждение о сложности STM32 — мало документации на русском языке. Спорно. Необходимы только два документа — Datasheet и Reference Manual на нужный микроконтроллер. Язык на котором он написан сложно назвать английским. Я изучал язык по непереведенным игрушкам, уровень английского остался на том же уровне, но даташиты я читаю без проблем, незнакомые термины понятны из контекста.


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