Я также раньше собирал конструкции на этих платах, но потом решил попробовать arduino-подобную плату с микроконтроллером STM32F103C8T6
Фото платы
Основные возможности микроконтроллера STM32F103C8T6
- 32-ух битное ядро ARM Cortex-M3
- Номинальная тактовая частота - 72 МГц (зависит от настроек тактирования и может быть как меньше, так и больше)
- Производительность - 1.25 DMIPS/MHz (1.25 операции за такт)
- Объем памяти программ - 64КБ (в действительности 128КБ)
- Объем оперативной памяти - 20 КБ
- Количество линий ввода/вывода - 37
- Напряжение питания - 2.0 - 3.6В (номинальное 3.3В)
- Возможность аппаратной отладки через интерфейсы JTAG и SWD
- Встроенный загрузчик программ через USART1
- 4 16-ти разрядных таймера (с 16-ти разрядным предделителем) по 4 канала сравнения в каждом, что позволяет в итоге получить до 16 каналов 16-ти битного ШИМ
- 2 сторожевых таймера
- 24-ех битный системный тймер
- 3 модуля USART
- 2 модуля SPI
- 2 модуля I2C
- 2 модуля 12-ти битного ADC (АЦП) с производительностью 1 миллион выборок в секунду
- Модуль CAN
- Модуль USB
- Модуль расчета CRC
- Модуль RTC (часы реального времени)
- 7-ми канальный модуль DMA (ПДП - прямой доступ к памяти)
- Контроллер вложенных прерываний
В интернете есть статьи на эту тему. https://geektimes.ru/post/277928/
https://geektimes.ru/post/255796/
https://geektimes.ru/post/263210/
Сперва я программировал STM32 в Arduino IDE как написано в статье, но быстро пришло понимание того что не используется вся мощь микроконтроллера, а она немалая по сравнению с AVR. Это более гибкая настройка портов и периферийных модулей, аппаратная отладка и др. Если сравнивать периферию, то разница очевидна. Например возможности таймеров http://robocraft.ru/blog/ARM/722.html
http://robocraft.ru/blog/ARM/739.html
Основные возможности таймеров
- 16-битный счётчик с автоперезагрузкой.
- 16-битный программируемый делитель частоты: с 1 по 65535.
- Схема синхронизации для запуска ЦАП.
- Генерация прерывания и/или запроса DMA по переполнению счётчика.
- До 4-х каналов для:
- Захвата сигнала (input capture).
- Сравнения вывода (output compare).
- Генерации сигнала ШИМ (выровненного по границе или по центру).
- Генерации одиночных импульсов.
- Схемы синхронизации для управления таймерами при помощи внешних сигналов и для соединения нескольких таймеров друг с другом.
- Комплементарные выходы с программируемым dead-time.
- Счётчик повторений.
- Вход BRK для сброса выходов таймера или выставления их в известное состояние.
- Поддерживают инкрементальные (квадратурные) энкодеры и датчики Холла.
- Генерация прерывания или запроса DMA по следующим событиям:
- Обновление: переполнение счётчика.
- Событие-триггер: старт, остановка, инициализация счётчика или его обновление внутренним или внешним триггером.
- Захват сигнала.
- Сравнение (output compare).
- Включение BRK.
Система тактирования намного гибче чем у ATmega328.
Тактирование STM32F103C8T6
Предусмотрена защита от сбоев работы внешнего кварцевого генератора и в случае нестабильной работы или вовсе прекращения, тактирование автоматически переключается на встроенный RC генератор HSI.
В микроконтроллер встроены часы реального времени (RTC) с возможностью тактирования от внешнего кварца с частотой 32768 Гц или внутреннего RC генератора LSI. У МК имеется специальный вывод для подключения батарейки питающей часы при отсутствии основного напряжения.
Разрабатывать программу можно в Arduino IDE, но как я написал выше, при этом не совсем рационально используются ресурсы микроконтроллера. Гораздо лучше разрабатывать программу в одной из IDE для STM32, позволяющей использовать библиотеки функций от STMicroelectronics.
Сперва я выбрал mikroBasic который показался мне простым и понятным (просто знаю бейсик), но как выяснилось, это не намного лучше Arduino IDE. Затем пробовал Keil, TrueSTUDIO, CooCox, EmBitz и др.
Наиболее простая и понятная IDE для начала на мой взгляд это EmBitz. Это простая и логичная среда, которая добавляет в проект все необходимые файлы включая библиотеки CMSIS и SPL. Остается только открыть файл main.с и написать код программы. В других перечисленных IDE с этим сложнее.
Дистрибутив EmBitz можно скачать с официального сайта. Устанавливается как любая другая программа и особенностей нет.
Ряд окон, появляющихся при первом запуске
Необходимо выбрать первую строку с компилятором EmBitz.Выбор файловых ассоциаций. Можно оставить вариант по умолчанию и файлы с EmBitz ассоциироваться не будут.
Чтобы начать разработку программы, следует создать проект.
Основные этапы создания проекта
Сначала нужно приступить к созданию проекта.Следует выбрать тип микроконтроллеров STMmicro-ARM и нажать GO.
В следующем окне нужно задать имя проекта и место размещения на диске.
Далее выбирается компилятор и настраиваются конфигурации. Нужно оставить то что по умолчанию и перейти к следующему шагу.
После нужно выбрать семейство МК. В данном случае это Cortex_M3 поскольку такое ядро у STM32F103C8T6.
После выбираем серию STM32F10x.
Далее в списке нужно выбрать STM32F103C8 или STM32F103CB. Они отличаются только размером памяти программ (64 и 128 КБ), но поскольку реально в C8 содержится 128 КБ, то разницы нет что выбрать.
В завершении создания проекта появятся несколько окон настройки отладки. Нужно оставить по умолчанию и закрыть окна кнопкой OK.
После создания проекта можно начать работу, открыв файл main.с где есть минимально необходимая часть кода.
Проект можно скомпилировать и принеобходимости запустить отладку (на скриншоте показаны кнопки панели инструментов производящие эти действия). Выполнение программы начинается с функции main, точнее перед этим выполняется очистка оперативной памяти и настройка тактирования так чтобы при частоте внешнего кварцевого генератора 8 МГц, частота ядра была номинальной и составляла 72 МГц.
Подробнее о том как это происходит
Проще всего отследить последовательность выполнения программы аппаратным отладчиком ST-Link или подобным. Следует соединить плату с отладчиком через интерфейс SWD, подключить отладчик к USB порту компьютера и запустить отладку в IDE (кнопка с перечеркнутым жучком в красном кружке справа на панели инструментов).Если все сделано правильно, появится окно с таким содержимым.
А после в IDE откроется файл startup_stm32f10x_md.S в котором отобразится текущая выполняемая строка с ассемблерным кодом, выполняемым при старте или сбросе микроконтроллера.
Чуть ниже расположен вызов функции SystemInit.
Нажав на F11 на клавиатуре можно выполнить ассемблерную инструкцию и перейти в функцию (откроется файл system_stm32f10x.c).
В функции производится инициализация и конфигурация системы тактирования микроконтроллера. В этой же функции вызывается функция SetSysClock.
В ней вызывается одна из функций настраивающая умножитель на требуемую частоту, в данном случае SetSysClockTo72 для настроки на 72 МГц.
В функции активируется внешний кварцевый генератор HSE и если это произведено успешно, умножитель настраивается на коэффициент 9 что в итоге дает (при частоте резонатора 8 МГц) 8*9 = 72МГц. Кроме этого в функции включается буфер предварительной выборки из flash памяти для кеширования инструкций и настраивается латентность flash.
После окончания выполнения кода функции SetSysClockTo72 управление снова возвращается в файл startup_stm32f10x_md.S где после выполнения еще ряда действий (очистка оперативной памяти и др.) выполнение переходит в функцию main файла main.c.
По традиции, первая программа будет мигать светодиодом. На плате для этой цели предусмотрен светодиод подключенный к выводу PC13.
Код
#include "stm32f10x_conf.h"
void DWT_Init(void)
{ // Активация модуля TRACE
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
// Разрешение работы счетчика CYCCNT модуля DWT.
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
// Задержка в циклах ядра.
void DWT_DelayCycles(uint32_t Cycles)
{
uint32_t Counter = DWT->CYCCNT;
while((DWT->CYCCNT - Counter) < Cycles);
}
int main(void)
{
// Включение тактирования порта GPIOC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
// Настройка вывода PC13 выходом.
GPIO_InitTypeDef Init;
Init.GPIO_Pin = GPIO_Pin_13; // Вывод 13.
Init.GPIO_Mode = GPIO_Mode_Out_PP;
Init.GPIO_Speed = GPIO_Speed_50MHz; // Предельная частота выхода.
GPIO_Init(GPIOC, &Init); // Конфигурация GPIOC (PC13)
DWT_Init();
while(1)
{
GPIO_SetBits(GPIOC, GPIO_Pin_13); // Логическая 1 на PC13.
DWT_DelayCycles(72000000); // Пауза 72 миллиона машинных циклов.
GPIO_ResetBits(GPIOC, GPIO_Pin_13); // Логический 0 на PC13.
DWT_DelayCycles(72000000); // Пауза 72 миллиона машинных циклов.
}
}
Далее создается и заполняется структура Init, а затем вызывается функция GPIO_Init для того чтобы настроить вывод PC13 в режим выхода. В цикле while изменяется состояние выхода PC13 что приводит к периодическому включению и выключению светодиода.
Задержка выполняется используя 32-ух битный счетчик CYCCNT блока DWT являющегося частью модуля аппаратной отладки ядра ARM Cortex-M3. Счетчик хорош тем что 32-ух битный что позволяет простыми средствами организовывать довольно большие и точные паузы.
Прошив эту программу в микроконтроллер, можно наблюдать за тем как будет периодически мигать светодиод. Прошить можно через отладчик ST-Link или встроенный Bootloader. Как это сделать написано в статье http://www.avislab.com/blog/stm32_st_link_ru/
Теперь произведем отладку этой программы. К боковому разъему SWD платы следует подключить аппаратный отладчик ST-Link.
Это выглядит так
По умолчанию выполнение программы начнется с ассемблерного файла startup_stm32f10x_md.S поскольку в нем располагается код выполняющийся сразу после сброса. Это не всегда удобно и чтобы отладчик останавливал программу (устанавливал скрытую точку останова) в начале функции main, следует открыть окно Debug interfase options (меню Debug -> Interfases) и для конфигурации Debug отметить Run to main().
Отладка программы
После запуска отладки программа в микроконтроллере начнет выполнятся под управлением отладчика и автоматически будет остановлена на первой строке кода в функции main. Желтая стрелка между номерами строк и кодом, показывает текущую выполняемую строку.Если несколько раз нажать на кнопку F10 дойдя до функции GPIO_Init и навести курсор мышки на структуру Init, то можно увидеть ее тип, адрес в памяти и содержимое полей.
Более подробно о назначении кнопок клавиатуры, используемых при отладке можно увидеть в меню Debug.
Далее нажимая кнопку F10 можно дойти до цикла while и при выполнении функции GPIO_SetBits светодиод будет гаснуть, а при выполнении GPIO_ResetBits начинать светится.
Сборка проекта и заливка прошивки в микроконтроллер
В списке конфигураций на панели инструментов нужно выбрать Release и пересобрать проект.При отсутствии ошибок внизу окна будет показана информация о сборке.
Размер прошивки составил 824 байта и не используется оперативная память, точнее используется только под стек (по умолчанию 256 байт).
Прошивка находится в папке проекта в \bin\Release\ и имеет расширение hex. Ее можно залить в микроконтроллер программой FlashLoader (через встроенный загрузчик) или программой STM32 ST-LINK Utility через отладчик ST-Link. Про оба способа достаточно подробно написано на сайте http://www.avislab.com/blog/stm32_st_link_ru/
Литература.
Обучающие статьи по теме STM32.
http://www.avislab.com/blog/stm32-list_ru/
http://narodstream.ru/programmirovanie-mk-stm32/
http://www.pvsm.ru/cat/stm32
http://microtechnics.ru/.../stm32-s-nulya/
Программы EmBitz, STM32 ST-LINK Utility, flash loader, драйверы и прошивка для ST-Link, документация на микроконтроллер STM32F103C8T6 и т. д. https://yadi.sk/d/UXQjAEMK3TYSUJ