Перейти к содержимому

Что нужно для программирования stm32

  • автор:

Низкоуровневое программирование STM32: от включения питания до «Hello, World»

В этом материале я хочу рассказать о том, как писать программы для микроконтроллеров (Microcontroller Unit, MCU) Cortex-M, вроде STM32, используя лишь набор инструментов ARM и документацию, подготовленную STMicroelectronics. У некоторых читателей может появиться вопрос о том, почему кому-то это может понадобиться. Если вам эта идея, на первый взгляд, не показалась очень уж страшной, то, возможно, вам будет интересно то, о чём пойдёт речь в этом материале. И, кстати, подумаем о том, кому и зачем это может пригодиться.

Конечно, разрабатывать программы для MCU STM32 можно с помощью существующих фреймворков. Это может быть ST HAL, обычный CMSIS, или даже что-то, более близкое к Arduino. Но… что тут увлекательного? Ведь, в итоге, тот, кто пользуется каким-то фреймворком, полностью зависим от документации к нему и от его разработчиков. И, с другой стороны, если документация к STM32 кажется кому-то, работающему с этой платформой, так сказать, бредом сивой кобылы, то можно ли говорить о том, что этот человек по-настоящему понимает данную платформу?

Поэтому давайте поговорим о низкоуровневом программировании STM32 и доберёмся от включения питания STM32 до «Hello, World».

STM32 очень похож на компьютер

На низком уровне микроконтроллер не особенно сильно отличается от полнофункционального компьютера, основанного на процессоре от Intel или AMD. Тут имеется как минимум одно процессорное ядро, инициализирующееся после подачи и стабилизации внешнего питания. В этот момент производится считывание загрузчика, код которого находится по адресу, заранее известному микроконтроллеру. А в обычных компьютерах подобную роль играет BIOS. В случае с MCU это — код, находящийся по определённому смещению в (обычно) интегрированной памяти, предназначенной только для чтения. То, что происходит потом, полностью зависит от этого кода.

В целом, этот код решает основные задачи по подготовке системы к работе. Например, задаёт таблицу векторов прерываний и записывает определённые данные в некие регистры. Очень важной задачей, кроме того, является инициализация указателя стека (Stack Pointer, SP). В начале работы системы некоторые данные из ROM копируются в RAM. В итоге вызывается функция main() , что похоже на запуск операционной системы обычного компьютера, выполняемый после завершения подготовки системы к работе средствами BIOS.

Пример Pushy

Возможно, аналогом «Hello, World» для STM32 можно назвать пример из моего фреймворка для STM32 Nodate, который я ласково называю Pushy. Он ещё проще, чем традиционный пример Blinky, так как он использует лишь регистры управления тактированием и сбросом (Reset & Clock Control, RCC) и базовые возможности интерфейса ввода/вывода общего назначения (General-Purpose Input/Output, GPIO). Код этого примера считывает входной регистр GPIO-пина и подстраивает значение на выходном пине в соответствии с входным. Благодаря этому можно, с помощью кнопки, включать и выключать светодиод. Вот код этого примера:

#include int main () < //const uint8_t led_pin = 3; // Nucleo-f042k6: Port B, pin 3. //const GPIO_ports led_port = GPIO_PORT_B; //const uint8_t led_pin = 13; // STM32F4-Discovery: Port D, pin 13 (оранжевый) //const GPIO_ports led_port = GPIO_PORT_D; //const uint8_t led_pin = 7; // Nucleo-F746ZG: Port B, pin 7 (синий) //const GPIO_ports led_port = GPIO_PORT_B; const uint8_t led_pin = 13; // Blue Pill: Port C, pin 13. const GPIO_ports led_port = GPIO_PORT_C; //const uint8_t button_pin = 1; // Nucleo-f042k6 (PB1) //const GPIO_ports button_port = GPIO_PORT_B; //const uint8_t button_pin = 0; // STM32F4-Discovery (PA0) //const GPIO_ports button_port = GPIO_PORT_A; //const uint8_t button_pin = 13; // Nucleo-F746ZG (PC13) //const GPIO_ports button_port = GPIO_PORT_C; const uint8_t button_pin = 10; // Blue Pill const GPIO_ports button_port = GPIO_PORT_B; // Установить режим вывода на пине, к которому подключён светодиод GPIO::set_output(led_port, led_pin, GPIO_PULL_UP); GPIO::write(led_port, led_pin, GPIO_LEVEL_LOW); // Установить режим ввода на пине, к которому подключена кнопка GPIO::set_input(button_port, button_pin, GPIO_FLOATING); // Если кнопка нажата (переход от высокого состояния к низкому), то 'button_down' будет в низком состоянии в том случае, если кнопка будет нажата. // Если кнопка не нажата (переход от низкого состояния к высокому, к Vdd), то 'button_down' будет в высоком состоянии в том случае, если кнопка будет нажата. uint8_t button_down; while (1) < button_down = GPIO::read(button_port, button_pin); if (button_down == 1) < GPIO::write(led_port, led_pin, GPIO_LEVEL_HIGH); >else < GPIO::write(led_port, led_pin, GPIO_LEVEL_LOW); >> return 0; > 

Тут можно сразу обратить внимание на два самых заметных элемента. Первый — это функция main() , которую вызывает система. Второй — это подключения модуля GPIO. Этот модуль содержит статический C++-класс, возможности которого используются для записи данных в GPIO-выход, к которому подключён светодиод. Его же возможности применяются и при чтении данных с входа, к которому подключена кнопка. Тут можно видеть ещё и упоминание имён пинов платы Blue Pill (STM32F103C8), но в примере имеются предустановки и для других плат, которые можно активировать, раскомментировав соответствующие строки.

Где именно в этом примере используются регистры группы RCC? В названии этих регистров содержится намёк на то, что они позволяют управлять тактовой частотой MCU. Их можно сравнить с переключателями, которые могут пребывать в двух состояниях — «включено» или «выключено», включая и отключая соответствующие возможности MCU. Если посмотреть, например, на описание регистра RCC_AHBENR в разделе 6.4 руководства по STM32F0xx, то мы увидим бит, маркированный как IOPAEN (Input/Output Port A ENable, включение порта ввода/вывода A), который управляет частотой для периферии, подключённой к GPIO A. То же касается и других портов.

Раздел 6.4.6 руководства по STM32F0xx, описание регистра RCC_AHBENR

Как можно видеть на вышеприведённой иллюстрации, RCC_AHBENR — это регистр, отвечающий за включение AHB. Это — одна из шин внутри MCU, к которой подключены процессорное ядро, SRAM, ROM и периферийные устройства.

Шины AHB (Advanced High-performance Bus) и APB (Advanced Peripheral Bus) описаны в спецификации AMBA фирмы Arm.

Раздел 2.1 руководства по STM32F0xx, архитектура STM32F0xx

В целом можно отметить, что AHB — это более быстрая шина, соединяющая процессорное ядро со SRAM, ROM и с высокоскоростной периферией. Более медленная периферия подключается к более медленной шине APB. Между AHB и APB имеется мост, позволяющий устройствам, подключённым к ним, взаимодействовать друг с другом.

Низкоуровневое программирование

Как уже было сказано, первым при включении STM32 запускается код загрузчика. В случае с MCU STM32F042x6 универсальный код загрузчика, написанный на ассемблере Thumb, можно найти здесь. Это — обычный код, предоставляемый STMicroelectronics (например, для STM32F0xx) вместе с CMSIS-пакетом. Он инициализирует MCU и вызывает функцию SystemInit() , объявленную в низкоуровневом C-коде CMSIS (вот — пример для STM32F0xx).

Функция SystemInit() сбрасывает системные регистры, отвечающие за частоту, что приводит к использованию стандартной частоты HSI (High Speed Internal oscillator, высокоскоростной внутренний генератор). После выполнения процедур настройки libc (в данном случае используется Newlib — вспомогательная C/C++-библиотека) она, наконец, вызывает функцию main() следующей командой:

bl main 

Эта инструкция, название которой расшифровывается как Branch with Link (переход с сохранением адреса возврата), приводит к переходу к заданной метке. В этот момент мы оказываемся в функции main() нашего примера Pushy. После этого в дело вступают возможности класса GPIO.

Класс GPIO

