Интернет. Настройки. Тарифы. Телефон. Услуги

Программирование STM32F4. Создание нового проекта в Keil

Список статей который поможет изучить микроконтроллер STM32 даже начинающему. Подробно обо всем с примерами начиная от мигания светодиодом до управления бесколлекторным двигателем. В примерах используется стандартная библиотека SPL (Standard Peripheral Library).

Тестовая плата STM32F103, ST-Link программатор, и программное обеспечение для прошивки под Windows и Ubuntu.

VIC (Nested vectored interrupt controller) – модуль контроля прерываний. Настройка и использование прерываний. Приоритеты прерываний. Вложенные прерывания.

АЦП (аналого-цифровой преобразователь). Схема питания и примеры использования АЦП в различных режимах. Regular и Injected каналы. Использование АЦП вместе с DMA. Внутренний термометр. Аналоговый watchdog.

Таймеры общего назначения. Генерирование прерывания через равные промежутки времени. Измерение времени между двумя событиями.

Захвата сигнала таймером на примере работы с ультразвуковым датчиком HC-SR04

Использование таймера для работы с энкодером.

Генерация ШИМ. Управление яркостью светодиода. Управление сервоприводом (сервомашинками). Генерация звука.

Давно, даже очень давно, не было новых статей на нашем статье, так что пришло время наверстывать 😉 Сегодня мы положим начало изучению STM32F4. И, наверное, начнем с создания нового проекта для этих контроллеров, хотя не хотел я, честно говоря, про это писать статью, так как новый проект тут создается, в принципе, так же как и для STM32F103 (). Но все-таки бывает, что именно с STM32F4 возникают некоторые трудности, так что, все-таки, рассмотрим этот процесс в подробностях)

Так что, запускаем Keil, создаем новый проект – Project -> New uVision Project. Сохраняем новый проект в какой-нибудь папке, и затем нам предложат выбрать используемый микроконтроллер. Что ж, выбираем, пусть это будет STM32F407VG:

Готово, в появившемся диалоговом окне тыкаем «Да» и к нам в проект добавится первый файл – startup_stm32f4xx.s . Также как и раньше, мы будем использовать библиотеки CMSIS и Standard Peripheral Library , но, естественно, уже для контроллеров STM32F4xx. Так что надо их обязательно скачать и добавить нужные файлы в наш пока еще пустой проект. Кстати не раз слышал от разных людей, что попадаются какие то «не такие» библиотеки для F4, и проект даже простейший не собирается. Сам я с таким не сталкивался, тем не менее, вот проверенные библиотеки, которые я сам использую:

Итак, скачали, все готово, теперь добавляем файлы в проект. На картинке видно, какие понадобятся:

Ну вот и закончена подготовка, теперь создадим новый.c файл, в котором и будет наш код. Идем в File->New , в Keil’е открывается пустой файл, жмем File->Save as и сохраняем его под именем test.c, например. Не забываем при сохранении указать расширение файла (.c). Файл создали, отлично, но надо его еще и в проект наш добавить. Ну, собственно, в этом ничего сложного нету 😉 В этот файл запишем тестовую пустую программу:

#include "stm32f4xx.h" #include "stm32f4xx_rcc.h" #include "stm32f4xx_gpio.h" /*******************************************************************/ int main() { while (1 ) { __NOP() ; } } /*******************************************************************/

Почти все уже готово, осталось заглянуть в настройки проекта – Project->Options for target… Открывается окошко с множеством вкладок, нас тут интересуют лишь несколько. Открываем вкладку C/C++ и в поле Define прописываем:

Ну и внизу в поле надо добавить пути абсолютно ко всем файлам, включенным в проект. После выполнения этого шага можно давить на F7 (Build), и проект соберется без ошибок и предупреждений. Как видите, ничего сложного)

Но вообще я лично делаю несколько иначе. Смотрите в чем минус такого подхода. Вот мы скачали себе куда-то библиотеки CMSIS и SPL, добавили файлы из этих папок, прописали пути к файлам, все круто. НО! Проект не соберется на другом компьютере, поскольку пути все абсолютные, то есть указывают на конкретные папки на вашем компьютере. И на другой машине придется фактически заново выполнять действия по созданию нового проекта. Это огромнейший минус. Поэтому я обычно создаю отдельную папку для нового проекта, в ней создаю подпапки для CMSIS, SPL и других используемых библиотек и в эти папки запихиваю все файлы, которые мне понадобятся в каждом конкретном проекте. Вот, например, создадим папку STM32F4_Test для нашего нового проекта и в ней следующие папки:

В папки CMSIS и SPL я засунул все необходимые файлы, которые мы добавляли, создавая проект, в начале статьи. Теперь запускаем Keil, создаем новый проект и сохраняем его в нашу подпапку Project, чтобы все файлы проекта лежали в одном месте и не устраивали хаос)

Проект создан, теперь, как и раньше просто добавляем в него все файлы из папок STM32F4_CMSIS и STM32F4_SPL. В папку Source запихиваем наш тестовый.c файл с функцией main() и его тоже добавляем в проект. Осталось настроить настройки =) Все то же самое – в поле define прописываем:

USE_STDPERIPH_DRIVER,STM32F4XX



Собираем проект – ошибок нет, полет нормальный! В принципе в итоге получили то тоже самое, но теперь проект будет без проблем сразу собираться на любом другом компьютере, а это очень удобно и полезно) Абсолютно все файлы проекта теперь лежат рядом, в одной папке, а пути стали относительными и их не придется менять.
На этом то, собственно все, в ближайшее время что-нибудь поделаем для программирования STM32F4, обязательно, так что до скорого!;)

Полный проект из примера статьи –

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

В качестве среды разработки в статье будет использоваться Eclipse CDT. Поскольку основное внимание будет сосредоточено вокруг программного кода, то вы можете спокойно проделать все манипуляции в Code::Blocks.

Общая структура проекта для ARM микроконтроллеров описана в моей статье .

Здесь я коротко напомню, что для сборки проекта для ARM — микроконтроллеров (STM32F10x в частности) понадобится скрипт компоновщика и C-Startup файл.

Скрипт компоновщика представляет собой файл с инструкциями по размещению кода программы и данных в памяти микроконтроллера. Он может скомандовать загрузить код вашей программы в Flash -память программ или SRAM -память данных.

Для микроконтроллеров с различным объемом памяти программ и данных необходимы разные скрипты компоновки. Их можно достать у производителя микроконтроллеров - компании STMicroelectronics.
Распакуйте из архива ARM_Toolchain/Lib/stm32f10x_stdperiph_lib.zip библиотеку STM32F10x standard peripheral library.
В ней имеются примеры проектов для различных сред разработки (IAR EWB, Keil uVision, Atollic True Studio и т.д). Наиболее близким для нас является Atollic True Studio, поскольку представляет собой модификацию Eclipse.
Зайдите в каталог Project/StdPeriph_Template/TrueSTUDIO, там есть несколько подкаталогов, названия которых соответствуют названиям отладочных плат STM3210x-EVAL.

Узнайте, в какой из этих плат используется микроконтроллер той же линейки, что и ваш. Скопируйте файл stm32_flash.ld из соответствующего каталога в свой проект.

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

Стартовый код (C-Startup) для микроконтроллеров STM32 может быть написан на С или Assembler.
Хотя библиотеку STM32F10x Standard Peripheral Library (далее по тексту используется сокращение STM32F10x SPL) часто критикуют за наличие ошибок, все же для начала программирования под STM32 использование этой библиотеки предоставляет самый простой способ быстро приступить к работе.
Но всегда хочется, чтобы была какая-то альтернатива. На самом деле их множество, например, программировать на языке ассемблера 🙂 .

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

Если вы категорически настроены против STM32F10x SPL, то специально для вас имеется еще одна альтернатива - библиотека libopencm3. В ней основное количество примеров сосредоточено вокруг основной серии микроконтроллеров STM32F10x , но появление примеров для других серий (STM32F2xx/4xx) является только вопросом времени. Вы всегда можете присоединиться к проекту libopencm3 и ускорить этот процесс.

Стандарт CMSIS также является не обязательным для применения в ваших программах.
Можно обойтись и без него, потратив некоторые усилия и время для реализации HAL (Hardware Abstraction Layer) уровня на языке программирования С.

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

Или вам необходимо реализовать программное обеспечение на языке С для микроконтроллеров с ядром ARM9, для которого производители ориентируются на использование готовых операционных систем (Linux, QNX, Windows CE), поэтому библиотек для программирования на языке С в чистом виде или в сочетании с более легковесной RTOS производители могут не предоставлять.

К счастью производители микроконтроллеров на основе ядра Cortex-M3 предоставляют в распоряжение разработчиков большое количество библиотек кода. Это касается и микроконтроллеров STM32.
Продолжим рассмотрение библиотеки STM32F10x SPL. Рассматривать ее будем на примере .
Вы можете открыть этот пример или же создать свой проект «с нуля», чтобы лучше осознать весь процесс происходящего.

