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

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

4157f6a5d81a4e92b8415df382e1117c.png

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

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


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

Однако для освоения большей части материала будет достаточно любой, даже самой простой платы на STM32. Я рекомендую именно платы Discovery, т.к. они уже содержат отладчик ST-Link, и для работы вам понадобится только кабель MiniUSB. Для начала не нужен даже источник питания, плата питается через тот же кабель.

Естественно, при использовании микроконтроллера, отличного от STM32F746G нужно будет делать поправки в проектах на другую тактовую частоту, другую распиновку и т.п., но суть остаётся той же. Рекомендую сразу скачать документацию к вашей плате с принципиальной схемой и pdf на микроконтроллер.

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

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

Ещё нам понадобится сам STM32CubeMX (скачивается бесплатно), и любая IDE для работы с проектом на С и поддержкой ST-Link. Их много, есть коммерческие, есть бесплатные, и я намеренно не буду приводить никаких названий. Каждый выбирает для себя.

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


Сначала вам нужно скачать и установить STM32CubeMX. Скачать можно бесплатно с сайта st.com. Скажу сразу, STM32CubeMX существует только в Windows-версии. Пишут, что нормально работает под wine, я лично не пробовал.

Заходим в File/New Project, выбираем нужный микроконтроллер. Для этого удобно пользоваться фильтрами в верхней части окна.

f621d044d14442f194be26bd91e51a7f.jpg

В нашем случае это STM32F746NGHx.

Далее настраиваем тактовый генератор. Во вкладке Pinout выбираем работу с внешним кварцем:

885d7efe261346a0a0190cbc76e2cbce.jpg

Во вкладке 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.

98abe91c76ab4f808cef38e67b7f130d.jpg

Теперь надо сконфигурировать GPIO, управляющий светодиодом. Это порт PI1. На вкладке Pinout находим вывод PI1, кликаем на него и устанавливаем в значение GPIO_Output.

2a9b69745d604bfb8aa56d767dc3bcd7.jpg

Для дальнейшего удобства можно присвоить пину имя. Это делать необязательно, но давайте это сделаем, чтобы код был более читаемым. Для этого на вкладке Configuration в столбце System нажимаем кнопку GPIO.

04699d1f9c1149a4a360d6246306e6ba.jpg

Попадаем в окно «Pin Configuration» и в поле User Label пишем «Led».

967f691ec99947ec90abfe633dc69608.jpg

