Оглавление

Стандартная библиотека периферии

Обзор.

Правила и соглашения.

Типы имен.

Синтаксис.

Тип переменных. Соответствуют подобной конструкции.

Периферийные регистры.

Структуры для регистров.

Объявление периферии.

Биты регистров.

Привязка битов.

Формула привязки.

Применение.

Описание DSP и CMSIS

Архитектура.

Файлы драйверов периферии.

Файлы CMSIS.

Как использовать библиотеку.

Как использовать SPL.

Инициализация и конфигурация периферии.

Примеры использования.



Что точно пригодится при работе.

Стандартная библиотека периферии

Обзор.

Своими словами.

CMSIS (Cortex Microcontroller Software Interface Standard) это стандарт по которому созданы

Более детально перечисленные блоки смотреть в главе «Архитектура»


Как в руководстве.

DSP and SPL это завершенный пакет, содержащий драйверы устройств для всех стандартных периферийных узлов STM. Эта либа является пакетом который содержит набор процедур, структур данных и макросов покрывающих тему периферии. Включают описания и примеры по каждой периферии. Позволяет менее глубоко изучать описания железа, но применять их при этом. Эта либа так же содержит CMSIS DSP Software Library, содержащая общие функции Cortex-M камней. Вся либа написана исключительно на СИ.

DSP and SPL состоит из трех слоев:

Правила и соглашения.

Типы имен.

PPP

Пусть это будет обозначать что речь идет об узле периферии, например такой как ADC или любой другой

stm32f4xx_

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

Константы используемые в одном файле там же и определены. В нескольких — определяются в хедерах. Все константы пишутся верхними буквами (дефайны).

Регистры в том же стиле. Тоже заглавные. Как правило совпадают с именами регистров в руководстве на МК.

Шаблон для именования функций следующий[периферийный модуль аббревиатура]_[название функции].

PPP_SendData

Функция работы с периферией.

PPP_Init

Инициализация периферийного устройства PPP в соответствии с указанными параметрами.

PPP_DeInit

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

PPP_StructInit

Используется для сброса значений модуля PPP.

PPP_Cmd

Включает/отключает периферию PPP.

PPP_ITConfig

Функции, используемые для настройки периферийной функции, всегда заканчиваются строкой ‘Config’, например PPP_DMAConfig, GPIO_PinRemapConfig

PPP_GetFlagStatus

Функции используемые для проверки состояния флагов регистров.

PPP_ClearFlag

Функции используемые для сброса состояния флагов регистров.

PPP_GetITStatus

Функции используемые для проверки состояния произошло ли прерывание.

PPP_ClearITPendingBit

Функции используемые для сброса бита прерывания который требуется чистить через ПО.

Синтаксис.

Тип переменных. Соответствуют подобной конструкции.

Конкретные типы переменных уже определены с фиксированным типом и размером. Эти типы определены в файле stm32f4xx.h

Например:

typedef enum {

ERROR = 0,

SUCCESS = !ERROR

}

ErrorStatus;

Периферийные регистры.

Те самые пресловутые «регистры контроллера» - основные объекты с которыми программист имеет дело большую часть времени, когда работает с CMSIS.

Доступ к регистрам обеспечивается через указатель на структуру. Под каждый модуль (типа АЦП, USART и подобный) выделяется одна структура. Все такие структуры объявлены в одном файле — stm32f4xx.h.

Структуры для регистров.

Пример как это может выглядеть:

typedef struct

{

__IO uint16_t SR; //регистр статуса

uint16_t RESERVED0; /*!< Reserved, 0x02 */

__IO uint16_t DR; //регистр данных

uint16_t RESERVED1; /*!< Reserved, 0x06 */

__IO uint16_t BRR; /*!< USART Baud rate register, Address offset: 0x08 */

uint16_t RESERVED2; /*!< Reserved, 0x0A */

__IO uint16_t CR1; /*!< USART Control register 1, Address offset: 0x0C */

uint16_t RESERVED3; /*!< Reserved, 0x0E */

__IO uint16_t CR2; /*!< USART Control register 2, Address offset: 0x10 */

uint16_t RESERVED4; /*!< Reserved, 0x12 */

__IO uint16_t CR3; /*!< USART Control register 3, Address offset: 0x14 */

uint16_t RESERVED5; /*!< Reserved, 0x16 */

__IO uint16_t GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x18 */

uint16_t RESERVED6; /*!< Reserved, 0x1A */

} USART_TypeDef;


В реальности это более развесистые «деревья» и очень хорошо что нам не пришлось их писать, а мы пришли «на готовенькое».

На этапе объявления этой структуры место в памяти под нее еще не выделено, а это значит что если мы сделаем объект типа USART_TypeDef и попробуем по-управлять юсартом, настроить передать принять данные — ничего из этого у нас не выйдет.


Реальная память МК с точки зрения периферии, разбита не на байты а на поля битов: по три, по четыре, по одному, и так в любых необходимых для модулей сочетаниях. Выше описанные структуры позволяют повторить «огибание этого рельефа» больших и малых областей битов и правильно работать с реальными регистрами которые есть по сути адреса и биты, использую удобные для человека псевдонимы.

Объявление периферии.

Ниже приведен пример декларации позволяющий понять как структура обретает жизнеспособность.


#define PERIPH_BASE ((uint32_t)0x40000000) //Задаем адрес с которого начинается вся периферия

#define APB1PERIPH_BASE PERIPH_BASE //периферия это шина APB1 и связанные с ней устройства

#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) //но периферия это еще и шина APB2

...

/* SPI1 Base Address definition*/

#define USART1_BASE (APB2PERIPH_BASE + 0x3000) //а теперь конкретный модуль — его местоположение нам известно

...

/* SPI1 Peripheral declaration */

#define USART1 ((SPI_TypeDef *) USART1_BASE) //тут происходит оживление декларированной ранее структуры. Теперь воздействие на регистры будет иметь смысл


с этим можно работать, и снова это все сделано за нас — это часть CMSIS.

Пример применение:

USART1->CR1 = 0x0001;

Биты регистров.

Все биты периферийных регистров содержатся в в stm32f4xx.h и они определены как константы (дефайны). Формат названий таких констант следующий

PPP_[register_name]_[bit_name]

Для примера:

#define SPI_CR2_RXDMAEN ((uint8_t)0x01) /*!<Rx Buffer DMA Enable */

#define SPI_CR2_TXDMAEN ((uint8_t)0x02) /*!<Tx Buffer DMA Enable */

#define SPI_CR2_SSOE ((uint8_t)0x04) /*!<SS Output Enable */

#define SPI_CR2_ERRIE ((uint8_t)0x20) /*!<Error Interrupt Enable */

#define SPI_CR2_RXNEIE ((uint8_t)0x40) /*!<RX buffer Not Empty Interrupt Enable */

#define SPI_CR2_TXEIE ((uint8_t)0x80) /*!<Tx buffer Empty Interrupt Enable */

Привязка битов.

Как же происходит привязка?

Формула привязки.

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

bit_word_offset = (byte_offset x 32) + (bit_number × 4)

bit_word_addr = bit_band_base + bit_word_offset

Применение.

Бит PLLON[24] в регистре RCC_CR

..

/*!< Peripheral base address in the alias region */

#define PERIPH_BASE ((uint32_t)0x40000000) //адрес — точка отсчета в области псевдонимов

...

/*!< Peripheral base address in the bit-band region */

#define PERIPH_BB_BASE ((uint32_t)0x42000000) //адрес - точка отсчета в области битового диапазона

...

/* ------------ RCC registers bit address in the alias region ----------- */

#define RCC_OFFSET (RCC_BASE — PERIPH_BASE) //регистры модуля RCC в области псевдонимов

...

/* --- CR Register ---*/

/* Alias word address of PLLON bit */

#define CR_OFFSET (RCC_OFFSET + 0x00) //байтов до нужного нам регистров ноль — т. е. Он в самом начале

#define PLLON_BitNumber 0x18 //номер бита

#define CR_PLLON_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (PLLON_BitNumber * 4)) //итоговый адрес до байт:бит которым можно пользоваться