Для второго случая я перечислю список необходимых шагов:

  • Создать в Eclipse новый пустой проект
  • Скопировать в проект скрипт компоновки и стартовый файл
  • Создать новый или скопировать шаблонный Makefile
  • При использовании в качестве шаблона Makefile из моего примера необходимо создать внутри проекта каталоги src, inc, bin, obj , внутри каталогов bin и obj создать подкаталоги Debug и Release.
  • Скопировать необходимые исходные и заголовочные файлы из библиотек CMSIS и STM32F10x SPL.
  • Внести необходимые изменения в секции настроек пользователя шаблонного Makefile, если он используется.
  • Создать в окне Eclipse “make target ” новые цели “Debug”, “cleanDebug”, “Release”, “cleanRelease”, “Program”.
  • Запустить на выполнение цель «Debug» и проследить за ее выполнением в окне «Console».

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

Конфигурирование STM32F10x SPL с помощью макроопределений

Для конфигурирования библиотеки используются предопределенные значения макросов, которые мы сейчас и рассмотрим.
Их можно задать внутри заголовочных файлов с помощью директивы препроцессора #define или же передать значения макроопределений через ключ -D компилятора GCC.
В своем примере я использую второй способ.
В Makefile переменная DEFINE содержит макросы, необходимые для компиляции библиотеки STM32F10x SPL.
Макроопределение STM32F10X_MD задает принадлежность используемого микроконтроллера к линейке Medium-density .
Сюда входят микроконтроллеры с объемом Flash-памяти от 64 до 128кБ.
В следующей таблице перечислены названия макросов для разных серий микроконтроллеров:

Наименование серии Макрос Описание
Low density Value line STM32F10X_LD_VL с объемом Flash-памяти 16 — 32кБ
Low density STM32F10X_LD
с объемом Flash-памяти 16 — 32кБ
Medium density Value line STM32F10X_MD_VL Flash — памяти
64 — 128кБ
Medium-density STM32F10X_MD микроконтроллеры серии STM32F101xx, STM32F102xx, STM32F103xx с объемом Flash- памяти 64 — 128кБ
High density Value line STM32F10X_HD_VL микроконтроллеры серии STM32F100xx с объемом
Flash — памяти 256 - 512кБ
High density STM32F10X_HD с объемом
Flash- памяти 256 - 512кБ
XL-density STM32F10X_XL
Flash- памяти 512 - 1024кБ
Connectivity line STM32F10X_CL

Для задания тактовой частоты микроконтроллера необходимо раскомментировать в файле system_stm32f10x.c макрос с необходимым значение тактовой частоты.

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) #define SYSCLK_FREQ_24MHz 24000000 #else /* #define SYSCLK_FREQ_HSE HSE_VALUE */ /* #define SYSCLK_FREQ_24MHz 24000000 */ /* #define SYSCLK_FREQ_36MHz 36000000 */ /* #define SYSCLK_FREQ_48MHz 48000000 */ /* #define SYSCLK_FREQ_56MHz 56000000 */ #define SYSCLK_FREQ_72MHz 72000000 #endif

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)

/* #define SYSCLK_FREQ_HSE HSE_VALUE */

#define SYSCLK_FREQ_24MHz 24000000

#else

/* #define SYSCLK_FREQ_HSE HSE_VALUE */

/* #define SYSCLK_FREQ_24MHz 24000000 */

/* #define SYSCLK_FREQ_36MHz 36000000 */

/* #define SYSCLK_FREQ_48MHz 48000000 */

/* #define SYSCLK_FREQ_56MHz 56000000 */

#define SYSCLK_FREQ_72MHz 72000000

#endif

Предполагается использование кварцевого резонатора с частотой 8МГц для всех основных
серий микроконтроллеров, кроме Connectivity line, для которой необходимо установить кварцевый резонатор на 25МГц.
Если вы используете кварцевые резонаторы с другими значениями частоты, то необходимо изменить значение макроса HSE_VALUE в заголовочном файле stm32f10x.h и адаптировать соответствующим образом все зависимые функции.
Назначение макроса USE_STDPERIPH_DRIVER нетрудно догадаться - использовать библиотеку STM32F10x standard peripheral library.
USE_FULL_ASSERT – использовать макрос ASSERT для отладки программы.

Использование макроса assert_param в библиотеке

Все функции библиотеки STM32F10x SPL используют для проверки своих аргументов макрос assert_param.
Этот макрос выполняет проверку выражения с участием проверяемого аргумента функции на равенство нулю. Если значение выражения равно нулю, то вызывается функция-обработчик ошибки аргумента assert_failed, в противном случае (выражение не равно нулю) проверка аргумента проходит успешно.
В своей программе вам необходимо реализовать функцию assert_failed.
В ней выводится сообщение об ошибке, название файла и номер строки кода, вызвавшей ошибку.
Макрос debug_printf может осуществлять вывод через USART c помощью стандартной библиотеки new_lib или, например, библиотеки от мистера Чена .