Первый вызываемый нами метод класса — это GPIO::set_output() . Он позволяет сделать указанный пин (с подключённым к нему повышающим резистором) выходным. Именно здесь мы встречаемся с первым различием между семействами MCU STM32. Дело в том, что более старые MCU, основанные на Cortex-M3 F1, имеют GPIO-периферию, очень сильно отличающуюся от той, которая используется в их более новых собратьях семейств F0, F4 и F7. Это выражается в том, что при работе с пинами STM32F1xx нужно записывать в единственный регистр множество опций:

 // Управление вводом/выводом распределено между двумя комбинированными регистрами (CRL, CRH). if (pin < 8) < // Установим регистр CRL (CNF & MODE). uint8_t pinmode = pin * 4; uint8_t pincnf = pinmode + 2; if (speed == GPIO_LOW) < instance.regs->CRL |= (0x2 else if (speed == GPIO_MID) < instance.regs->CRL |= (0x1 else if (speed == GPIO_HIGH) < instance.regs->CRL |= (0x3 if (type == GPIO_PUSH_PULL) < instance.regs->CRL &= ~(0x1 else if (type == GPIO_OPEN_DRAIN) < instance.regs->CRL |= (0x1 > else < // Установим регистр CRH. uint8_t pinmode = (pin - 8) * 4; uint8_t pincnf = pinmode + 2; if (speed == GPIO_LOW) < instance.regs->CRH |= (0x2 else if (speed == GPIO_MID) < instance.regs->CRH |= (0x1 else if (speed == GPIO_HIGH) < instance.regs->CRH |= (0x3 if (type == GPIO_PUSH_PULL) < instance.regs->CRH &= ~(0x1 else if (type == GPIO_OPEN_DRAIN) < instance.regs->CRH |= (0x1 > 

