STM32F4 CMSIS — настройка GPIO в режим MCO

STM32

Эта статья начинает курс по практической инициализации периферии платы разработчика STM32F401CCU6 Black Pill с использованием библиотеки CMSIS.

Прикупил я тут на Али обновленные платы разработчика STM32 – так называемая Black Pill. В приобретённой мною версии платы использован микроконтроллер STM32F401CCU6 в корпусе UQFN48. Поскольку данный микроконтроллер построен на ядре Cortex M4, то полноценной информации по его инициализации на регистрах не так много в русскоязычном интернете. Вот я и решил «заполнить» данный пробел.

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

Для программирования будем использовать DataSheet и Reference Manual, а производить инициализацию c использованием библиотеки CMSIS. Не признаю я разные HAL и SPL, а уж тем более CubeMX с его перегруженными комментариями портянками кода.

Прежде всего стоит разобраться на какой частоте происходит тактирование ядра. В этом нам поможет альтернативная функция MCO (Master Clock Output). Её основное предназначение – подавать тактовый сигнал на внешние физические устройства, используя один из выбранных источников тактирования микроконтроллера. Но мы будем использовать её в связке с осциллографом в качестве индикатора тактового сигнала.

Стоит заметить, что режимов MCO для нашего микроконтроллера бывает два (MCO1 и MCO2), но только для корпусов LQFP64, LQFP100, UFBGA100.

У нас же на платке Black Pill распаян микроконтроллер в корпусе UQFN48, поэтому будем довольствоваться одним режимом — MCO1(вывод PA8), который поддерживает вывод сигналов тактирования LSE(внешний кварц для системы RTC), HSE(внешний кварц для ядра), HSI(внутренняя RC-цепочка), PLLCLK(выход системы ФАПЧ).

Интересующий вывод GPIO мы выяснили, следует определить порядок настройки регистров GPIO для вывода PA8, для активации альтернативной функции MCO1. Открываем в Reference Manual таблицу с конфигурацией регистров GPIO для различных режимов работы.

Напишем код инициализации в соответствии с таблицей, не забыв, предварительно, включить тактирование порта A:

void vInitGPIO_MCO1(void)
{
    //enable clock for GPIOA
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
	
    //PA8 -> MCO(AF) -> PLLCLK
    GPIOA->MODER |= GPIO_MODER_MODER8_1; //AF
    GPIOA->OTYPER &= ~GPIO_OTYPER_OT_8; //PP
    GPIOA->PUPDR |= GPIO_PUPDR_PUPDR8_0; //PU
    GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8; //High speed
    ...
}

Осталось настроить регистр выбора альтернативной функции. Новичку на данном этапе будет просто запутаться, поскольку регистров два (старший и младший), а обозначены они в CMSIS как элементы массива. В самом регистре имеются битовые поля по 4 бита на каждый пин, таким образом на один регистр приходится по 8 выводов. Мы настраиваем PA8, следовательно нам необходимо нулевое битовое поле старшего регистра выбора альтернативных функций – AFRH. В Reference Manual всё расписано по-человечьи, чего не скажешь о CMSIS — там битовое поле для PA8 обозначено как AFRH0

Выясним, какой номер имеет альтернативная функция MCO. На перспективу, очень удобно пользоваться сводной таблицей по всем альтернативным функциям, которая находится в DataSheet:

Для удобства я обычно создаю define с названием номера альтернативной функции в заголовочном файле:

#define GPIO_AF_MCO    0x00UL

Прописываем номер альтернативной функции в битовом поле AFRH0:

//AF0->MCO
GPIOA->AFR[1] |= (GPIO_AF_MCO << GPIO_AFRH_AFSEL0_Pos);

Теперь выбираем источник тактирования – HSI. По умолчанию контроллер тактируется от внутреннего RC-генератора, поэтому мы выбираем именно него. Остальные источники тактирования по просту не инициализированы. За выбор источника отвечает регистр RCC_CFGR:

Назначаем источник тактирования для альтернативной функции MCO1:

RCC->CFGR &= ~RCC_CFGR_MCO1; //HSI

Для наглядности приведу окончательную функцию инициализации, которая у нас с вами получилась:

void vInitGPIO_MCO1(void)
{
    //enable clock for GPIOA
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
	
    //PA8 -> MCO(AF) -> PLLCLK
    GPIOA->MODER |= GPIO_MODER_MODER8_1; //AF
    GPIOA->OTYPER &= ~GPIO_OTYPER_OT_8; //PP
    GPIOA->PUPDR |= GPIO_PUPDR_PUPDR8_0; //PU
    GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8; //High speed
    //AF0->MCO
    GPIOA->AFR[1] |= (GPIO_AF_MCO << GPIO_AFRH_AFSEL0_Pos);
    RCC->CFGR &= ~RCC_CFGR_MCO1; //HSI
}

После прошивки микроконтроллера встаём щупом осциллографа на вывод PA8 и видим наш сигнал тактирования от источника HSI.

Частота у микроконтроллера без разгона (из коробки), как видно на осциллограмме составляет 15.946 МГц, что действительно соответствует внутреннему RC-генератору. В следующий раз мы подключимся к внешнему кварцу 25 МГц, распаянному на плате и выставим максимальную номинальную частоту тактирования для STM32F401CCU6 – 84 МГц, используя систему ФАПЧ.

Буду очень рад, если вы оставите комментарии к этой статье с интересующими вопросами и конструктивными советами по улучшению информативности по данной теме.

Добавить комментарий