#define debug_printf xprintf /* printf */ #ifdef USE_FULL_ASSERT void assert_failed(uint8_t* file, uint32_t line) { debug_printf("Wrong parameters value: file %s on line %d\r\n", file, (int)line); while (1) { } }/* assert_failed */ #endif/*USE_FULL_ASSERT*/

#define debug_printf xprintf /* printf */

#ifdef USE_FULL_ASSERT

void assert_failed (uint8_t * file , uint32_t line )

debug_printf ("Wrong parameters value: file %s on line %d\r\n" , file , (int ) line ) ;

while (1 )

} /* assert_failed */

#endif/*USE_FULL_ASSERT*/

Реализованная в вашем коде функция assert_failed используется только когда объявлен макрос USE_FULL_ASSERT. В противном случае весь отладочный код исключается из исходника. Этот функционал реализован в заголовочном файле настроек библиотеки драйверов stm32f10x_conf.h.

#ifdef USE_FULL_ASSERT #define assert_param(expr) ((expr) ? (void)0: assert_failed((uint8_t *)__FILE__, __LINE__)) void assert_failed(uint8_t* file, uint32_t line); #else #define assert_param(expr) ((void)0) #endif /* USE_FULL_ASSERT */

#ifdef USE_FULL_ASSERT

#define assert_param(expr) ((expr) ? (void)0: assert_failed((uint8_t *)__FILE__, __LINE__))

void assert_failed (uint8_t * file , uint32_t line ) ;

#else

#define assert_param(expr) ((void)0)

#endif /* USE_FULL_ASSERT */

Тут объяснять особо нечего. Лучше рассмотрим пример использования assert_param.

void set_param(uint8_t * param, uint8_t value) { assert_param(param != NULL); *param = value; }/*set_param*/

void set_param (uint8_t * param , uint8_t value )

assert_param (param != NULL ) ;

* param = value ;

} /*set_param*/

Функция устанавливает значение параметра через указатель, передаваемый в качестве аргумента. Если макрос USE_FULL_ASSERT не объявлен, то можно считать, что строчки
assert_param(param != NULL) в коде просто нет, иначе в этом определении происходит проверка параметра.
Если указатель не определен, то значение param != NULL будет ложно и будет запущена функция assert_failed , которая выведет через USART название файла и номер строки с ошибкой, после чего зациклится, тем самым предотвратив присвоение значения по неопределенному адресу в памяти.
Вы совсем не обязаны использовать макрос assert_param в своем коде, но в коде библиотеки
STM32F10x SPL он используется везде.
Функцию set_param можно реализовать с проверкой ошибок аргумента без применения assert_param.

#define ERROR (-1) #define OK (0) int set_param(uint8_t * param, uint8_t value) { int r = ERROR; if (param == NULL) return r; *param = value; r = OK; return r; }/*set_param*/

#define ERROR (-1)

#define OK (0)

int set_param (uint8_t * param , uint8_t value )

int r = ERROR ;

if (param == NULL )

return r ;

* param = value ;

r = OK ;

return r ;

} /*set_param*/

C-Startup файл в библиотеке STM32F10x SPL

В стартовом коде выполняется первичная инициализация микроконтроллера, настраивается стек, выполняется обнуление секции BSS, происходит вызов основной функции main().
Прямого отношения к библиотеке STM32F10x SPL стартовый код не имеет. Однако в этом загрузочном коде перед вызовом основной функции main() программы вызывается функция инициализации микроконтроллера SystemInit(), что входит в состав CMSIS.
Его можно без труда отыскать в библиотеке CMSIS.
Зайдите в каталог Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/TrueSTUDIO и скопируйте нужный файл. Осталось лишь выяснить к какой линейке принадлежит используемый в вашем проекте микроконтроллер.
Для этого просмотрите следующую таблицу:

Наименование серии Название файла Описание
Low density Value line startup_stm32f10x_ld_vl.s микроконтроллеры серии STM32F100xx с объемом
Flash- памяти 16 — 32кБ
Low density startup_stm32f10x_ld.s микроконтроллеры серии STM32F101xx, STM32F102xx, STM32F103xx
с объемом Flash- памяти 16 — 32кБ
Medium density Value line startup_stm32f10x_md_vl.s микроконтроллеры серии STM32F100xx
Medium-density startup_stm32f10x_md.s микроконтроллеры серии STM32F101xx, STM32F102xx, STM32F103xx
с объемом Flash- памяти 64 — 128кБ
High density Value line startup_stm32f10x_hd_vl.s микроконтроллеры серии STM32F100xx
High density startup_stm32f10x_hd.s микроконтроллеры серии STM32F101xx, STM32F103xx
с объемом Flash- памяти 256 - 512кБ
XL-density startup_stm32f10x_xl.s микроконтроллеры серии STM32F101xx, STM32F103xx
с объемом Flash- памяти 512 - 1024кБ
Connectivity line startup_stm32f10x_cl.s микроконтроллеры серии STM32F105xx и STM32F107xx

В стартап-файле прописаны названия обработчиков векторов прерываний и исключений, однако реализован только обработчик вектора сброса, внутри которого и производится вся начальная инициализация перед вызовом функции main().
Реализация всех остальных обработчиков исключений возложена на программиста приложения. Если в вашей программе не используется ни один обработчик, то и нет нужды их прописывать. В случае возникновения исключения будет использован обработчик по-умолчанию - зацикливание кода программы.

Состав библиотеки CMSIS

Как было уже написано ранее в этой публикации библиотека CMSIS предоставляет доступ к периферийным модулям микроконтроллера с помощью элементов структур языка C.
Реализация этой библиотеки делится на две части. Первая часть обеспечивает доступ к периферии ядра Cortex-M3 , а вторая - к периферии конкретной модели микроконтроллера.
Поскольку стандарт CMSIS единый для всех микроконтроллеров с ядром Cortex-M3, то реализация первой части будет одинакова у всех производителей, а вот вторая часть у каждого производителя будет своей.
В состав CMSIS входят несколько заголовочных и исходных файлов. К первой части относятся файлы:

  • core_cm3.h
  • core_cm3.c

Вторая часть CMSIS включает в себя С-Startup файл, а также файлы:

  • stm32f10x.h
  • system_stm32f10x.h
  • system_stm32f10x.c

Заголовочный файл stm32f10x.h содержит макроопределения для доступа к периферийным модулям микроконтроллеров stm32f10x.
В файлах system_stm32f10x.h и system_stm32f10x.c реализована начальная инициализация микроконтроллера.

Состав и конфигурация библиотеки STM32F10x SPL

Библиотека состоит из одноименных с периферийными модулями исходных и заголовочных файлов с префиксом stm32f10x_ .
Например, реализация взаимодействия с модулем USART содержится в файлах stm32f10x_usart.h и stm32f10x_usart.c .
Существуют соглашения об именах элементов библиотеки и определенные правила кодирования, которые описаны в документации.
Библиотека содержит реализацию драйверов периферийных модулей микроконтроллера.
В названиях элементов библиотеки используются такие акронимы для модулей периферии:

Акроним Периферийный модуль
ADC аналогово-цифровой преобразователь
BKP регистры резервного копирования
CAN интерфейс CAN
CEC контроллер потребления
CRC модуль расчета контрольной суммы
DAC цифро-аналоговый преобразователь
DBGMCU отладка микроконтроллера
DMA контроллер прямого доступа к памяти
EXTI контроллер внешних прерываний
FSMC контроллер внешней памяти
FLASH Flash-память программ
GPIO порты ввода/вывода общего назначения
I2C интерфейс I2C
I2S интерфейс I2S (Sound)
IWDG независимый сторожевой таймер
NVIC контроллер вложенных прерываний
PWR контроллер питания
RCC контроллер сброса и тактирования
RTC контроллер реального времени (часы)
SDIO интерфейс SDIO
SPI интерфейс SPI
SysTick системный таймер
TIM базовый таймер или таймер с расширенными возможностями
USART универсальный последовательный синхронно-асинхронный
приемо-передатчик
WWDG оконный сторожевой таймер

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

#include "stm32f10x_gpio.h" //#include "stm32f10x_i2c.h" //#include "stm32f10x_iwdg.h" //#include "stm32f10x_pwr.h" #include "stm32f10x_rcc.h"

#include "stm32f10x_gpio.h"

//#include "stm32f10x_i2c.h"

//#include "stm32f10x_iwdg.h"

//#include "stm32f10x_pwr.h"

#include "stm32f10x_rcc.h"

Для включения нужного модуля необходимо раскомментировать директиву #include с соответствующим заголовочным файлам.
Заголовочный файл stm32f10x_conf.h включен в stm32f10x.h, поэтому для использования функций библиотеки STM32F10x SPL достаточно подключить в своем исходнике только один заголовочный файл stm32f10x.h

// в файле stm32f10x.h #ifdef USE_STDPERIPH_DRIVER #include "stm32f10x_conf.h" #endif

Повторюсь, что в проекте также должны быть определены макросы USE_STDPERIPH_DRIVER, USE_FULL_ASSERT и макрос, задающий серию используемого микроконтроллера (например STM32F10X_MD для линейки Medium density).
Если вы используете стандартное значение частоты кварцевого резонатора и контроллер будет работать на максимальной тактовой частоте 72МГц, то ничего больше изменять не придется.
В Makefile необходимо добавить список компилируемых файлов библиотеки.
Например:

SRC += stm32f10x_rcc.c SRC += stm32f10x_gpio.c

SRC += stm32f10x_rcc . c

SRC += stm32f10x_gpio . c

Использование библиотеки STM32F10x SPL. Механизмы работы

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

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_PPPx, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_PPPx, ENABLE);

RCC_AHBPeriphClockCmd (RCC_AHBPeriph_PPPx , ENABLE ) ;

RCC_APB2PeriphClockCmd (RCC_APB2Periph_PPPx , ENABLE ) ;

RCC_APB1PeriphClockCmd (RCC_APB1Periph_PPPx , ENABLE ) ;

Тут PPP обозначает название актонима модуля (например ADC или USART) , а x – номер периферийного модуля.
Прежде всего необходимо узнать к какой шине подключен используемый вами модуль.
Всего у микроконтроллеров с архитектурой ядра Cortex-M3 имеется в наличии три шины:
шина инструкций, шина данных и системная шина. Шина инструкций соединяет ядро с Flash — памятью программ. Шины данных и системная объединены в матрицу шин AHB (ARM Hi-Speed Bus), которая работает на частоте ядра. Однако частота шины AHB может быть понижена путем установки делителей. Через шину AHB соединяются высокоскоростные устройства, например ядро и модуль ПДП.
Устройства ввода/вывода подсоединяются к шине AHB через промежуточные шины APB1 и APB2 (ARM Peripheral Bus).
Максимальная частота работы шины APB2 составляет 72МГц, частота шины APB1
ограничена значением 36МГц.
К какой из шин подключен задействованный вами периферийный модуль можно узнать из документации или посмотреть в заголовочном файле stm32f10x_rcc.h.
Откройте этот файл и выполните последовательно поиск значений RCC_AHBPeriph, RCC_APB1Periph и RCC_APB2Periph.

#define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001) #define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002) #define RCC_AHBPeriph_SRAM ((uint32_t)0x00000004) #define RCC_AHBPeriph_FLITF ((uint32_t)0x00000010) #define RCC_AHBPeriph_CRC ((uint32_t)0x00000040)

#define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001)

#define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002)

#define RCC_AHBPeriph_SRAM ((uint32_t)0x00000004)

#define RCC_AHBPeriph_FLITF ((uint32_t)0x00000010)

#define RCC_AHBPeriph_CRC ((uint32_t)0x00000040)

По названиям макросов определяем какие модули к каким шинам подключены. Также для определения принадлежности к одной из трех шин можно воспользоваться здравым смыслом. Например, модуль USART является устройством ввода/вывода, значит подключен к одной из шин APB. USART является достаточно низко-скоростным интерфейсом, поэтому наверняка он подключен к шине APB1.

#define RCC_APB1Periph_USART2 ((uint32_t)0x00020000) #define RCC_APB1Periph_USART3 ((uint32_t)0x00040000) #define RCC_APB1Periph_UART4 ((uint32_t)0x00080000) #define RCC_APB1Periph_UART5 ((uint32_t)0x00100000)

После подачи тактового сигнала на периферийный модуль можно настроить его параметры путем вызова функции инициализации:

PPP_Init(PPP, &PPP_InitStructure);

PPP_Init (PPP , & amp ; PPP_InitStructure ) ;

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

PPP_InitTypeDef PPP_InitStructure = { val1, val2, …, valN};/* инициализация структуры при объявлении*/

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

PPP_InitTypeDef PPP_InitStructure; PPP_InitStructure.member1 = val1; PPP_InitStructure.member2 = val2; PPP_InitStructure.memberN = valN;

PPP_InitTypeDef PPP_InitStructure ;

PPP_InitStructure . member1 = val1 ;

PPP_InitStructure . member2 = val2 ;

PPP_InitStructure . memberN = valN ;

Рассмотрим пример из проекта stm32f10xQuickstart:

GPIO_InitTypeDef GPIO_InitStructure; #ifdef USE_STM32H_103 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &GPIO_InitStructure);

GPIO_InitTypeDef GPIO_InitStructure ;

