STM32F4: Немного о стандартных библиотеках для новичков

Когда только начинаешь программировать микроконтроллеры или давно не занимался программированием, то разбираться в чужом коде довольно не легко. Вопросы "Что это такое?" и "Откуда это взялось?" возникают чуть ли не на каждом сочетании букв и цифр. И чем быстрее приходит понимание логики "что? зачем? и откуда?", тем легче проходит изучение чужого кода, в том числе и примеров. Правда иногда для этого приходиться не один день "попрыгать по коду" и "полистать мануалов".

У всех микроконтроллеров STM32F4xx довольно много периферии. За каждым периферийным устройством микроконтроллеров закреплена определённая, конкретная и неперемещаемая  область памяти. Каждая область памяти состоит из регистров памяти, причём эти регистры могут быть 8-разрядными, 16-разрядными, 32-разрядными или ещё как, зависит от микроконтроллера. В микроконтроллере STM32F4 эти регистры 32-разрядные и каждый регистр имеет своё назначение и свой конкретный адрес. Ничто не мешает в своих программах обращаться к ним напрямую, указывая адрес. По какому адресу размещен тот или иной регистр и к какому периферийному устройству он относиться указывается в карте памяти. Для STM32F4 такая карта памяти есть в документе DM00031020.pdf, который можно найти на сайте st.com. Документ называется

RM0090
Reference manual
STM32F405xx/07xx, STM32F415xx/17xx, STM32F42xxx and STM32F43xxx advanced ARM-based 32-bit MCUs

В разделе 2.3 Memory map на странице 64 начинается таблица с адресами областей регистров и их принадлежностью к периферийному устройству. В той же таблице есть ссылка на раздел с более подробным распределением памяти для каждой периферии.

Карта памяти микроконтроллера STM32F4

Слева в таблице указан диапазон адресов, в середине название периферии и в последнем столбце - где находиться более подробное описание распределения памяти.

STM32F4 карта памяти портов ввода вывода GPIO

Так для портов ввода-вывода общего назначения GPIO в таблице распределения памяти можно найти что для них  выделены адреса начиная с 0х4002 0000.  Порт ввода-вывода общего назначения GPIOA занимает диапазон адресов от 0х4002 000 до 0х4002 03FF. Порт GPIOB занимает диапазон адресов 0х4002 400 - 0х4002 07FF. И так далее.

STM32F4 GPIO подробное описание

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

GPIO карта памяти регистра

Здесь также находиться таблица, но уже с картой памяти для диапазона адресов GPIO. Согласно этой карте памяти первые 4 байта принадлежат регистру MODER, следующие 4 байта принадлежат регистру OTYPER и так далее. Адреса регистров считаются от начала диапазона, принадлежащему конкретному порту GPIO. То есть каждый регистр GPIO имеет конкретный адрес, который можно использовать при разработке программ для микроконтроллера.

Но использование адресов регистров для человека неудобно и чревато большим количеством ошибок. Поэтому производители микроконтроллеров создают стандартные библиотеки, которые облегчают работу с микроконтроллерами. В этих библиотеках физическим адресам ставиться в соответствие их буквенное обозначение. Для STM32F4xx эти соответствия заданы в файле stm32f4xx.h. Файл stm32f4xx.h принадлежит библиотеке CMSIS и лежит в папке Libraries\CMSIS\ST\STM32F4xx\Include\.

Посмотрим как определяется в библиотеках порт GPIOA. Аналогично определяется и всё остальное. Достаточно понять принцип. Файл stm32f4xx.h довольно большой и поэтому лучше использовать поиск или возможности, которые предоставляет ваш toolchain.
 

Определение GPIOA

Для порта GPIOA находим строку в которой упоминается GPIOA_BASE

GPIOA_BASE определяется через AHB1PERIPH_BASE

AHB1PERIPH_BASE в свою очередь определяется через PERIPH_BASE

А в свою очередь PERIPH_BASE определяется как 0х4000 0000. Если посмотреть карту рапределения памяти периферийных устройств (в разделе 2.3 Memory map на странице 64), то увидим этот адрес в самом низу таблицы. С этого адреса начинаются регистры всей периферии микроконтроллера STM32F4. То есть PERIPH_BASE - это начальный адрес всей периферии микроконтроллеров STM32F4xx вообще, и микроконтроллера STM32F407VG в частности..

AHB1PERIPH_BASE определяется как сумма (PERIPH_BASE + 0x00020000). (см.картинки обратно). Это будет адрес 0х4002 0000. В карте памяти с этого адреса начинаются порты ввода-вывода общего назначения GPIO.

GPIOA_BASE  определяется как (AHB1PERIPH_BASE + 0x0000), то есть это начальный адрес группы регистров порта GPIOA.

Ну а сам порт GPIOA  определяется как структура из регистров, размещение которых в памяти начинается с адреса GPIOA_BASE (см строку #define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE).

STM32F4 Структура регистров GPIO

Структура каждого порта GPIO определяется как тип GPIO_TypeDef.

Таким образом, стандартные библиотеки, в данном случае  файл stm32f4xx.h, просто очеловечивают машинную адресацию. Если вы увидите запись GPIOA->ODR = 1234, то это означает, что по адресу 0х40020014 будет записано число 1234.  GPIOA имеет начальный адрес 0х40020000 и регистр ODR имеет адрес 0х14 от начала диапазона, поэтому GPIOA->ODR имеет адрес 0х40020014.

Или например, вам не нравиться запись GPIOA->ODR, то можно определить #define GPIOA_ODR    ((uint32_t *) 0x40020014) и получить тот же самый результат, записав GPIOA_ODR = 1234;. Только вот насколько это целесообразно? Если действительно хочется ввести свои обозначения, то лучше просто переназначить стандартные. Как это делается, можно посмотреть в файле stm32f4_discovery.h Например, вот так там определяется один из светодиодов:

#define LED4_PIN                    GPIO_Pin_12
#define LED4_GPIO_PORT    GPIOD
#define LED4_GPIO_CLK       RCC_AHB1Periph_GPIOD  

Более детальное описание периферии портов находиться в stm32f4xx_gpio.h

 

Метки / Tags: