STM32F407 Урок 01. Мигаем светодиодами и не только.
Добрый день, уважаемые читатели, сегодня мы поморгаем светодиодами, добавим реакцию на кнопки и выведем сообщения в виртуальный USB COM порт с китайской платой разработчика STM32F407VET6.
Все вышеперечисленное мы будем делать с помощью конфигуратора STMCubeMX и среды разработки Atollic TrueStudio. У многих при слове CubeMX возникает стойкое отторжение, но послушайте мою точку зрения :
1) С CubeMX увеличивается на порядок легкость вхождения в мир STM32, не Arduino, конечно, но все понятней чем напрямую с регистрами периферии. Да, глюки имеют место быть, как минимум два конкретных бага попортили мне жизнь и отняли по пол дня, но в большинстве случаев виноват был я, а не "глюкавый ХовноКуб".
2) Легкость портирования, тут конечно необходимо учитывать особенности разных серий и камней, но портирование программы для чтения ключей iButton с помощью UART с F207 на F103 у меня заняло не более 10 минут. Причем большую часть времени заняла конфигурация периферии. Сколько бы у меня заняло времени с портированием на регистрах, трудно сказать, но думаю не менее нескольких часов, при отсутствии ошибок.
3) Абсолютно ничего вам не мешает переписать функции HAL на регистры или использовать и то и другое в своем коде, к чему вы, непременно, придете со временем.
4) Atolic - сейчас выкуплен STM и абсолютно бесплатен для ваших проектов, хотя ничего вам не мешает использовать другой приглянувшийся IDE.
Итак начнем, запускаем Куб, так как у нас борода не от STM - выбираем первый пункт : ACCES TO MCU SELECTOR, в поле Search вводим F407. Из шести штук, предложенных Кубом, выбираем наш кристалл с буковками VE. После небольшой паузы, откроется окно для выбора режима ножек МК. Если вы внимательно изучили прошлый обзор и схему нашей платы, то должны знать, что светодиоды D2 D3 зажигаются лог "0" на выходах PA6 PA7. Сконфигурируем их с начальным уровнем "1", без подтяжки, режим Output Push Pull и назовем соответственно LED2 LED3 :
Кнопки K0 K1 замыкаю на землю входы PE4 PE3, а кнопка K_UP подает лог "1" на PA0. Конфигурируем PE4 PE3 как входы с подтяжкой к Vcc и обзываем KEY0 KEY1 соответственно. PA0 определяем как вход с подтяжкой к GND и меткой K_UP :
С GPIO покончено, обязательно выбираем режим Debug хотя бы Serial Wire, иначе рискуете следующий раз заливать прошивку вместо ST-Link переходником USB-UART. Про режим трассировки с выводом через канал SW поговорим в последующих уроках, картинка с подсказками :
Не забываем про внешние резонаторы HSE 8MHz и LSE 32768 Hz. LSE мы пока пользоваться не будем, но определим как шаблон для следующих проектов с RTC :
Теперь самое интересное - вкладка Clock Configuration, здесь Вы задаете источники тактирования кристалла, вводя циферки в поле HCLK можно полюбоваться как Куб подбирает делители для нужных частот периферии. В первый раз я тут задержался минут на 5:
Далее разворачиваем спойлер Connectivity и выбираем USB_OTG_FS :
Затем в Middleware конфигурируем Class for FS IP как Communication Device Class (Virtual Port Com) :
Вы можете, конечно, выбрать и режим DFU и HID, но пока я советую сделать именно так. Если бы у нас была фирменная борода от STM, со встроенным ST-Link, через его-же USB можно было использовать вывод отладочных сообщений в UART3, но на этой плате такой возможности я не нашел, поэтому пока делаем так. Потом будем делать через Trace Asynchronous Sw. От простого к сложному, как говорят.
Далее во вкладке Project Manager выбираем папку для нашей рабочей среды, имя файла, IDE True Studio, советую увеличить размер кучи и стэка, и жмакаем на GENERATE CODE:
При запуске Atolic выберем папку куда мы положили проект, в Project Explorer раскрываем наш проект из папки srcвыбираем main.c для редактирования. Все наши изменения делаем ТОЛЬКО между строками :
/* USER CODE BEGIN xxx */
ваш код тут
/ * USER CODE END xxx */
Иначе при следующей генерации проекта из Куба он благополучно затрет инициализацию ваших переменных или вызов конфигурационных функций и потеряете кучу времени пытаясь понять почему только все работало а теперь нет.
Сперва определим массив для пересылки отладочных сообщений в виртуальный COM, чтобы прочитать их в Терминале.
/* USER CODE BEGIN 2 */
char str_tx[21];
/* USER CODE END 2 */
Следом в бесконечном цикле введем цикличное изменение состояния светодиода LED2 и включение LED3 при нажатии кнопки KEY0. При нажатии K_UP будем посылать отладочное сообщение в виртуальный COM. Код достаточно прозрачен, может возникнуть вопрос о применении функции sprintf для текстового сообщения, в будущем мы будем выводить не только текст но и значения переменных, поэтому чтобы не городить многоэтажные конструкции используем запись в массив, который затем выплевываем в терминалку.
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_TogglePin(GPIOA, LED2_Pin);
if (!HAL_GPIO_ReadPin(GPIOE,KEY0_Pin))
HAL_GPIO_WritePin(GPIOA,LED3_Pin,GPIO_PIN_RESET);
else HAL_GPIO_WritePin(GPIOA,LED3_Pin,GPIO_PIN_SET);
if (HAL_GPIO_ReadPin(K_UP_GPIO_Port,K_UP_Pin))
{sprintf(str_tx,"KEY_UP PRESS!\r\n");
CDC_Transmit_FS((unsigned char*)str_tx,strlen(str_tx));}
HAL_Delay(300);
/* USER CODE END WHILE */
Для избавления от WARNING при компиляции добавим определение функций библиотеки USB :
/* USER CODE BEGIN Includes */
#include "usbd_cdc_if.h"
/* USER CODE END Includes */
Откопмпилируем наш код, зальем через Debugger в плату, полюбуемся на мигующий LED2 и реагирующий на кнопку K_UP светодиод LED3. При подключении провода к USB и установке дров на STMicroelectronics Virtual COM Port (брать на фирменном сайте ST) можете в настройках поставить скорость побольше :
Если повезет - можно даже увидить надпись при нажатии K_UP :
Теперь давайте разберемся, почему сообщения в порт иногда не выдаются. Все дело в том, что при сбросе контроллера, а это происходит не только при нажатии кнопки RST, но и при выходе из режима отладки и даже входе в него, компьютер теряет связь по USB с МК, чтобы связь проинициализировать, нужно кратковременно подтянуть сигнал D+ USB к земле. Сверимся со схемой - это ножка PA12 нашего МК. Напишем нашу функцию, подающую на PA12 лог "0" на время 1мс :
/* USER CODE BEGIN 4 */
void MX_VCU_Reset(void)
{ // reset USB DP (D+)
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_Delay(1);
}
/* USER CODE END 4 */
Вставим ее до инициализации перефирии МК :
/* USER CODE BEGIN SysInit */
MX_VCU_Reset();
/* USER CODE END SysInit */
И опишем ее :
/* USER CODE BEGIN PFP */
void MX_VCU_Reset(void);
/* USER CODE END PFP */
Откомпилируем, теперь работает получше, но тоже не совсем отлично, приходится отключать Connect терминала с портом, иначе при сбросе МК поможет только перезапуск терминала, но уже не надо перетыкать провод USB - уже победа. Если кто знает как победить полностью данную особенность виртуального COM порта - прошу в личку. Позже добавлю возможность оставлять ваши коментари.
В следующем уроке изучим таймеры и помигаем светодиодами с помощью ШИМ и ДМА.
Адрес для контактов : imax9@narod.ru
Если вам понравились мои работы и вы желаете поддержать сайт - сделайте дотацию.
При копировании статьи – обязательна ссылка на авторство и источник. Без разрешения автора копирование запрещено.
© Максим Ильин 2019 г.