Начинаем работать в STM32CubeMX. Часть 1

в 1:59, , рубрики: stm32, микроконтроллеры, прерывание, программирование микроконтроллеров, таймер

Приветствую аудиторию хабра, и хочу предложить вашему вниманию первый пост, посвященный использованию среды разработки STM32CubeMX, написанный для тех, кто хочет начать изучение STM32 «с нуля».

Начинаем работать в STM32CubeMX. Часть 1 - 1

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

1. Небольшое введение

Сначала сделаю небольшое пояснение. Для изучения данного материала вам понадобится отладочная плата с микроконтроллером STM32. Я использую плату STM32F746G Discovery, которая на сегодняшний день является одной из самых лучших, и, соответственно, дорогих плат семейства Discovery.

Начинаем работать в STM32CubeMX. Часть 1 - 2

Однако для освоения большей части материала будет достаточно любой, даже самой простой платы на STM32. Я рекомендую именно платы Discovery, т.к. они уже содержат отладчик ST-Link, и для работы вам понадобится только кабель MiniUSB. Для начала не нужен даже источник питания, плата питается через тот же кабель.
Естественно, при использовании микроконтроллера, отличного от STM32F746G нужно будет делать поправки в проектах на другую тактовую частоту, другую распиновку и т.п., но суть остаётся той же. Рекомендую сразу скачать документацию к вашей плате с принципиальной схемой и pdf на микроконтроллер.
Для дальнейшей работы будет неплохо иметь осциллограф, практически любой, однако начать можно и без него.
Опять же, предвидя вопросы про покупку платы, я покупал на aliexpress, и это обошлось гораздо дешевле, чем у отечественных продавцов.
Ещё нам понадобится сам STM32CubeMX (скачивается бесплатно), и любая IDE для работы с проектом на С и поддержкой ST-Link. Их много, есть коммерческие, есть бесплатные, и я намеренно не буду приводить никаких названий. Каждый выбирает для себя.

2. Hello World, или управление светодиодом

Сначала вам нужно скачать и установить STM32CubeMX. Скачать можно бесплатно с сайта st.com. Скажу сразу, STM32CubeMX существует только в Windows-версии. Пишут, что нормально работает под wine, я лично не пробовал.
Заходим в File/New Project, выбираем нужный микроконтроллер. Для этого удобно пользоваться фильтрами в верхней части окна.
Начинаем работать в STM32CubeMX. Часть 1 - 3
В нашем случае это STM32F746NGHx.

Далее настраиваем тактовый генератор. Во вкладке Pinout выбираем работу с внешним кварцем:
Начинаем работать в STM32CubeMX. Часть 1 - 4
Во вкладке Clock Configuration в поле HCLK (MHz) пишем 216. В ответ получаем сообщение «No solution found using the current selected sources. Do yoy want to use other sources?» Отвечаем «OK» и выбираем источник HSE в мультиплексоре PLL Source Mux. Значения PLLM, PLLN и PLLP устанавливаем, как показано на рисунке. Проверяем, что HCLK = 216MHz.
Начинаем работать в STM32CubeMX. Часть 1 - 5
Теперь надо сконфигурировать GPIO, управляющий светодиодом. Это порт PI1. На вкладке Pinout находим вывод PI1, кликаем на него и устанавливаем в значение GPIO_Output.
Начинаем работать в STM32CubeMX. Часть 1 - 6
Для дальнейшего удобства можно присвоить пину имя. Это делать необязательно, но давайте это сделаем, чтобы код был более читаемым. Для этого на вкладке Configuration в столбце System нажимаем кнопку GPIO.
Начинаем работать в STM32CubeMX. Часть 1 - 7
Попадаем в окно «Pin Configuration» и в поле User Label пишем «Led».
Начинаем работать в STM32CubeMX. Часть 1 - 8

Сейчас можно сгенерировать код (Project/Generate Code). STM32CubeMX генерирует не только исходный код, но и файлы проекта для ряда популярных IDE.
Обратим внимание, что в коде расставлены комментарии вида:

/* USER CODE BEGIN 3 */
/* USER CODE END 3 */

Свой код можно писать только в них, иначе при повторной генерации исходника ваш код будет затёрт.
Итак, находим цикл while(1) в main() и пишем в нём следующее:

HAL_GPIO_TogglePin(Led_GPIO_Port, Led_Pin); //Toggle the state of pin
HAL_Delay(500); //задержка в мс

Сейчас можно запустить проект. Подключаем плату и загружаем прошивку. Светодиод на плате должен мигать с частотой 1Гц.
Однако приведённый выше подход не идеален. Функция HAL_Delay содержит внутри пустой цикл, и наша программа не может заниматься в это время ещё чем-то полезным. Для решения проблемы есть два пути: использование прерываний и использование операционной системы реального времени. Про операционную систему я напишу в другой раз, а работу с прерываниями мы освоим сейчас.

3. Таймер и прерывания

Настроим таймер, например TIM1. Для этого во вкладке Pinout выбираем для этого таймера источник тактирования:
Начинаем работать в STM32CubeMX. Часть 1 - 9
Источником тактирования при стала внутренняя тактовая частота периферии, равная для нашего случая 108MHz. Уточнить это значение или изменить его путём деления главной тактовой частоты можно на вкладке Clock Configuration.
Теперь переходим на вкладку Configuration и настраиваем частоту срабатывания таймера. Нажимаем на кнопку TIM1 и в появившемся окне во вкладке Parameter Settings задаем значения Prescaler и Counter Period. Обратите внимание, коэффициенты деления должны быть уменьшены на 1 от нужных значений. На самом деле, частота прерываний таймера может быть найдена по формуле:

Update_event = TIM_CLK/((PSC + 1)*(ARR + 1)*(RCR + 1))

В нашем случае частота будет равна 108e6 / ((53999 + 1) * (999 + 1)) = 2Hz. При этом частота мигания светодиода составит 1Hz, как в предыдущем примере.
Теперь на вкладке контроллера прерываний (NVIC Settings) нужно разрешить прерывание TIM1 Update:
Начинаем работать в STM32CubeMX. Часть 1 - 10
На этом работа в STM32CubeMX закончена, можно сгенерировать код. В исходнике нам в первую очередь нужно запустить сам таймер, а затем вставит обработчик прерывания, который будет мигать светодиодом:

/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance==TIM1) //check if the interrupt comes from TIM1
{
HAL_GPIO_TogglePin(Led_GPIO_Port, Led_Pin); //Toggle the state of pin
}
}
/* USER CODE END 0 */

int main(void)
{
...
/* USER CODE BEGIN 2 */
//запуск таймера
HAL_TIM_Base_Start_IT(&htim1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//главный цикл пуст, в нём можно делать что угодно.
}
/* USER CODE END 3 */
}

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

4. Что дальше?

На этом я заканчиваю первую часть. Что планируется дальше?
В следующей части я планирую описать работу с встроенным ЦАП и затронуть тему DMA. В качестве небольшого анонса: мы научимся генерировать вот такую красивую синусоиду:
Начинаем работать в STM32CubeMX. Часть 1 - 11
(Эта синусоида не очень красивая, на самом деле, но будет лучше).
В дальнейших планах: работа с контроллерами USB (для начала в режиме VCP, виртуального COM-порта), контроллера Ethernet, АЦП, и, возможно, затронем тему использования FreeRTOS.

Автор: 32bit_me

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js