А в других упомянутых семействах MCU имеются отдельные регистры для каждой опции (режим, скорость, повышающий или понижающий резистор, тип):

 uint8_t pin2 = pin * 2; instance.regs->MODER &= ~(0x3 MODER |= (0x1 PUPDR &= ~(0x3 PUPDR |= (0x1 else if (pupd == GPIO_PULL_DOWN) < instance.regs->PUPDR |= (0x2 if (type == GPIO_PUSH_PULL) < instance.regs->OTYPER &= ~(0x1 else if (type == GPIO_OPEN_DRAIN) < instance.regs->OTYPER |= (0x1 if (speed == GPIO_LOW) < instance.regs->OSPEEDR &= ~(0x3 else if (speed == GPIO_MID) < instance.regs->OSPEEDR &= ~(0x3 OSPEEDR |= (0x1 else if (speed == GPIO_HIGH) < instance.regs->OSPEEDR &= ~(0x3 OSPEEDR |= (0x3

Запись опций в регистры выполняется с помощью побитовых операций, используемых для записи значений с применением битовых масок. Имена регистров обычно хорошо описывают их предназначение. Например — PUPDR расшифровывается как Pull-Up Pull-Down Register — «регистр управления подтяжкой к плюсу питания или к земле».

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

 uint8_t pin2 = pin * 2; instance.regs->MODER &= ~(0x3 PUPDR &= ~(0x3 PUPDR |= (0x1 else < instance.regs->PUPDR |= (0x2

Для чтения данных с входного пина мы пользуемся IDR (Input Data Register, регистр входных данных) для банка GPIO, с которым работаем:

 uint32_t idr = instance.regs->IDR; out = (idr >> pin) & 1U; // Прочитать нужный бит. 

Аналогично выглядит и использование ODR (Output Data Register, регистр выходных данных), с помощью которого осуществляется вывод данных на пин:

 if (level == GPIO_LEVEL_LOW) < instance.regs->ODR &= ~(0x1 else if (level == GPIO_LEVEL_HIGH) < instance.regs->ODR |= (0x1

И, наконец, в вышеприведённом коде имеется сущность instance , которая представляет собой ссылку на запись в структуре std::vector . Она была статически создана в ходе запуска MCU. В ней зарегистрированы свойства периферии:

std::vector* GPIO_instances() < GPIO_instance instance; static std::vector* instancesStatic = new std::vector(12, instance); #if defined RCC_AHBENR_GPIOAEN || defined RCC_AHB1ENR_GPIOAEN || defined RCC_APB2ENR_IOPAEN ((*instancesStatic))[GPIO_PORT_A].regs = GPIOA; #endif #if defined RCC_AHBENR_GPIOBEN || defined RCC_AHB1ENR_GPIOBEN || defined RCC_APB2ENR_IOPBEN ((*instancesStatic))[GPIO_PORT_B].regs = GPIOB; #endif [..] return instancesStatic; > static std::vector* instancesStatic = GPIO_instances(); 

Если периферийное устройство существует (то есть — имеется в CMSIS-заголовке для конкретного MCU, например, для STM32F042), то в структуре GPIO_instance создаётся запись, указывающая на память, соответствующую регистрам этого устройства ( regs ). К этим записям, равно как и к мета-информации, содержащейся в них, потом можно обращаться. Например, можно узнать о состоянии устройства:

 GPIO_instance &instance = (*instancesStatic)[port]; // Проверяем, является ли порт активным. Если это не так - активируем его. if (!instance.active) < if (Rcc::enablePort((RccPort) port)) < instance.active = true; >else < return false; >> 

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

Класс RCC

Класс RCC тоже интересуется тем, существует ли то или иное периферийное устройство. Делается это для того чтобы избежать разного рода сюрпризов. При этом используются те же определения препроцессора CMSIS. После проверки существования устройства включить его довольно просто:

bool Rcc::enable(RccPeripheral peripheral) < uint8_t perNum = (uint8_t) peripheral; RccPeripheralHandle &ph = (*perHandlesStatic)[perNum]; if (ph.exists == false) < return false; >// Проверка состояния текущего периферийного устройства. if (ph.count > 0) < if (ph.count >= handle_max) < return false; >// Увеличение количества обработчиков на 1. ph.count++; > else < // Активация периферийного устройства. ph.count = 1; *(ph.enr) |= (1 return true; > 

В дополнение к изменению значения соответствующего бита ( ph.enable ) мы подсчитываем ссылки. Это делается для того чтобы случайно не выключить периферийное устройство, которое используется в другом месте кода.

Запуск примера

После того, как мы разобрались с вышеприведённым материалом, у нас должно появиться некоторое понимание того, как пример Pushy работает на низком уровне. Теперь мы можем его собрать и запустить. Для этого нам понадобится, как уже было сказано, набор инструментов ARM и фреймворк Nodate. Первый можно установить с помощью используемого вами менеджера пакетов (речь идёт о пакете arm-none-eabi-gcc ) или — загрузив его с сайта Arm. Фреймворк Nodate можно установить с GitHub. После этого путь к корневой папке фреймворка нужно записать в глобальную системную переменную NODATE_HOME .

После того, как эти задачи решены, нужно перейти в папку Nodate , а потом — в подпапку examples/stm32/pushy . В ней надо открыть файл Makefile и указать предустановки, рассчитанные на используемую плату (там сейчас есть предустановки для Blue Pill, Nucleo-F042K6, STM32F4-Discovery, Nucleo-746ZG). Далее, надо открыть файл src/pushy.cpp и раскомментировать строки, имеющие отношение к целевой плате.

Далее, в папке, в которой находится Makefile , нужно собрать проект командой make . Целевая плата должна быть подключена к компьютеру с использованием ST-Link, на компьютере должна быть установлена программа OpenOCD. Если это так — MCU можно прошить командой make flash . После этого соответствующий образ будет записан в память устройства.

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

Здесь продемонстрирован простой пример низкоуровневого программирования STM32. Освоив его, вы, фактически, находитесь лишь немного «ниже» уровня примера Blinky.

Надеюсь, я смогла показать то, что низкоуровневое программирование STM32 — это совсем несложно.

Какие инструменты вы используете при написании программ для STM32?

Программирование микроконтроллеров STM32

Микроконтроллеры STM32 обратили на себя моё внимание двумя новостями. Первая новость была о выпуске платы STM32F4DISCOVERY, которая оснащена аудио-кодеком и микроконтроллером с ядром ARM Cortex-M4 с набором DSP-команд. Вторая новость была о выпуске платы Olimexino-STM32, представляющую из себя Arduino-совместимую плату на базе микроконтроллера STM32F103RB.

В ожидании появления обеих плат на рынке, я приобрёл себе плату Olimex-H103 и недорогой JTAG-отладчик ARM-USB-OCD, чтобы начать осваивать микроконтроллеры STM32 в операционной системе Linux.

Дело в том, что возможность программировать микроконтроллеры STM32 посредством интерфейса ST-Link/V2 в то время была доступна только в операционной системе Windows, к тому же отладчик OpenOCD можно использовать и для программирования других ARM-микроконтроллеров, например AT91SAM. К тому времени уже полгода у меня пылилась на полке плата Olimex-H64, так что для меня это был хороший повод приобрести JTAG-отладчик, чтобы не мучиться с попытками освоить SAM-BA и TCL.

Выбор отладочной платы

Успешно освоив 8-битные микроконтроллеры, спаяв несколько плат собственной разработки на их основе, я пришёл к выводу, что 32-битные микроконтроллеры удобнее осваивать, используя готовые отладочные платы, прежде чем пробовать разработать и спаять собственную плату.

В случае микроконтроллеров STM32 выбор платы в первую очередь основывается на выборе интерфейса программирования. Это либо IEEE 1149.1 JTAG, либо SWD-отладчик ST-Link. Лично я как пользователь Linux предпочитаю JTAG, поскольку программирование ARM-микроконтроллеров посредством JTAG в Linux поддерживается на базе открытых технологий, хотя по степени глючности оба варианта пока что не превосходят друг друга.

Платы STM32 серии DISCOVERY

В качестве стартовых отладочных плат для своих микроконтроллеров компания ST Microelectronics выпускает недорогие платы серии DISCOVERY, оснащные встроенным отладчиком ST-Link/V2.

Для разработки и программирования этих плат в Linux требуется скачать и настроить IDE-среду разработки Eclipse. В принципе, после успешной настройки программисту доступна даже возможность пошаговой отладки программы, но на практике при переходе из режима отладки обратно в режим программирования периодически происходит какой-то сбой, так что повторно войти в режим отладки у меня лично получалось через раз. Так что я предпочитаю программировать микроконтроллер из командной строки с помощью утилиты texane/stlink.

Платы STM32 с JTAG

Сторонние разработчики оснащают отладочные платы на базе микроконтроллеров STM32 интерфейсом IEEE 1149.1 JTAG для программирования и отладки. Эти платы стоят немножко дороже, но их можно программировать с помощью GDB-сервера OpenOCD.

Однако стоит учесть и то, что для программирования потребуется приобрести JTAG-программатор, в чём OpenOCD в силу своей универсальности как раз и имеет преимущественно перед встроенным ST-Link в платах серии DISCOVERY.

Программная поддержка периферийных устройств

В целом в программировании микроконтроллеров STM32 нет ничего принципиально сложного благодаря тому, что программирование периферийных устройств микроконтроллера осуществляется на основе стандартной библиотеки микроконтроллеров Cortex CMSIS (Cortex Microcontroller Software Interface Standard).

Скачав и установив Standard Peripheral Library для выбранной линейки микроконтроллеров STM32, можно попробовать скомпилировать примеры из папки StdPeriph_Examples, хотя для среды Eclipse и ARM-GCC скорее всего потребуется использовать один из базовых проектов, скопировав необходимые файлы из папки с примером в папку проекта.

Урок 1. Введение. Общие сведения, скорее впечатления, об STM32.

Уроки STM32

Вводная статья курса уроков по программированию микроконтроллеров STM32.

Этой статьей начинаю цикл уроков, посвященных программированию микроконтроллеров STM32.

Тема очень интересная, по популярности может превзойти ”Уроки Ардуино”. В принципе, это в какой-то степени продолжение или расширение ”Уроков Ардуино”. По крайней мере, я собираюсь постоянно ссылаться на статьи из этой рубрики, проводить аналогию между ними и уроками STM32.

Я не призываю бросать программировать на Ардуино и переходить только на STM32. Но есть задачи, которые на Ардуино выполнить невозможно или намного сложнее. Да и разве плохо уметь создавать системы, устройства на обоих типах микроконтроллеров.

Язык программирования в принципе один и тот же. Тем более одинаковы аппаратные компоненты, подключаемые к контроллеру: кнопки, светодиоды, дисплеи, модули проводных и беспроводных технологий связи и т.п.

Много информации уже есть на сайте. Например, зачем мне заново рассказывать про технологию клиент-сервер, если в рубрике ”Уроки Ардуино” есть статья об этом.

Контроллеры STM32 значительно превосходят по техническим характеристикам платы Ардуино на 8 разрядных микроконтроллерах ATmega328, ATmega2560 и т.п. У них более высокая производительность, больше объем памяти, периферийные устройства разнообразнее по функциям, номенклатуре, количеству. STM32 позволяют реализовывать значительно более сложные задачи, чем платы Ардуино.

Несмотря на вышесказанное я считаю, что программировать STM32 не сложнее, чем Ардуино. По крайней мере, я собираюсь так преподнести материал. Хотя объем информации будет больше.

Уроки рассчитаны как на опытных программистов, изучающих STM32, так и на людей, делающих первые шаги в программировании. Т.е. я собираюсь приводить строгую информацию и сопровождать ее подробными пояснениями. Для второй категории читателей я буду давать ссылки на аналогичные темы в ”Уроках Ардуино”. Не хочется одно и то же ”разжевывать” несколько раз.

Буду преподносить оптимальный с моей точки зрения подход к программированию STM32. Кто-то может с ним не согласиться.

Итак. Я ставлю цель:

  • научить вас практическому программированию микроконтроллеров STM32;
  • расширить ваши знания в области программирования на языке C++, конечно у кого их не хватает;
  • представить строгую техническую информацию о контроллерах STM32 на русском языке;
  • какая-то часть уроков будет посвящена аппаратной части, подключаемой к микроконтроллеру.

Общие сведения о микроконтроллерах семейства STM32.

Возможности контроллеров STM32 потрясают! По крайней мере, меня.

Плата с микроконтроллером STM32F103C8T6 по стоимости сопоставима с ценой плат Ардуино на базе ATmega328 и значительно дешевле плат типа Arduino Mega2560.

По моей партнерской ссылке она стоит всего 175 руб.

Отладочная плата STM32F103C8T6

Но по техническим характеристикам! Что стоит только сравнение разрядности обрабатываемых данных. 32 против 8!

У меня ощущение, что я сравниваю Ардуино не с маленькой дешевой платой, а с дорогим монстрообразным 32 разрядным контроллером. Судите сами.

Параметры STM32F103C8T6 Arduino Nano
Разрядность 32 бит 8 бит
Частота 72 мГц 16 мГц
Объем FLASH 64 кБайт 32 кБайт
Объем ОЗУ 20 кБайт 2 кБайт
Число выводов 37 22
Аппаратное умножение и деление Есть, 32 разряда Только умножение, 8 разрядов
АЦП 2 АЦП, 12 разрядов, 10 входов, 1 мкс время преобразования 10 разрядов, 8 входов, 100 мкс время преобразования
Контроллеры прямого доступа к памяти 7 каналов нет
Таймеры 7 3
UART 3 (выше скорость, больше режимов) 1
I2C 2 1
SPI 2 1
USB 1 нет
CAN 1 нет
Часы реального времени есть нет
Модуль аппаратного расчета CRC кода есть нет

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

И это еще далеко не самый мощный вариант STM32. У меня есть плата STM32F407VET6 с частотой 210 мГц и АЦП со скоростью преобразования до 7,2 миллионов выборок в секунду. Собираюсь на ней сделать динамическую подсветку телевизора, т.е. обрабатывать видеосигнал.

Плата STM32F407VET6

Техническая документация.

Я не буду пересказывать общую информацию о микроконтроллерах STM32. Советую вам просмотреть книжку “Мартин М. Инсайдерское руководство по STM32”, чтобы иметь общее представление о STM32. Я не стал давать ссылку. Не знаю, как обстоят дела с авторским правом на этот документ. Но найдете без труда. Подробно компоненты и узлы STM32 будем изучать в уроках.

Из строгой официальной документации надо иметь:

  • Общее описание микроконтроллера STM32F103C8. Периферия, электрические характеристики.
  • Справочное руководство. Описание регистров, работы периферии.
  • Описание ядра микроконтроллера, система команд.
  • Описание библиотеки HAL для STM32F1.

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

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

STM32. Программирование микроконтроллеров STM32.

Рад всех снова приветствовать на сайте microtechnics! Итак, на данной странице для дополнительной и наглядной систематизации я собрал некоторые из статей по микроконтроллерам STM32 и разбил их на небольшие группы. Список этот я буду время от времени пополнять параллельно с выходом новых статей, а полный набор постов можно по-прежнему найти в одной из рубрик сайта, а именно — ссылка.

STM32, связь с внешним миром

  • Modbus RTU Master. Библиотека для микроконтроллеров STM32.
  • Modbus RTU Slave. Пример реализации на микроконтроллере STM32.
  • Ethernet. Часть 1. Подключение и настройка ENC28J60.
  • Ethernet. Часть 2. ENC28J60. Прием и передача кадров.
  • Ethernet. Часть 3. Канальный уровень. Протокол ARP.
  • Ethernet. Часть 4. Сетевой уровень. Протоколы IP и ICMP.
  • Библиотека для работы с шиной 1-Wire на STM32.
  • Протокол LIN. Настройка и обмен данными. STM32CubeMx.
  • Драйвер протокола LIN для микроконтроллеров на базе UART.

Разное

  • Манчестерский код. Часть 1. Кодирование данных.
  • Манчестерский код. Часть 2. Декодирование данных.
  • STM32 и C++. Мой вариант архитектуры, обработка прерываний.
  • Рисуем изображение на экране осциллографа.
  • Отладка, STM32 и IAR, или Поймай меня, если сможешь.
  • Простейшая организация микросекундной задержки.
  • Микроконтроллер и Bootloader. Описание и принцип работы.
  • Микроконтроллер и Bootloader. Пример реализации.
  • STM32CubeMx. Быстрый старт с FreeRTOS для STM32.

Алгоритмы

  • ПИД-регулятор. Пример ПИД-регулятора температуры на STM32.
  • Настройка ПИД-регулятора. Метод Циглера-Никольса.
  • Эмуляция EEPROM на базе Flash-памяти микроконтроллеров.
  • Измерение напряжения питания микроконтроллера.
  • Мониторинг напряжения аккумулятора на микроконтроллере STM32.
  • Фильтрация и избавление от шумов в данных АЦП.

STM32 периферия

  • I2C. Настройка и пример использования шины I2C.
  • SPI и DMA. Конфигурация и пример использования.
  • ADC (АЦП) и DMA. Обзор, настройка и пример проекта.
  • UART. Прием и передача данных по UART в STM32CubeMx.
  • Timer Input Capture. Режим захвата сигнала.
  • Протокол CAN. Настройка в STM32CubeMx.
  • Watchdog. STM32CubeMx. Настройка модуля WWDG.
  • STM32CubeMx и watchdog. Настройка и использование IWDG.
  • DAC. Пример использования и настройка в STM32CubeMx.
  • USB. Реализация USB Mass Storage Device.
  • USB. Реализация USB Virtual COM Port.
  • SD-карта. Настройка FatFs в STM32CubeMx.
  • RCC. Настройки тактирования в STM32CubeMx.
  • Таймеры. STM32CubeMx. Настройка и использование.
  • GPIO. Настройка портов ввода-вывода в STM32CubeMx.
  • Быстрый старт с STM32CubeMx.

STM32 LCD

  • Подключение дисплея на базе ST7735 к микроконтроллеру STM32.
  • Дисплей на базе ST7735. Вывод изображения.
  • Дисплей на базе контроллера SSD1306. Библиотека для STM32.
  • Семисегментный индикатор. Динамическая индикация.

Датчики

  • Подключение датчика температуры DS18B20. Модуль KY-001.
  • Аудио-плеер на STM32. Воспроизведение WAV-файла.
  • Подключение магнитного энкодера AS5048 к микроконтроллеру.

Ностальгия

  • STM32CubeMx. USB Custom HID. Прием и передача данных.
  • Создание USB дескрипторов для класса Custom HID.
  • Микроконтроллер и драйвер светодиодов DM164.
  • USB. Реализация USB Audio Device Class.
  • Mass Storage Device. Использование FLASH-памяти.
  • FatFs. Файловая система FAT на внешней SD-карте.
  • Передача данных по USB.
  • Audio. Воспроизведение звука на STM32F4Discovery.
  • FreeRTOS. Быстрый старт для микроконтроллера STM32F4.
  • USB. Использование интерфейса USB на примере STM32F3.
  • Гироскоп L3GD20. Часть 2. Определение положения платы.
  • Гироскоп L3GD20. Часть 1. Настройка и обмен данными.
  • STM32 и дисплей на базе HD44780 в 4-битном режиме.
  • Подключение и использование дисплея на базе HD44780.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *