Arm. stm32 быстрый старт

STM32-VLDiscovery: мой вариант быстрого старта.

Внимание, статья обновлена. См. примечание в конце.

Предисловие.

Некоторое время назад, я, как и многие другие, принял участие в акции EBV, заказав себе упомянутую в названии платку. Моя первая попытка поковырять ее не увенчалась успехом, да и буквально одновременно с ней мне в руки попал LaunchPad… Одним словом, лежал STM32-Discovery буквально до сегодняшнего дня и пылился. Но в конце концов я взялся за него с твердым намерением наконец-то помигать светодиодом во что бы то ни стало. Естесственно, прежде всего я стал читать уже написанное на русском и английском. Однако, несмотря на большое количество статей, все они показались мне слишком разрозненными, а некоторые из более цельных — излишне объемными для начала. Возможно, я плохо искал, но так нигде и не нашел текста, прямо и без тучи лишней информации повествующего о том, как с нуля помигать светодиодом на STM32-Discovery. Полезные части встречались в разных местах, и вот я решил объединить их в по возможности лаконичное и законченное повествование.

Создание и настройка проекта.

Итак, что мы имеем: микроконтроллер STM32F100RB, установленный на плате с отладчиком; два светодиода, подключенных к PC8 (синий) и PC9 (зеленый). В качестве инструмента для написания кода я выбрал IAR.

Задача: помигать ими, попутно разобравшись, как настроить проект в IAR, что такое CMSIS и как в этих условиях организуется доступ к периферии.

Итак, наченем. Быстро и в картинках.
Запускаем IAR:

Создаем новый проект:

Просим IAR самостоятельно написать шаблон для main() и сохраняем:


И теперь начинается самое интересное – надо настроить опции проекта, чтобы у оного был шанс заработать. Если для AVR настройки проекта трогать почти не приходилось, для MSP430 дело ограничивалось небольшим вмешательством, то здесь все будет более глобально.

Первое, что нужно сделать – указать тип используемого контроллера. Как уже говорилось, в STM32-Discovery стоит STM32F100RB.


Далее надо поправить настройки линковщика. В них надо указать начало таблицы векторов прерываний, а также начало и конец областей памяти программы (ROM) и оперативной памяти (RAM). Рассчитываются они следующим образом: в STM32F100RB 128Kb памяти кода и 8Kb оперативной памяти. Начало у этих областей фиксировано на всей линейке – 0x08000000 (INTVEC) 0x08000000 (ROM) и 0x20000000 (RAM). Нам надо посчитать конечные адреса областей. Очевидно, что они получаются по следующей формуле:

[начало области] + ([размер области в килобайтах] * 1024) — 1.

Для STM32F100RB соответственно:

ROM: 0x08000000 + (0x80 * 0x400) — 1 = 0x0801FFFF
RAM: 0x20000000 + (0x8 * 0x400) — 1 = 0x20001FFF

Стек и кучу пока трогать не будем.

Действуем: ставим галку Override default, жмем Edit.

Вводим значения:


Жмем Save, сохраняем конфиг:

С линковщиком все. Теперь надо настроить отладчик, чтобы при попытке запуска программы IAR подключался к ST-LINK на плате Discovery.
Выбираем отладчиком ST-LINK:

Для корректной работы на следующей вкладке ставим галку Use flash loader:

И далее указываем режим SWD:

Все. Проект настроен, жмем OK. Теперь надо подключить CMSIS.
Что такое CMSIS, и вообще для чего она нужна? Каждый, кто уже писал под какой-нибудь МК, знает, что, прежде чем писать код, очень полезно подключить специальный заголовочный файл, в котором описаны имена регистров, модулей, констант и прочие обозначения, используемые в документации – без всего этого написание кода отдает мазохизмом. Естесственно, тут надо сделать то же самое. Только вместо одного файла надо добавить в проект шесть. Вот эти шесть файлов и есть CMSIS. Почему так много? Дело в том, что многие вещи, которые для, например, MSP430 компилятор генерирует сам – стартовый код, таблица прерываний, и т.п. здесь нужно писать руками. А этого делать, разумеется, неохота. Вот все это и входит в CMSIS.
Где добыть CMSIS? Для этого качаем STM32VLDISCOVERY firmware package – там все есть. Распаковываем, находим в stm32vldiscovery_packageLibraries папку CMSIS – это оно. Еще там есть папка STM32F10x_StdPeriph_Driver – этого добра нам не надо. В этой папке лежит т.н. стандартный драйвер периферии, представляющий собой набор функций для тех, кому лень читать даташит. Нас же, повторюсь, интересует исключительно CMSIS. Итак, нам нужны следующие файлы:

— собственно, сама CMSIS

tm32vldiscovery_packageLibrariesCMSISCM3DeviceSupportSTSTM32F10xstm32f10x.h

— заголовочный файл с определениями констант, битовых масок и т.п.

stm32vldiscovery_packageLibrariesCMSISCM3DeviceSupportSTSTM32F10xstartupiarstartup_stm32f10x_md_vl.s

— код начальной инициализации микроконтроллера.

На будущее отмечу, что файл system_stm32f10x.c содержит функцию SystemInit(), которая вызывается до main() и проводит первичную настройку. Изначально там содержится код настройки системы тактирования. Пока необходимости что-либо менять там нет.

Все перечисленные файлы кидаем в директорию проекта и добавляем в него:



Эстеты могут разложить их все по красивым папочкам, это дела не меняет.

Теперь последний шаг – небольшое допиливание CMSIS напильником. В начале файла stm32f10x.h надо раскомментировать дефайн, соответствующий используемому контроллеру. Для нас это #define STM32F10X_MD_VL, ибо STM32F100RB отностися к Medium density Value Line devices. Но не только раскомментировать нужный дефайн, но и закомментировать ненужный — #define STM32F10X_XL !


Все! Теперь действительно можно писать код!

Первая программа.

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

Блоки периферии в STM32 имеют количество конфигурационных регистров, поражающее воображение человека, пришедшего с не настолько продвинутых платформ. Порты также не являют собой исключения, но в данный момент нам понадобятся только следующие регистры: GPIOC_CRH, (настройка на ввод-вывод, настройка скорости работы), GPIOC_ODR (собственно, сам выходной регистр порта) и RCC_APB2ENR. Вообще говоря, RCC_APB2ENR не относится к регистрам порта – это регистр системы тактирования. Но у периферии STM32 есть одна особенность – она не заработает (!), пока для нее не будет явно включено тактирование. В упомянутом же регистре расположен бит, отвечающий за порт C.

Несколько слов о доступе к регистрам, он организован несколько необычно. Блоки периферии здесь представлены в виде структур, полями которых как раз и являются регистры. Как по мне, решение чрезвычайно необычное, но, по крайней мере, не вызывающее особого дискомфорта, и, в каком-то смысле, даже логичное.
Итак, собственно программа (подробности относительно записываемых значений можно найти в даташите):

Подключаем STM32-Discovery к USB. В IAR жмем Make, после окончания компиляции — Download and debug:

В режиме отладки запускаем исполнение программы, нажав Go:

Все. Светодиодики мигают, миссия выполнена.
Выход из режима отладки:

К сожалению, после выхода из отладки исполнение программы прекращается. Чтобы запустить ее вне отладки, надо передернуть USB.

Вот и все. Далее нужно просто читать Reference Manual.

Спасибо всем, дочитавшим до этого места. Надеюсь, моя статья сэкономит кому-нибудь пару вечеров.

Список использованных источников:

Была обнаружена следующая проблема: в некоторых версиях IAR при старте отладки возникает ошибка — «Fatal Error: ST-Link Connection Error». При этом диалог настройки ST-Link в этой версии IAR выглядит следующим образом:

Решение (за него спасибо тов. SubDia с Радиокота): установить SWO Clock равным 32KHz.

Arm. stm32 быстрый старт

[Что нужно для работы и отладки]

1. Установите IAR Embedded Workbench 6.30, это можно сделать на Windows 7 и Windows 8 (к сожалению, Windows XP не поддерживается).

2. Купите на ebay.com китайский J-LINK (строка для поиска JLINK Emulator V8 site:ebay.com ).

3. Купите отладочную плату. Замечательный кандидат — STM32-P407 от Olimex (используется микроконтроллер STM32F407ZGT6).

Также можно выбрать одну из плат DISCOVERY от компании ST. Достоинство этих плат в том, что у них открытая документация (можно даже самому заказат печатную плату, исходные файлы Altium и Gerber опубликованы), платы DISCOVERY можно купить на AliExpress. Для плат DISCOVERY есть множество готовых примеров, они поддерживаются пакетом CubeMX.

[STM32F407ZGT6 — как сделать новый проект]

В качестве стартовой точки для нового проекта можно просто открыть пример, который предоставлен IAR или Olimex, и начать редактировать и изменять его. Так сделать проще всего, но недостаток в том, что появляются длинные пути к файлам, и название проекта не соответствует Вашему техзаданию. Поэтому можно сделать проект заново, с нуля. Потом можно сделать в нем все нужные настройки (которые были в проекте примера), и подключить к нему нужные файлы, размещенные у ближайших каталогах. Здесь я рассмотрю создание такого нового проекта по шагам. Этот проект будет просто мигать светодиодом.

1. Создание нового проекта C. Создайте в любом удобном месте диска каталог для нового рабочего пространства (workspace). Предположим, это будет каталог MyWorkspace. Запустите IAR 6.30, выберите пункт меню Project — Create New Project. откроется окно выбора типа нового проекта. Выберите C -> main и нажмите OK.

Далее откроется окно, где предложат выбрать папку для нового проекта и имя файла проекта (файл с расширением *.ewp). Перейдите в папку MyWorkspace, создайте в ней новую папку HelloWorld, зайдите в неё и в поле имени файла введите имя проекта HelloWorld, нажмите кнопку Сохранить.

Выберите в меню IAR пункт File -> Save all. Откроется окно, где будет предложено выбрать папку и имя файла для рабочего пространства (файл с расширением *.eww). Выберите папку MyWorkspace, зайдите в неё, и в качестве имени файла введите MyWorkspace. Затем нажмите Открыть.

После этого действия новый проект будет успешно создан, ему будут присвоены настройки по умолчанию, и будут созданы две новые конфигурации проекта Debug и Release. Корневой каталог проекта будет MyWorkspaceHelloWorld, а корневой каталог Workspace MyWorkspace (в этот Workspace Вы при желании можете добавлять другие проекты). В каталоге MyWorkspaceHelloWorldтакже будут созданы подкаталоги Debug (туда по умолчанию попадают выходные и временные файлы результата компиляции), settings (папка для дополнительных настроек проекта), а также будут созданы файлы HelloWorld.dep, HelloWorld.ewd, HelloWorld.ewp и main.c.