#ifdef USE_STM32H_103

RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC , ENABLE ) ;

GPIO_InitStructure . GPIO_Pin = GPIO_Pin_12 ;

GPIO_InitStructure . GPIO_Speed = GPIO_Speed_50MHz ;

GPIO_InitStructure . GPIO_Mode = GPIO_Mode_Out_PP ;

GPIO_Init (GPIOC , & amp ; GPIO_InitStructure ) ;

Элементам структуры GPIO_InitStructure присваивается значение номера вывода, режим и скорость работы порта.
Вызовом функции GPIO_Init производится инициализация линии 12 порта GPIOC.
Первый аргумент функции GPIO_Init представляет собой указатель на область памяти периферийного устройства GPIOC, преобразованный в указатель на структуру GPIO_TypeDef.

// stm32f10x.h #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) #define PERIPH_BASE ((uint32_t)0x40000000) typedef struct { __IO uint32_t CRL; __IO uint32_t CRH; __IO uint32_t IDR; __IO uint32_t ODR; __IO uint32_t BSRR; __IO uint32_t BRR; __IO uint32_t LCKR; } GPIO_TypeDef;

// stm32f10x.h

#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)

#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)

#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)

#define PERIPH_BASE ((uint32_t)0x40000000)

typedef struct

IO uint32_t CRL ;

IO uint32_t CRH ;

IO uint32_t IDR ;

IO uint32_t ODR ;

IO uint32_t BSRR ;

IO uint32_t BRR ;

IO uint32_t LCKR ;

} GPIO_TypeDef ;

Структура GPIO_InitStructure имеет тип GPIO_InitTypeDef, описана в заголовочном файле
stm32f10x_gpio.h:

//stm32f10x_gpio.h typedef struct { uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; }GPIO_InitTypeDef; typedef enum { GPIO_Speed_10MHz = 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz }GPIOSpeed_TypeDef; typedef enum { GPIO_Mode_AIN = 0x0, GPIO_Mode_IN_FLOATING = 0x04, GPIO_Mode_IPD = 0x28, GPIO_Mode_IPU = 0x48, GPIO_Mode_Out_OD = 0x14, GPIO_Mode_Out_PP = 0x10, GPIO_Mode_AF_OD = 0x1C, GPIO_Mode_AF_PP = 0x18 }GPIOMode_TypeDef;

//stm32f10x_gpio.h

typedef struct

uint16_t GPIO_Pin ;

GPIOSpeed_TypeDef GPIO_Speed ;

GPIOMode_TypeDef GPIO_Mode ;

} GPIO_InitTypeDef ;

typedef enum

GPIO_Speed_10MHz = 1 ,

GPIO_Speed_2MHz ,

GPIO_Speed _ 50MHz

} GPIOSpeed_TypeDef ;

typedef enum

{ GPIO_Mode_AIN = 0x0 ,

GPIO_Mode_IN_FLOATING = 0x04 ,

GPIO_Mode_IPD = 0x28 ,

GPIO_Mode_IPU = 0x48 ,

GPIO_Mode_Out_OD = 0x14 ,

GPIO_Mode_Out_PP = 0x10 ,

GPIO_Mode_AF_OD = 0x1C ,

GPIO_Mode_AF_PP = 0x18

} GPIOMode_TypeDef ;

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

Mode – режим работы вывода (вход/выход). Точнее этих значений несколько больше, настроенные как выходные, порты имеют ограничение максимальной частоты выводимого сигнала.

Режим Mode Описание
00 вход
01 выход с частотой до 10МГц
10 выход с частотой до 2МГц
11 выход с частотой до 50МГц

CNF – биты конфигурации вывода. Зависят от режима работы:

Согласитесь, что при такой структуре регистра конфигурации выводов устанавливать самостоятельно все биты для конфигурации будет крайне неудобно. Гораздо проще это будет сделать при помощи библиотечной функции GPIO_Init.
После того, как вы инициализируете модуль периферии его необходимо активировать с помощью функции PPP_Cmd:

PPP_Cmd(PPP, ENABLE);

PPP_Cmd (PPP , ENABLE ) ;

Для модулей GPIO этой функции не существует, после инициализации вы можете сразу пользоваться выводами GPIO. Необходимо помнить, что библиотека предоставляет только интерфейс к аппаратуре микроконтроллера. Если у аппаратного модуля нет флага активации/деактивации, то и вызов функции PPP_Cmd(PPP, ENABLE) невозможен.
Для управления состоянием вывода GPIOx в режиме выхода и считывания значения в режиме входа или выхода в библиотеке предусмотрены следующие функции:

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

void GPIO_SetBits (GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin ) ;

void GPIO_ResetBits (GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin ) ;

uint8_t GPIO_ReadOutputDataBit (GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin ) ;

uint16_t GPIO_ReadOutputData (GPIO_TypeDef * GPIOx ) ;

uint8_t GPIO_ReadInputDataBit (GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin ) ;

uint16_t GPIO_ReadInputData (GPIO_TypeDef * GPIOx ) ;

Аналогичным образом производится настройка и работа с остальными периферийными модулями. Однако существуют некоторые отличия в связи со спецификой конкретного аппаратного модуля, поэтому я настоятельно рекомендую сначала просмотреть примеры использования выбранного модуля для библиотеки STM32F10x SPL.

Обработка прерываний и исключений

В составе ядра Cortex-M3 присутствует контроллер вложенных векторизованных прерываний. Контроллер поддерживает до 240 источников, которые могут вызывать прерывания процессорного ядра. Сколько векторов из 240 возможных реализовано в конкретной модели микроконтроллера зависит от производителя. У микроконтроллеров stm32f10x этих векторов может быть до 43. Эти линии прерываний называются маскируемыми. Кроме того существует 15 векторов прерываний ядра Cortex-M3 и одно внешнее не маскируемое прерывание EXTI.
Контроллер поддерживает вложенные прерывания, когда внутри одного обработчика может возникнуть другое прерывание. В связи с этим каждый источник прерывания имеет свой приоритет. Поддерживается 16 уровней приоритетов прерываний.
Наивысшие значения приоритетов имеют векторы прерываний ядра Cortex-M3.
Три самых высоких уровня прерываний закреплены за векторами жестко и не могут быть изменены:

Номер Обработчик Приоритет Описание
1 Reset_Handler -3(наивысший) Вектор сброса
2 NMI_Handler -2 Немаскируемое прерывание
3 HardFault_Handler -1 Аварийные состояния

Всем остальным векторам прерываний могут быть назначены уровни приоритета от 0 до 15.
Высшему уровню приоритета соответствует меньшее его значение. Уровень приоритета можно назначить не только отдельному вектору, но и целой группе векторов. Такая возможность упрощает работу с большим количеством векторов прерываний.
Для установки группы приоритетов используется функция из библиотеки STM32F10x SPL.

Я указывал, что к системе подключается стандартная библиотека. На самом деле, подключается CMSIS - система обобщенного структурного представления МК, а также SPL - стандартная библиотека периферии. Рассмотрим каждую из них:

CMSIS
Представляет собой набор заголовочных файлов и небольшого набора кода для унификации и структурировании работы с ядром и периферией МК. По сути, без этих файлов невозможно нормально работать с МК. Получить библиотеку можно на странице сопровождающей документации к МК.
Эта библиотека если верить описанию создавалась для унификации интерфейсов пр работе с любым МК семейства Cortex. Однако, на деле выходит, что это справедливо только для одного производителя, т.е. перейдя на МК другой фирмы вы вынуждены изучать его периферию почти с нуля.
Хотя те файлы которые касаются процессорного ядра МК у всех производителей идентичны (хотя бы потому, что модель процессорного ядра у них одна - предоставленная в виде ip-блоков компанией ARM).
Поэтому работа с такими частями ядра как регистры, инструкции, прерывания и сопроцессорные блоки стандартна для всех.
Что касается периферии то у STM32 и STM8 (внезапно) она почти похожа, также частично это справедливо и для других МК выпущенных компанией ST. В практической части, я покажу насколько просто использовать CMSIS. Однако трудности в его использовании связаны с нежеланием людей читать документацию и разбираться в устройстве МК.

SPL
Standard Peripheral Library - стандартная библиотека периферии. Как следует из названия, назначение этой библиотеки - создание абстракции для периферии МК. Библиотека состоит из заголовочных файлов где объявлены человеко-понятные константы для конфигурирования и работы с периферией МК, а также файлы исходного кода собираемые собственно в саму библиотеку для операций с периферией.
SPL является абстракцией над CMSIS представляя пользователю общий интерфейс для всех МК не только одного производителя, но и вообще всех МК с процессорным ядром Cortex-Mxx.
Считается, что она более удобна новичкам, т.к. позволяет не думать как работает периферия, однако качество кода, универсальность подхода и скованность интерфейсов накладывают на разработчика определенные ограничения.
Также функционал библиотеки не всегда позволяет точно реализовать настройку некоторых компонентов таких как USART (универсальный синхронный-асинхронный последовательный порт) в определённых условиях. В практической части, я также опишу работу с этой частью библиотеки.