Сейчас можно сгенерировать код (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 выбираем для этого таймера источник тактирования:
afe401cdfcc9443c984432b2a8a7827a.jpg

Источником тактирования стала внутренняя тактовая частота периферии, равная для нашего случая 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:

d19aeb4da6974a24b6265f27e1b125ca.jpg

На этом работа в 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. В качестве небольшого анонса: мы научимся генерировать вот такую красивую синусоиду:
b464b34579a14e81ac5f4dce7aebacc0.jpg

(Эта синусоида не очень красивая, на самом деле, но будет лучше).

В дальнейших планах: работа с контроллерами USB (для начала в режиме VCP, виртуального COM-порта), контроллера Ethernet, АЦП, и, возможно, затронем тему использования FreeRTOS.

Комментарии (24)

  • 26 сентября 2016 в 08:01 (комментарий был изменён)

    0

    Ваш цикл (я надеюсь!) статей очень кстати. Я вчера почти весь день убил, пытаясь собрать хоть в чём-нибудь код, сгенерированный STMCube. Первый свой проект я делал в Eclipse + GNU ARM Plugin, но собрать это в нём — без шансов. В итоге установил IAR и там собрал и даже запустил, хоть и не без проклятий и ещё часа гугления.

    В какой IDE вы разрабатываете, что пореуомендуете?

    • 26 сентября 2016 в 08:08

      –1

      Я не хотел бы обсуждать здесь IDE, чтобы не вызывать холиваров, и не пропагандировать установку нелицензионного ПО.
      Но могу сказать, что вы на верном пути.
    • 26 сентября 2016 в 08:27

      0

      Что бы собрать какой-то проект для stm32 (в том числе и сгенерированный STMCube) не требуется вообще никакая IDE. Нужен исключительно компилятор C/C++ для ARM (например gcc) и всё. Ну и драйверы ST-Link/V2 (с сайта ST) для собственно прошивки полученного бинарника в МК. Для удобного управления данным процессом обычно ещё используют какую-то современную систему сборки (CMake/GYP/scons/waf и т.п.), но это исключительно для удобства, а не обязательное требование — для первоначальной сборки достаточно просто командной строки.

      А IDE — это для удобства навигации по коду, автодополнения, рефакторинга и т.п. удобств в написание кода, а не для сборки готовых исходников.

      • 26 сентября 2016 в 08:29

        +1

        Ну, да, кроме как просто собрать скелет, я хотел бы ещё какую-то свою функциональность дописать :)
        И даже отладить.
        • 26 сентября 2016 в 08:38

          0

          Именно. Навигация пр коду, это хорошо, но проекты для микроконтроллеров редко бывают огромными. А вот интерактивная отладка очень нужна.
          • 26 сентября 2016 в 09:06

            0

            Кстати, а вот насчёт отладки есть интересный нюанс, т.к. в мире МК основные затруднения возникают скорее в режиме реального времени и соответственно плохо отлаживаемы в классических пошаговых режимах (т.е. сама то отладка без проблем реализуется, только смысла от неё нет, т.к. все тайминги всех протоколов нарушаются). И соответственно тут больше помогает осциллограф плюс например такой интересный инструмент как STMStudio (так же как и драйверы для st-link/v2 бесплатно качается с сайта ST).
            • 26 сентября 2016 в 09:12

              0

              Пошаговая отладка остаётся очень полезным инструментом, хотя насчёт таймингов вы правы. Просто отладка проекта под микроконтроллер, это немного другой уровень чёрной магии, чем в обычном программировании. Умение работать с осциллографом/логическим анализатором, разумеется, абсолютно необходимо.
        • 26 сентября 2016 в 09:05

          0

          Ну лично я бы мог порекомендовать QtCreator в роли C++ IDE. Но в целом подходит вообще любая, и Eclipse и VisualStudio и Netbeans и CLion…
          • 26 сентября 2016 в 09:14

            0

            Надо будет попробовать QtCreator, пока это самая правильная IDE, которую я видел.
            • 26 сентября 2016 в 09:25

              0

              Там кстати есть встроенная поддержка программирования для МК. Причём если для других МК потребуется настроить OpenOCD, то для st-link есть отдельная нативная поддержка, которую не надо настраивать.
          • 26 сентября 2016 в 09:16 (комментарий был изменён)

            0

            Я бы тоже мог порекомендовать Qt Creator и билд-систему qmake для десктопных С++ проектов (и Qt проектов для Android / iOS). Как его использовать для STM — ума не приложу, если я даже в Eclipse c GNU ARM плагином не смог собрать код, сгенерированный STMCube. И в EmBitz не смог (который бывший EmBlocks — embedded IDE на базе Code: Blocks).
            • 26 сентября 2016 в 09:32

              0

              Ну вообще то qmake — это достаточно убогая система на фоне современных решений. Но и её более чем достаточно для данных примитивных целей.

              А в чём собственно затруднение? Сборка под МК на базе ARM ничем не отличается от сборки обычного десктопного приложения с помощью gcc. Вся разница исключительно в нескольких дополнительных опциях компилятора (и то они в основном для экономии памяти) и одной опции компоновщика.

              Кстати, а опции самого STMCube стоят правильно?) Там есть существенные различие в настройка генерации. Причём разница не только в формате проектов целевых IDE, но и в режиме формирования каталогов исходников (добавлять библиотечные файлы или нет и т.п.).

              • 26 сентября 2016 в 10:33

                0

                Не трогал опции Cube, ничего о них не знаю.
                Главная проблема со сборкой — как-раз таки в бибилиотеках, peripheral library, HAL и всей этой ерунде.
                • 26 сентября 2016 в 10:56

                  0

                  Там вообще много разных интересных настроек по генерации исходников. Но для конфигурации дальнейшей сборки принципиальны только две:
                  1. Целевая IDE для которой генерируется проект. И хотя сам сгенерированный проект (в смысле файлы настроек IDE) мы не используем вообще, но от этой настройки зависит и создаваемая структура проекта. Лучше всего ставить SW4STM32 — будет меньше всякого мусора и будет всё нужное для gcc.
                  2. Как раз используемые библиотеки. Там есть варианты: добавить сами библиотеки, добавить в проект только нужные файлы из них, добавить ссылки на них (в смысле только #include и прописанные пути к библиотекам в настройках проекта). Соответственно для разовой сборки лучше всего ставить второй вариант, тогда просто в папке проекта будет всё нужное для сборки. Ну, а лично у меня все библиотеки (HAL и т.п.) уже заранее собраны и настроены отдельно, так что я всегда использую 3-ий вариант.
                  • 26 сентября 2016 в 10:57 (комментарий был изменён)

                    0

                    Спасибо. У меня тоже используется вариант «скопировать только нужные файлы», но это мне не слишком помогло (пока не поставил IAR, в которой можно просто открыть проект. И то, там не все нужные настройки были прописаны, но гугл помог — теперь всё собирается, работает и даже дебажится).
    • 26 сентября 2016 в 09:55

      0

      С помощью CubeMX генерируем проект для IDE SW4STM32, затем, с помощью https://github.com/baoshi/CubeMX2Makefile творим магию
      cubemximporter.py  eclipse_project_folder cubemx_project_folder
      
  • 26 сентября 2016 в 08:24

    +2

    Скажу сразу, STM32CubeMX существует только в Windows-версии. Пишут, что нормально работает под wine, я лично не пробовал.

    Он существует и в linux и даже в os x версии. Это «обычное» java-приложение.

    hint: в new project есть board selector. Там можно выбрать конкретную плату и сразу получить проинициализированную периферию именно для этой платы.

    • 26 сентября 2016 в 08:35

      0

      Спасибо, попробую. Но в данном случае надо инициалы зимовать не всю периферию, а только некоторые устройства.
    • 26 сентября 2016 в 08:49

      0

      Инициализировать, проклятая автозамена.
  • 26 сентября 2016 в 08:48

    0

    BGA монстр из серии F7 в роли мигателя светодиодами — это конечно весьма забавно. Но мне кажется что здесь в качестве примера лучше подошло бы что-нибудь из серии F0 в корпусе TSSOP20 — как-то адекватнее и по цене и по сложности и по мощности.
    • 26 сентября 2016 в 08:50

      0

      Я, кажется, написал, что подойдёт любая плата Discovery.
      • 26 сентября 2016 в 09:10

        0

        Само собой. Просто F7 — это уже несколько нестандартный продукт в мире МК, который ближе скорее к полноценным ЦПУ, т.к. позволяет запускать полноценные ОС.
  • 26 сентября 2016 в 09:53

    0

    Сам увлекся программированием для микроконтроллеров, посмотрел на суммарное количество инструментов для OSX и понял что нужно писать свою среду разработки. В качестве встроенного инструмента планирую в следующей внедрить аналогичный генератор себе. Кому интересно, может погуглить Stm32Box.
  • 26 сентября 2016 в 11:49

    0

    Как Вы вовремя! Вчера вечер потратил на выбор микроконтроллера с низким потреблением и размышления на тему «пора переходить на ARM». Буду должен.

© Habrahabr.ru