2. Настройка проекта. Как ни странно, новый проект будет даже успешно компилироваться (если выбрать Project -> Rebuild all), но это вовсе не означает, что в результате компиляции будет получено именно то, что нам нужно. Необходимо выбрать тип процессора,

Откройте свойства проекта (Project -> Options. ), на закладке General Options выберите Processor variant -> Device, нажмите кнопочку справа и выберите процессор ST -> STM32F407 -> STM32F407ZG.

Перейдите в раздел опций Debugger, и в выпадающем списке Driver выберите J-Link/J-Trace (если у Вас подключен именно этот аппаратный отладчик). Нажмите OK.

На этом минимальная настройка проекта закончена, его можно даже запустить в отладчике (Project -> Download and Debug). Но пока проект ничего не умеет, потому что в теле функции main (модуль main.c) нет никакого кода, стоит просто заглушка возврата нулевого значения:

3. Добавление модулей для управления периферией. В состав библиотеки ST есть готовые модули, которые предоставляют удобные макросы и функции для управление периферией микроконтроллера. Не будем выдумывать велосипед, просто давайте воспользуемся этой прекрасной возможностью.

Читайте также  Простой торговый автомат своими руками

Сделайте копию файла C: Program Files (x86) IAR Systems Embedded Workbench 6.5 arm examples ST STM32F4xx STM32F4xx_DSP_StdPeriph_Lib Project STM32F4xx_StdPeriph_Examples GPIO IO_Toggle stm32f4xx_conf.h, и поместите его в корень проекта, в папку MyWorkspaceHelloWorld.

Добавите в корень проекта HelloWorld новую группу, куда мы будем подключать библиотечные модули для управления периферией. Для этого нажмите правой кнопкой на имя проекта, выберите Add -> Add Group. -> и введите имя группы STM32F4xx_StdPeriph_Driver.

В каталоге рабочего пространства (у нас это папка MyWorkspace) сделайте копию папки Libraries, которую можно найти в папке примеров IAR C: Program Files (x86) IAR Systems Embedded Workbench 6.5 arm examples ST STM32F4xx IAR-STM32F407ZG-SK. После этого добавьте в папку проекта STM32F4xx_StdPeriph_Driver готовый модуль Libraries STM32F4xx_StdPeriph_Driver src stm32f4xx_gpio.c. Для этого нажмите правую кнопку на папке проекта STM32F4xx_StdPeriph_Driver и выберите Add -> Add Files. и выберите нужный файл.

Добавьте в настройки проекта пути поиска для заголовочных файлов. Для этого откройте Project -> Options -> C/C++ Compiler -> закладка Preprocessor, и добавьте в Additional include directories пути поиска:

Здесь $PROJ_DIR$ макрос, который раскрывает абсолютный путь до папки, в которой находится файл проекта HelloWorld.ewp. Макрос $TOOLKIT_DIR$ раскрывает полный путь до рабочего каталога текущего инструментария IAR (C: Program Files (x86) IAR Systems Embedded Workbench 6.5 arm).

Добавьте в окно Defined symbols символы (они используются в заголовочных файлах):

4. Мигание светодиодом. Давайте сделаем проект более осмысленным — научимся мигать светодиодом STAT1, который установлен на отладочной плате STM32-P407.

Добавьте в папку проекта STM32F4xx_StdPeriph_Driver модуль stm32f4xx_rcc.c (Add -> Add Files. выберите файл MyWorkspace Libraries STM32F4xx_StdPeriph_Driver src stm32f4xx_rcc.c).

Добавьте код инициализации ядра процессора. Создайте в Workspace группу EWARM (Add -> Add Group. -> введите имя группу EWARM -> OK) и добавьте туда файл startup_stm32f40xx.s (Add -> Add Files. -> выберите файл MyWorkspace Libraries CMSIS Device ST STM32F4xx Source Templates iar startup_stm32f40xx.s).

Также добавьте группу CMSIS, и добавьте туда модуль MyWorkspace Libraries CMSIS Device ST STM32F4xx Source Templates system_stm32f4xx.c.

Откройте файл исходного кода main.c, и замените его старый код на следующий:

Светодиод STAT1 подключен к порту PF6 микроконтроллера (см. схему в архиве [2]).

Примечание: есть на мой взгляд некая несуразица в именовании регистров BSRRL и BSRRH, предназначенных для управления состоянием портов GPIO. Ведь по идее L значит Low, т. е. лог. 0, а H означает High, т. е. логическую единицу. Но здесь почему-то происходит все с точностью до наоборот — установка бита в регистре BSRRL почему-то приводит не к сбросу порта в 0, а в установку его в 1. Аналогично установка бита в регистре BSRRH почему-то приводит не к установке порта в 1, а к его сбросу в 0. Запись 0 никакого влияния на состояние порта не оказывает.

[Работа с портами ввода/вывода GPIO, примеры IOToggle и JTAG_Remap]

Запустите IAR 6.30, на стартовой странице выберите EXAMPLE PROJECTS -> ST -> STM32F4xx -> CMSIS and STM32F4xx stdperiph lib 1.1.0 -> GPIO, далее выберите папку, куда будет копирован пример. Откроется окно Workspace, где будет два примера работы с портами ввода-вывода: «IOToggle — STM324x7I_EVAL» и «JTAG_Remap — STM324x7I_EVAL».

Порты GPIO подключены к шине микроконтроллера AHB. С использованием регистров BSRRH и BSRRL требуется только один цикл, чтобы установить в лог. 1 любой вывод микроконтроллера, и еще 1 цикл чтобы сбросить в его 0. Таким образом, ножки GPIO можно переключать с частотой шины AHB, поделенной на 2.

В этих примерах показывается, как использовать BSRRH и BSRRL (аббревиатуры расшифровываются как Port Bit Set/Reset Register High and Low) для переключения выводов IO.

Порты PG6 и PG8 (сконфигурированные в режиме output pushpull) переключаются в бесконечном цикле:
— PG6 и PG8 устанавливаются в лог. 1 путем установки соответствующих бит в регистре BSRRL.
— PG6 и PG8 сбрасываются в лог. 0 путем установки соответствующих бит в регистре BSRRH.

В этом примере HCLK сконфигурирована на 168 МГц, так что PG6 и PG8 переключаются с частотой 84 МГц (на плате STM324xG-EVAL/STM32437I-EVAL туда подключены светодиоды LED1 и LED2). Чтобы достичь максимально возможной частоты переключения IO, опции Вашего компилятора должны быть сконфигурированы на максимальную оптимизацию по скорости.

Таблица 1. Содержимое папок примера GPIO IO Toggle.

GPIO/IOToggle/stm32f4xx_conf.h Файл конфигурации библиотеки.
GPIO/IOToggle/stm32f4xx_it.c Обработчики прерывания.
GPIO/IOToggle/stm32f4xx_it.h Заголовочный файл для stm32f4xx_it.c.
GPIO/IOToggle/main.h Заголовочный файл для main.c.
GPIO/IOToggle/main.c Основная программа.
GPIO/IOToggle/system_stm32f4xx.c Системный файл кода STM32F4xx (настройка тактовой частоты).

Примечание: файл system_stm32f4xx.c сгенерирован автоматически инструментарием конфигурации тактовой частоты (clock configuration tool), и может быть просто откорректирован с учетом Ваших потребностей. Чтобы выбрать другие настройки тактирования, используйте файл STM32F4xx_Clock_Configuration_V1.1.0.xls, предоставленный в апноуте AN3988, доступном на сайте ST [4].

По умолчанию проект настроен на запуск в симуляторе, но его легко можно перенастроить на загрузку через JTAG, и он будет работать на реальном железе (Options -> Debugger -> в выпадающем списке выберите J-Link/J-Trace). Проект GPIO IO Toggle можно с успехом использовать как стартовую точку для своих собственных проектов, особенно если Вы только начинаете разбираться с платформой STM32.

Таблица 2. Содержимое папок примера GPIO JTAG/SWD Remap.

GPIO/GPIO_JTAGRemap/stm32f4xx_conf.h Файл конфигурации библиотеки.
GPIO/GPIO_JTAGRemap/stm32f4xx_it.c Обработчики прерывания.
GPIO/GPIO_JTAGRemap/stm32f4xx_it.h Заголовочный файл для stm32f4xx_it.c.
GPIO/GPIO_JTAGRemap/main.h Заголовочный файл для main.c.
GPIO/GPIO_JTAGRemap/main.c Основная программа.
GPIO/GPIO_JTAGRemap/system_stm32f4xx.c Системный файл кода STM32F4xx (настройка тактовой частоты).

Кроме ножек JTAG/SWD как выход используются порты PG6 и PG8, и как вход кнопки используется порт PG15 (переключает режим инициализации программы).

Программирование ARM-контроллеров STM32 на ядре Cortex-M3. Часть 4. Регистры, старт и режимы работы контроллеров STM32

Понимаю, что статья уже получилась довольно длинной и всем хочется поскорее написать какую-нибудь программулину, делающую хоть что-то полезное, и залить её в контроллер, но так уж вышло, что контроллеры STM32 несколько сложнее простейших восьмибитных железяк, поэтому сейчас речь снова пойдёт, как пишут некоторые нетерпеливые читатели, «не о том».

В этой части мы поговорим о том, с чем нам чаще всего придётся оперировать при работе с контроллером — о рабочих регистрах ядра Cortex-M3, о режимах его работы и о том, как контроллер включается.

Итак, в ядре Cortex-M3 имеется 13 регистров общего назначения — R0..R12, регистр, используемый для хранения указателя стека, — R13, регистр связи — R14, счётчик команд — R15 и 5 регистров специального назначения.

Регистры общего назначения разделяются на младшие регистры — R0..R7 и старшие регистры — R8..R12. Разница между ними в том, что некоторые 16-тибитные команды набора thumb-2 умеют работать только с младшими регистрами, а со старшими — не умеют.

Регистров R13 вообще-то говоря два, а не один. Первый называется MSP — указатель основного стека, а второй PSP — указатель стека процесса. Однако в каждый момент доступен только один из этих регистров. Какой именно — определяется в одном из регистров специального назначения. Зачем такое надо? Это сделано для возможности организации защиты операционной системы (ага, на этот контроллер можно поставить ОС, если хочется) от кривых прикладных программ. MSP используется обработчиками исключительных ситуаций и всеми программами, использующими привилегированный уровень выполнения (например ядро ОС), а PSP — используется программами, не требующими привилегированного уровня выполнения (например, прикладными программами от которых мы хотим защитить ядро ОС). Указатели стека всегда должны быть выровнены на границу 32-хбитного слова, т.е. два их младших бита всегда должны быть сброшены в ноль.

Регистр R14 называется LR (link register) — регистр связи и используется для запоминания адреса возврата при вызове подпрограмм.

Регистр R15 называется PC (program counter) — счётчик команд и используется для хранения адреса текущей выполняемой команды.

Теперь о специальных регистрах.

Регистр xPSR содержит флаги результатов выполнения арифметических и логических операций, состояние выполнения программы и номер обрабатываемого в данный момент прерывания. Иногда об этом регистре пишут во множественном числе. Это сделано потому, что к трём его частям можно обращаться как к отдельным регистрам. Эти «подрегистры» называются: APSR — регистр состояния приложения (тут как раз хранятся флаги), IPSR — регистр состояния прерывания (содержит номер обрабатываемого прерывания) и EPSR — регистр состояния выполнения. Полностью структура регистра xPSR приведена на рисунке ниже.

Флаги в регистре APSR стандартные:

  1. N (negative flag) — отрицательный результат операции
  2. Z (zero flag) — нулевой результат операции
  3. C (carry flag) — флаг переноса/займа
  4. V (overflow flag) — флаг переполнения
  5. Q (saturation flag) — флаг насыщения

В регистре PRIORITY MASK используется только нулевой бит (PRIMASK), который будучи установлен в единицу запрещает все прерывания с конфигурируемым приоритетом. После включения бит PRIMASK сброшен в ноль — все прерывания разрешены.

В регистре FAULT MASK также использует только нулевой бит (FAULTMASK), который будучи установлен в единицу запрещает все прерывания и исключения, кроме немаскируемого прерывания (NMI). После включения бит FAULTMASK сброшен в ноль — все прерывания разрешены.

Регистр BASEPRI используется для запрещения всех прерываний, значение приоритета которых больше или равно, чем записано в этом регистре. Тут надо сказать, что чем меньше значение — тем выше уровень приоритета. В регистре BASEPRI используются только младшие 8 бит.

Регистр CONTROL используется для управления одним из режимов процессора — режимом потока. Нулевой бит этого регистра (nPRIV) определяет уровень выполнения (привилегированный — Privilegied, или непривилегированный — Unprivilegied), а первый бит (SPSEL) — используемый указатель стека (MSP или PSP). Разница между привилегированным и непривилегированным уровнями выполнения состоит в том, что для привилегированного уровня доступны все области памяти и все команды процессора, а для непривилегированного уровня некоторые области памяти закрыты (например, регистры специального назначения, кроме APSR, системная область) и, соответственно, команды для доступа в эти обасти — запрещены. Попытка выполнения запрещённых команд, пытающихся обратиться в закрытые области памяти вызывает генерацию исключения отказа.

Теперь о режимах работы процессора.

Процессор Cortex-M3 имеет два режима работы: режим потока (Thread) и режим обработчика (Handle). Режим Handle используется для обработки исключительных ситуаций, а режим Thread — для выполнения всего остального кода. Переключение из одного режима в другой происходит автоматически. Как мы уже говорили, когда разбирались с регистром CONTROL, в режиме Thread процессор может использовать как привилегированный уровень выполнения, так и непривилегированный, в режиме Handle — только привилегированный. Аналогично, в режиме Thread может использоваться как основной стек (MSP), так и стек процесса (PSP), а в режиме Handle — только основной стек.

Важно понимать, что, например, переключившись в режиме Thread с привилегированного уровня в непривилегированный, мы потеряем доступ в регистр CONTROL и обратно сможем переключиться только в режиме Handle. В режиме Handle бит nPRIV регистра CONTROL доступен для чтения/записи, но не влияет на текущий режим выполнения. Это позволяет изменить уровень выполнения, который будет у программы, когда процессор выйдет из режима обработчика в режим потока. Бит SPSEL в режиме Handle для записи недоступен и всегда читается как ноль, а при выходе из режима обработчика в режим потока восстанавливается автоматически. Все варианты переходов между различными режимами и уровнями выполнения иллюстрирует ориентированный граф, представленный на рисунке ниже:

Читайте также  Как рассчитать время заряда конденсатора?

Далее поговорим о том, как контроллер стартует.

Стартует контроллер всегда на внутреннем генераторе, на частоте 8 Мгц. Откуда брать тактовый сигнал в дальнейшем, на сколько его умножать или делить — настраивается в программе. Если в программе этого не сделать, то хоть десять внешних кварцев повесьте, контроллер так и будет работать от внутреннего генератора 8 МГц.

При старте контроллер анализирует сочетание уровней на двух своих ногах — BOOT0, BOOT1, и, в зависимости от этого сочетания, начинает загрузку либо из flash-памяти, либо из ОЗУ, либо из системной области памяти. Это делается с помощью уже описанного нами ранее механизма псевдонимизации. По идее загрузка всегда начинается с нулевого адреса, просто в зависимости от
сочетания на ногах BOOT0, BOOT1 начальные адреса памяти назначаются псевдонимами одной из трёх областей: flash, встроенного ОЗУ или системной области. Справа приведена табличка, в которой указано, какая именно область проецируется в начальные адреса памяти в зависимости от сочетания ног BOOT0, BOOT1.

При этом в системной области производителем зашита специальная программа (bootloader), которая позволяет запрограммировать flash-память. Но об этом позже.

Первым делом контроллер считывает 32-х битное слово по адресу 0x00000000 и помещает его в регистр R13 (указатель стека). Далее он считывает 32-х битное слово по адресу 0x00000004 и помещает его в регистр R15 (счётчик команд). Последнее действие вызывает переход на начало программного кода и дальше начинается выполнение программы.

