Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Кармин Новиелло - Освоение STM32.pdf
Скачиваний:
2740
Добавлен:
23.09.2021
Размер:
47.68 Mб
Скачать

6. Управление GPIO

С появлением «инициативы STCube» компания ST решила полностью обновить уровень аппаратной абстракции (Hardware Abstraction Layer, HAL) для своих микроконтроллеров

STM32. До выпуска HAL STCube официальной библиотекой для разработки приложений

STM32 долгое время была Стандартная библиотека для работы с периферией (Standard Peripheral Library, SPL). Несмотря на то, что она до сих пор широко распространена среди разработчиков STM32, и вы сможете найти множество примеров использования данной библиотеки в Интернете, HAL STCube является отличным усовершенствованием старой SPL. Фактически, будучи первой библиотекой, разработанной ST, не все части SPL были совместимы между различными семействами STM32, а ранние версии библиотеки содержали множество ошибок. Это стало причиной появления различных альтернативных библиотек, и официальное программное обеспечение от ST многие люди по-преж- нему считают плохим.

Поэтому ST полностью переработала HAL и несмотря на то что ему все еще необходима небольшая подстройка, ST обеспечивает ему официальную поддержку в будущем. Более того, новый HAL значительно упрощает портирование кода между подсемействами STM32 (F0, F1 и др.), сокращая затраты усилий, необходимых для адаптации вашего приложения к другому микроконтроллеру (без хорошего уровня абстракции совместимость между выводами – это всего лишь маркетинговое преимущество). По этой и некоторым другим причинам представленная книга основана исключительно на STCube HAL.

Данная глава начинает наше путешествие по HAL с рассмотрения одного из самых простейших модулей: HAL_GPIO. Мы уже использовали многие функции из этого модуля в предыдущих примерах данной книги, но сейчас настало время понять все возможности, предлагаемые столь простым и часто используемым периферийным устройством. Тем не менее, прежде чем мы сможем начать описание возможностей HAL, лучше всего кратко взглянуть на то, как периферийные устройства STM32 отображаются на логические адреса и как они представлены в библиотеке HAL.

6.1. Отображение периферийных устройств

STM32 и дескрипторы HAL

Каждое периферийное устройство STM32 соединяется с ядром микроконтроллера некоторым набором шин, как показано на рисунке 11.

1 Здесь, чтобы упростить данную тему, мы рассматриваем шинную организацию одного из простейших микроконтроллеров STM32: STM32F030. STM32F4 и STM32F7, например, обладают более продвинутой системой межшинных соединений, которая выходит за рамки данной книги. Пожалуйста, всегда обращайтесь к справочному руководству по вашему микроконтроллеру.

Управление GPIO

159

Рисунок 1: Архитектура шин микроконтроллера STM32F030

Системная шина соединяет ядро Cortex-M с шинной матрицей, которая выполняет роль арбитра между ядром и контроллером DMA. И ядро, и контроллер DMA действуют как ведущие (masters).

Шина DMA соединяет ведущий интерфейс DMA продвинутой высокопроизводи-

тельной шины (Advanced High-performance Bus, AHB) с шинной матрицей, которая управляет доступом к ЦПУ и доступом контроллера DMA к SRAM, Flash-памяти и периферийным устройствам.

Шинная матрица (BusMatrix) управляет последовательностью доступа между системной шиной ядра и ведущей шиной DMA. Арбитраж производится по алгоритму циклического перебора Round Robin. Шинная матрица состоит из двух ведущих (шины ЦПУ и DMA) и четырех ведомых (slaves): интерфейс Flash-памяти,

SRAM, шина AHB1 с мостом AHB-APB (где APB – Advanced Peripheral Bus – продви-

нутая периферийная шина) и шина AHB2. Периферийные устройства шины AHB подключены к системной шине через шинную матрицу для обеспечения доступа к ядру и к контроллеру DMA.

Мост AHB-APB обеспечивает полностью синхронные соединения между шиной AHB и шиной APB, к которой подключена большая часть периферийных устройств.

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

В Главе 1 мы узнали, что периферийные устройства отображаются на определенную область 4 ГБ адресного пространства, начиная с 0x4000 0000 и продолжая до 0x5FFF FFFF.

2 Для некоторых из вас приведенное выше описание может быть неясным и слишком сложным для понимания. Не беспокойтесь и продолжайте читать эту главу дальше. Все станет понятным, как только вы дойдете до главы, посвященной DMA.