Заметим, что, опять же все это сделано за нас и это очень хорошо.


Здесь показан пример как поменять значение в подготовленном CR_PLLON_BB, что приведет к изменения поведения МК.

void RCC_PLLCmd(FunctionalState NewState)

{

*(__IO uint32_t *) CR_PLLON_BB = (uint32_t)NewState;

}


Тут мы видим пример применения константы бита регистра RCC_CR_PLLON для выставления/сброса одного из регистров. RCC_CR_PLLON это число в котором только нужный(ные) бит выставлены и когда мы делаем ИЛИ в итоговом регистре в этот бит записывается единичка.

void RCC_PLLCmd(FunctionalState NewState)

{

if (NewState != DISABLE)

{ /* Enable PLL */

RCC->CR |= RCC_CR_PLLON; //ИЛИ = выставляем единицу

}

else

{ /* Disable PLL */

RCC->CR &= ~RCC_CR_PLLON; /И = сбрасываем единицу — пишем ноль

}

}

Описание DSP и CMSIS

Хорошая глава для тех кто окончательно хочет понять что есть что среди этих абстрактных или до конца не понятных акронимов SPL, SMSIS, DSP.

Архитектура.

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

Application layer

Приложение пользователя: примеры или пользовательский код.

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

BSP

Обертки для работы с оценочными платами — боковая вспомогательная ветка библиотеки, в «боевом» применении не используется.

BSP (Board Specific Package) - это пакет для конкретной платы (BSP), который реализует уровень абстракции для взаимодействия с ресурсами «человеческого» интерфейса; кнопки, светодиоды, ЖК-дисплей и COM-порты (USARTs), доступные на оценочных платах STMicroelectronics. Для управления этими различными ресурсами предоставляется общий API, который может быть легко адаптирован для поддержки любой другой платы разработки, просто адаптировав процедуру инициализации.


HAL

SPL

Standard Peripherals driver

Драйверы для узлов МК — работают через CMSIS

Стандартный драйвер периферийных устройств STM32F4xx, который предоставляет драйверы и заголовочные файлы для всех периферийных устройств. Он использует уровень CMSIS для доступа к регистрам STM32F4xx.

CMSIS

CPAL

Core Peripheral Access Layer.

Регистры ядра: адрес — название — функции доступа.

Базовый уровень периферийного доступа: содержит определения имен, определения адресов и вспомогательные функции для доступа к основным регистрам и периферийным устройствам. Он также определяет независимый от устройства интерфейс для ядер RTOS, который включает определения каналов отладки.

CMSIS DSP

DSP

Driver Software Library

Функции общего спектра.

Библиотека программного обеспечения CMSIS DSP: содержит набор общих функций обработки сигналов для использования на устройствах на базе процессора Cortex-M. Библиотека полностью написана на C и полностью совместима с CMSIS.

DPAL

Device Peripheral Access Layer.

Регистры периферии: адрес — название — функции доступа.

Уровень доступа к периферийному устройству STM32F4xx: предоставляет определения для всех определений периферийного регистра, определения битов и сопоставления памяти для STM32YXXX камней.

MCU

Файлы драйверов периферии.

Каждый периферийный узел имеет свой код в stm32f4xx_ppp.c и .h файлах, другими словами в stm32f4xx_ppp.c содержаться все функции требуемые для работы узла PPP.

Есть файл для отображения памяти, stm32f4xx.h, там вся периферия отображена. Он содержит все объявления регистров и определения битов. Это единственный файл, который необходимо включить в пользовательское приложение для взаимодействия с библиотекой.

stm32f4xx_conf.h используется для определения набора параметров интерфейса с библиотекой драйверов до запуска любого приложения.


Название файла

Описание

stm32f4xx_conf.h

Конфигурационный файл периферийных драйверов. Пользователь может включит или отключить тут модули МК.

stm32f4xx_ppp.h

Заглавный файл драйвера модуля PPP.

stm32f4xx_ppp.c

Драйвер — все функции для работы PPP.

stm32f4xx_it.h

Тут все прототипы обработчиков прерываний для PPP.

stm32f4xx_it.c

Шаблоны функций обработчиков прерываний. Пользователь может добавить дополнительные обработчики. Для того чтобы узнать какие можно использовать нужно посмотреть в startup_stm32f4xx.s

Файлы CMSIS.

Название файла

Описание

stm32f4xx.h

Файл является уникальным включаемым файлом, который программист приложения использует в исходном коде, обычно в main.c. Этот файл содержит:

  • раздел конфигурации, позволяющий выбрать:

    • Устройство, используемое в пользовательском приложении.

    • Использовать или не использовать драйверы периферийного устройства в коде приложения (т.е. код будет основан на прямом доступе к регистрам периферийного устройства, а не к API драйверов) , эта опция контролируется дефайном USE_STDPERIPH_DRIVER

    • изменить несколько параметров, специфичных для конкретного приложения, таких как частота кристалла HSE

  • структуры данных и отображение адресов для всех периферийных устройств

  • объявления периферийных регистров и определение битов

  • макросы для доступа к аппаратному обеспечению периферийных устройств

system_stm32f4xx.h

Системный заголовочный файл уровня периферийного доступа устройств CMSIS Cortex-M4F STM32F4xx.

system_stm32f4xx.c

Системный исходный файл уровня периферийного доступа устройств CMSIS Cortex-M4F STM32F4xx.

startup_stm32f4xx.s

Стартап файл..

Как использовать библиотеку.

Как использовать SPL.

#define PLL_M (HSE_VALUE / 1000000) /* Possible value 0 and 63 */

#define PLL_N 336 /* Possible value 192 and 432 */


/* SYSCLK = PLLVCO / PLL_P !!!! DO NOT EXCEED 168 MHz */

#define PLL_P 2 /* Possible value 2, 4, 6, or 8 */


/* OTGFS, SDIO and RNG Clock = PLLVCO / PLLQ */

#define PLL_Q 7 /* Possible value between 4 and 15 */


/* ex. to have SYSCLK @ 168 MHz

SYSCLK = PLLVCO / PLL_P

= ((HSE_VALUE / PLL_M) * PLL_N) / PLL_P

= ((HSE_VALUE / PLL_M) * PLL_N) / PLL_P

= ((25 MHz / 25) * 336 ) / 2 = 168 MHz

*/

Инициализация и конфигурация периферии.

Здесь описан пошаговый скрипт инициализации и настройки использования периферийных драйверов. Модуль периферии будет указан как PPP.

  1. В main.c задать структуру PPP_InitTypeDef. Например PPP_InitTypeDef PPP_InitStructure. Рабочей переменной будет PPP_InitStructure, через нее нам будет доступна иниция PPP.

  2. Заполнить PPP_InitStructure нужными значениями. Это можно сделать двумя способами:

PPP_InitStructure.member1 = val1;

PPP_InitStructure.member2 = val2;

PPP_InitStructure.memberN = valN; /* where N is the number of the structure members */

PPP_StructInit(&PPP_InitStructure);

PP_InitStructure.memberX = valX;

PPP_InitStructure.memberY = valY; /*where X and Y are the members the user wants to configure*/

  1. Проинициализировать периферию PPP вызовом PPP_Init()

PPP_Init(PPP, &PPP_InitStructure);

  1. На этом шаге периферия настроена и можно её включить вызовом PPP_Cmd(..)

PPP_Cmd(PPP, ENABLE);

Отметим:

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

RCC_AHBxPeriphClockCmd(RCC_AHBxPeriph_PPPx, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_PPPx, ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PPPx, ENABLE);

  1. PPP_DeInit(..) может быть использована для сброса всех регистров модуля PPP к значениям по умолчанию

PPP_DeInit(PPP);

  1. Для изменения настроек после конфигурирования периферии, можно еще повторно изменить настойки таким образом:

PPP_InitStucture.memberX = valX;

PPP_InitStructure.memberY = valY; /* where X and Y are the only members that user wants to modify*/

PPP_Init(PPP, &PPP_InitStructure);

Примеры использования.

В папке STM32F4xx_StdPeriph_Templates есть пример проекта под Keil и Atollic.



v5.