Слово по адресу 0x00000004 (адрес начала основной программы) называется вектор сброса. Вообще в памяти контроллера после указателя стека по адресу 0x00000000, начиная с адреса 0x00000004 должна лежать таблица векторов исключений и прерываний, первый вектор в которой — это вектор сброса, а остальные вектора — адреса процедур обработчиков различных исключений и прерываний. В простейших программах, если вы не собираетесь обрабатывать исключения и прерывания, все остальные вектора, кроме вектора сброса, могут отсутствовать. Хотелось бы обратить внимание, что в таблице векторов указываются именно адреса начала обработчиков, а не команды перехода на эти обработчики, как, например, в 8-ми битных пиках или атмелах.

Надеюсь понятно, что если ногами BOOT0, BOOT1 начальная область памяти установлена псевдонимом, например, flash-памяти, то считывание по адресу 0x00000000 реально приведёт к считыванию адреса 0x08000000 (начало flash-памяти), а считывание адреса 0x00000004 — к считыванию адреса 0x08000004 и так далее.

Ну и в завершение скажу, что стартует контроллер всегда в режиме потока с привилегированным уровнем выполнения.

ARM. STM32 быстрый старт

Данная статья, которая является еще одним «быстрым стартом» в освоении ARM-контроллеров, возможно поможет сделать первые шаги в освоении 32-битных контроллеров ARM на базе ядра Cortex-M3 — STM32F1xxx серии. Возможно данная статья (которых на эту тему появляется как грибов после дождя) станет для кого-то полезной.

Введение

Почему ARM?
1. Есть из чего выбрать (разными производителями сегодня выпускается более 240 ARM-контроллеров)
2. Низкая цена (например за 1$ можно получить 37хI / O, 16K Flash, 4K RAM, 2xUART, 10x12bitADC, 6x16bitPWM).

А начнем нашу работу с контроллеров фирмы ST Microelectronics. Контроллеры на основе ядра ARM Cortex-M3 характеризуются широким набором периферии, высоким уровнем рабочих характеристик, низкой цене
P.S. В самом начале создается впечатление, что ARM’ы это какие-то страшные (в пайке, разводке, программировании) существа. Но это только на первый взгляд 🙂 и вы в этом сами убедитесь.

Итак, изучать ARMы будем на примере контроллеров STM32F1. Одновременно эта серия имеет несколько линеек:

  • Value line STM32F100 — 24 МГц CPU, motor control, CEC.
  • Access line STM32F101 — 36 МГц CPU, до 1 Mб Flash
  • USB access line STM32F102 — 48 МГц CPU with USB FS
  • Performance line STM32F103 — 72 МГц, до 1 Mб Flash, motor control, USB, CAN
  • Connectivity line STM32F105/107 — 72 МГц CPU, Ethernet MAC, CAN, USB 2.0 OTG

Также существует следующая классификация:

STM32F101xx, STM32F102xx, STM32F103xx

STM32F101xx, STM32F102xx, STM32F103xx

Connectivity line devices

Придется часто лазить здесь
Еще скажу несколько слов об этом ресурсе. Ясное дело, выбираем нужный контроллер и попадаем на страницу с кучей файлов в формате. рdf. (вкладка Design support). Можно читать все, но достаточно ознакомиться с такими файлами:
1. REFERENCE MANUAL (содержит полную спецификацию на контроллер).
2. ERRATA SHEET (содержит описание ошибок, которые могут возникать при работе с периферией).
3. Остальные документы содержат примеры работы с периферией, вопросы, связанные с программированием, описание некоторых библиотек, а с самого низа страницы можно найти EVARM-проекты демоплат и подобное ПО.

Архитектура

Итак, наш контроллер STM32 содержит в себе Cortex-M3 процессор (M означает серию для бюджетных устройств). Для того, чтобы начать программировать ARMы и не пользоваться только default’ными примерам и настройками нужно иметь представление об их архитектуре. Для начала:
1) 32-битный МК, выполненный по Гарвардской архитектуре (память программ и данных разделены),
2) имеет несколько отдельных шин и 3-ступенчатый конвейер и более 10 регистров общего назначения, что позволяет выполнять операции параллельно и (большинство) — за один такт.
3) набор инструкций — Thumb-2 (смесь 16 — и 32-битных команд, ориентированный на компиляторы C / C + +).

Рассмотрим упрощенную блок-схему шинной архитектуры STM32:

Архитектура на примере линейки Connectivity devices

Итак, давайте коротко пройдемся по основам основ:
Матрица шин (bus matrix) — контроллер высокоскоростных шин, обеспечивающий независимую связь и арбитраж (в случае одновременного доступа к одному ресурсу) между системной шиной и шиной данных ядра, DMA, Ethernet (masters) и периферией — SRAM, FLASH, AHB (slaves) .

Шины ядра:
ICode bus — 32-битная шина инструкций — обеспечивает связь ядра с интерфейсом инструкций Flash.
DCode bus — шина данных — обеспечивает связь ядра с интерфейсом данных во Flash.
System bus — системная шина ядра — обеспечивает связь ядра и периферии
Flash interface (FLITF) интерфейс Flash-памяти — обеспечивает чтение, запись, стирание, чтение с буфером предварительной выборки, защиту памяти (от записи или чтения).
AHB system bus (Advanced High-performance Bus) — шина, которая связывает матрицу шин и периферийные шины APB (Advanced Peripheral Bus (Bridge)). Шина AHB, предназначена для управления, например, регистрами системной периферии (GPIO ЦАП и т.п.). Надо сказать, что шины APB1,2 работают на разных частотах: так APB2 может работать на частоте ядра, а быстродействие APB1 ограничено 36 МГц. Поэтому, на APB2 и висит скоростная периферия (АЦП, некоторые таймеры порты ввода / вывода и т.д.)
DMA (Direct Memory Access) — обеспечивает прямой доступ к памяти в обход ядра (нужно лишь задать что, откуда и куда передать, а DMA сам все возьмет и передаст кому надо через матрицу шин)
Reset & Clock Control (RCC) — обеспечивает тактирование ядра и периферии (которая по дефолту отключена от тактового сигнала) и сброс контроллера.

Стандартная схема подключения

И здесь для начинающих возникает вопрос в чем и как рисовать и разводить печатные платы для, например, 144-ногого микроконтроллера (48-ноги еще куда не шло). Однако ничего страшного в рисовании схемы, разводке и пайке данных контроллеров нет. Для этого можно пользоваться программой Eagle (она содержит библиотеку компонентов ST или в крайнем случае можно поискать в Интернете или скачать внизу статьи), можно попробовать рисовать платы в старом добром Sprint-е (хотя, первый вариант мне кажется более надежным). Ниже приведены стандартные схемы включения контроллеров семейства Value line STM32F100С4 и Connectivity line STM32F105

Привожу базовую схему подключения контроллеров STM32F1 и некоторые их нюансы:

  1. Корпус: контроллеры STM32 помещены в корпусах LQFP с числом лапок от 48 до 144, при этом распиновка ножек контроллеров в одинаковых корпусах — совпадает, что не может не радовать.
  2. Питание:
    1. Контроллер питается от источника в 3.3 В (хотя можно подключать 2-3.6 В).
    2. Хотя напряжение питания равно 3.3В, много ножек контроллера толерантны к 5В сигналов (см. в спецификации лапки с пометкой FT).
    3. Vbat — используется для подключения резервного источника питания. Если в схеме резервный источник не используется, то Vbat надо посадить на общий источник питания.
    4. Vdd_1 . 4 подтягиваем к «+», Vss_1 . 4 сажаем на «-» источника питания.
    5. Спецификация на контроллер советует поставить параллельно источнику питания 5 конденсаторов в 100нФ (поближе к контроллеру) и один на 4.7мкФ (ближе к Vdd_3). Во многих схемах авторы часто не ставят их, думаю, если контроллер питается от чистого стабилизированного источника их можно не ставить.
    6. Питание АЦП (он питается напряжением 2,4-3,6 В) и цифровой части схемы в STM32 разделены (для большей надежности, очевидно) и если мы не используем отдельный источник для АЦП, Vdda / Vssa сажаем на соответствующие выводы общего источника, иначе схема может работать некорректно и непредсказуемо. В 100-пиновых корпусах есть еще дополнительные лапки опорного источника АЦП Vref + / Vref-. Vref- нужно повесить на Vdda, а на Vref + можно бросить от 2,4 В до Vdda.
  3. Резонатор. STM32 может тактироваться от:
    1. Внутреннего высокочастотного генератора на 8 МГц (HSI).
    2. Внутреннего низкочастотного источника тактовых импульсов 40 кГц (LSI).
    3. Внешнего высокочастотного осциллятора (HSE).
    4. Внешнего низкочастотного осциллятора на 32,768 кГц (LSE-генератор может работать вместе с HSE или синхросигналом и обеспечивает синхронизацию часов реального времени и работу оконного сторожевого таймера).
    5. Внешнего сигнала синхронизации (его частота должна быть целым делителем максимальной рабочей частоты контроллера).
  4. Сброс контроллера можно провести:
    1. «заземлив» лапку NRST. Стоит сказать, что разработчик постарался и уже включил подтягивающий резистор этой лапки. (external reset)
    2. С помощью одного из сторожевых таймеров независимого или оконного (IWDG или WWDG reset).
    3. С помощью схемы слежения за низким напряжением (low-power management reset)
    4. при входе в режим Standby
    5. при входе в режим Stop
    6. Программно — установкой определенного бита