Управление GPIO

160

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

2.

Рисунок 2: Карта памяти областей периферийных устройств для микроконтроллера STM32F030

Способ организации данного пространства, а, следовательно, и способ отображения периферийных устройств зависит от конкретного микроконтроллера STM32. Например, в микроконтроллере STM32F030 шина AHB2 отображается на область, расположенную между 0x4800 0000 и 0x4800 17FF. Это означает, что данная область размером 6144 Байт. Данная область дополнительно разбита на несколько подобластей, каждая из которых соответствует определенному периферийному устройству. Следуя предыдущему примеру, периферийное устройство GPIOA (которое управляет всеми выводами, подключенными к порту PORT-A) отображается на область, расположенную между 0x4800 0000 и 0x4800 03FF, что означает, что она занимает 1 КБ отображенной периферийной памяти. То, как организовано это отображаемое в памяти пространство, зависит от конкретного периферийного устройства. Таблица 13 показывает организацию памяти периферийного устройства GPIO.

Рисунок 3: Организация памяти регистра GPIO MODER

3 И таблица 1, и рисунок 1 взяты с сайта ST из справочного руководства по STM32F030 (http://www.st.com/web/en/resource/technical/document/reference_manual/DM00091010.pdf).

Управление GPIO

161

Таблица 1: Карта памяти периферийного устройства GPIO микроконтроллера STM32F030

Периферийным устройством управляют, изменяя и считывая каждый регистр области, на которую оно отображается. Например, продолжая пример периферийного устройства GPIOA, чтобы переключить вывод PA5 в режим выходного вывода, мы должны сконфигурировать регистр MODER таким образом, чтобы биты [11:10] принимали значение 01 (что соответствует режиму выхода общего назначения), как показано на рисунке 3. Далее, чтобы на выводе появился высокий уровень напряжения, мы должны установить соответствующий бит [5] в регистре выходных данных (Output Data Register, ODR), который в соответствии с таблицей 1 отображается на ячейку памяти GPIOA + 0x14, то есть

0x4800 0000 + 0x14.

Управление GPIO

162

В следующем небольшом примере показано, как использовать указатели для доступа к периферийной памяти, на которую отображается GPIOA в микроконтроллере

STM32F030.

int main(void) {

volatile uint32_t *GPIOA_MODER = 0x0, *GPIOA_ODR = 0x0;

GPIOA_MODER

= (uint32_t*)0x48000000;

//

Адрес

регистра

GPIOA->MODER

GPIOA_ODR =

(uint32_t*)(0x48000000 +

0x14); //

Адрес

регистра

GPIOA->ODR

// Следующая функция гарантирует, что периферия включена и подключена к шине AHB1.

__HAL_RCC_GPIOA_CLK_ENABLE();

*GPIOA_MODER = *GPIOA_MODER | 0x400; // Запись в MODER[11:10] = 0x1

*GPIOA_ODR = *GPIOA_ODR | 0x20; // Запись в ODR[5] = 0x1, устанавливая PA5 высоким while(1);

}

Важно еще раз уточнить, что каждое семейство STM32 (F0, F1 и др.) и каждый представитель какого-либо семейства (STM32F030, STM32F103 и др.) предоставляют свой набор периферийных устройств, которые отображаются на определенные адреса. Более того, способ реализации периферийных устройств отличается между сериями STM32.

Одно из предназначений HAL – абстрагироваться от конкретного отображения периферии. Это делается определением нескольких дескрипторов (handlers) для каждого периферийного устройства. Дескриптор – это не что иное, как структура Си, ссылки на которую используются для указания на реальный адрес периферии. Давайте рассмотрим один из них.

В предыдущих главах мы конфигурировали вывод PA5 следующим кодом:

/* Конфигурация вывода GPIO : PA5 */

GPIO_InitStruct.Pin = GPIO_PIN_5;

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

Здесь переменная GPIOA является указателем на тип GPIO_TypeDef, определенный следующим образом:

typedef struct {

volatile uint32_t MODER; volatile uint32_t OTYPER; volatile uint32_t OSPEEDR; volatile uint32_t PUPDR; volatile uint32_t IDR; volatile uint32_t ODR; volatile uint32_t BSRR; volatile uint32_t LCKR; volatile uint32_t AFR[2]; volatile uint32_t BRR;

} GPIO_TypeDef;