Для удобства пайки LQFP корпусов, существуют переходники. Продаются на eBay, бывают универсальные и под фиксированное количество ножек. Средняя цена: 1$ за штуку, посмотреть можно здесь.

  • Все
  • Тематические

    В прошлой статье мы настроили IDE, и теперь просто обязаны испытать STM32 в деле. Этот урок будет служить этаким трамплином для программерского прыжка в STM32: помигаем светодиодами, поиграемся с таймером — легко и непринуждённо, без копошения в несущественных сейчас деталях. Цель урока — дать общее представление о том, как программируются эти МК.

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

    • Сносно писать на языке программирования C. То есть, уметь кодить на C консольные утилитки для ПК, хотя бы поверхностно представлять себе, что получается из кода при компиляции, уверенно пользоваться указателями (в т.ч. указателями на указатели).
    • Уметь работать в командной строке и знать про переменные окружения вроде PATH.
    • Уметь читать. Это не шутка, часто люди пробегают глазами сообщения об ошибках, даже не понимая написанного, а то и вовсе их не читают, а потом задают вопросы: «А что значит ошибка gcc: fatal error: no input files?», хотя ответ очевиден.
    • Естественно, знать азы электроники. Курс — не про подключение светодиодов к плате, а про микроконтроллеры STM32 и их особенности.

    И, конечно же, приветствуется умение работать в Linux (:

    Итак, приступим к практическому использованию STM32. Для всех микроконтроллеров Cortex-M3 есть одна общая для семейства библиотека CMSIS, которая содержит в себе описание констант, функций, адресов регистров и т.п. для работы с системным таймером SysTick и контроллером прерываний. Доступ к остальной периферии, которая уже зависит от производителя, осуществляется через библиотеки, предоставляемые производителем конкретного МК. У ST Microelectronics такая библиотека для каждого семейства МК называется Standard Peripheral Library. Название длинноватое, так что далее я её буду звать просто SPL.

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

    Сделайте копию скелетного проекта для своей платы и настройте его, если ещё не сделали этого ( описание настройки тут ). Я использую плату STM32VLDiscovery , и буду писать код для неё, так что назвал копию stm32vld_quickstart. Всё, что нужно сделать после копирования, чтобы можно было полноценно работать с проектом — это заменить название ELF-бинарника в файлах gdb_commands_debug и gdb_commands_release с stm32vld_template.elf на stm32vld_quickstart.elf. К эльфам, кстати, эти файлы никакого отношения не имеют: ELF = Executable and Linkable Format.

    Для начала, зажгём два пользовательских светодиода, которые находятся на краю платы, противоположном разъёму mini-USB. Они подключены к порту C, к пинам 8 и 9. У STM32 порты 16-битные, так что не удивляйтесь такой нумерации пинов.

    Как вы, наверное, заметили, плата STM32VLDiscovery поставляется с прошивкой, которая при включении платы мигает светодиодом PC9, а при нажатии пользовательской кнопки (синяя) на секунду зажигает светодиод PC8 и увеличивает скорость мигания светодиода PC9. А мы возьмём, и всё сломаем!

    Откройте в проекте исходник main.c и скопируйте в него следующий код:

    Жмите Ctrl+B, чтобы собрать проект, запускайте утилиту stlink (командой «st-util -1») и отладочную конфигурацию в Eclipse через меню Debug→Debug configurations. , чтобы программа залилась в МК. Когда запустится отладка и курсор встанет на первом выражении в main(), жмите F8 (continue). Оба светодиода должны зажечься. Кстати, если вас напрягает долгая прошивка через stlink, в Windows вы можете использовать улитилу CoFlash от создателей CoIDE — тогда из файлов gdb_commands* нужно будет убрать строки «load /stm32vld_quickstart.elf».

    Наверняка у вас возникли некоторые вопросы — например, про тактирование порта C и частоту GPIO. Это особенности STM32: при включении МК тактирование на периферию не подаётся — это сделано для снижения энергопотребления, так что прежде чем что-то пытаться делать с периферией, нужно подать на неё тактовый сигнал. Это касается всей периферии, не только GPIO. Что до частоты — это частота обновления состояния вывода GPIO. Сам контроллер STM32F100RBT6B может работать на частоте 24 МГц, но скорость работы пинов может быть другой. Для STM32F10x доступны 3 частоты — 2, 10 и 50 МГц. В случае с нашим МК работать будут только 2 и 10 МГц, а сейчас нам и 2 МГц хватит за глаза.

    Ну, одними светодиодами сыт не будешь, так что давайте-ка задействуем пользовательскую кнопку на PA0. Пусть при её нажатии зажигается один светодиод и гаснет другой:

    Как видите, сконфигурировать пин на вход ничуть не сложнее, чем на выход. Функции SPL позволяют читать/писать как порты целиком, так и отдельные комбинации битов, что очень удобно. Код получается не сложнее ардуинистого. Кстати, в общей сложности режимов GPIO имеется 8 — входы/выходы со всякими подтяжками и Open Drain. Но, если заглянуть в STM32VLDiscovery User manual (скачать у нас ), то там вы найдёте принципиальную схему платы, на которой видно, что пользовательская кнопка уже прижата к земле через резистор R21 (10 K). О режимах GPIO я расскажу в следующей статье.

    Антидребезг я здесь никакой не применял, так что реакция на нажатие кнопки не всегда будет адекватной. Но мы можем это исправить примитивным способом — опрашивать кнопку не постоянно, а 100 раз в секунду, к примеру. Тут-то нам и пригодится таймер SysTick, который не умеет ШИМ и прочих вкусностей, но зато 24-битный и очень лёгкий в использовании. А для пущей крутизны нагрузим его миганием светодиода:

    Здесь мы настраиваем таймер так, чтобы он срабатывал каждые SystemCoreClock/100 тиков. Костанта SystemCoreClock в случае с STM32100RBT6B равна 24000000 (24 МГц) — это максимальная его частота при работе от кварца. Тут нужно учитывать, что таймер SysTick 24-битный, и значения больше 16777216 он использовать не может, но это легко обойти, используя свою переменную-счётчик в обработчике прерывания. В этом примере я использовал счётчик для переключения светодиода 10 раз в секунду. По-хорошему, обработку прерывания лучше делать в главном цикле, а в прерывании выставлять какой-нибудь флаг. Прерывания и правильную работу с ними мы тоже, со временем, рассмотрим под всеми углами.

    Теперь вы получили представление о том, как работать с SPL, и готовы к более серьёзным вещам — в следующей статье мы изучим GPIO вдоль и поперёк.

    ОБОРУДОВАНИЕ
    ТЕХНОЛОГИИ
    РАЗРАБОТКИ

    Блог технической поддержки моих разработок

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Но по техническим характеристикам! Что стоит только сравнение разрядности обрабатываемых данных. 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 миллионов выборок в секунду. Собираюсь на ней сделать динамическую подсветку телевизора, т.е. обрабатывать видеосигнал.

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

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

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

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

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