Долгое время мы занимались изучением возможностей написания программного кода для контроллеров STM серии F1. И вот наконец-то, когда мы их неплохо изучили, применяя к ним различные приёмы разработки программного обеспечения, мы можем перейти к гораздо более мощной линейке контроллеров серии F4, в которых, по сравнению с предыдущей проработанной линейкой имеется ряд серьёзных улучшений.
В линейке контроллеров STM32F4 установлен более серьёзный процессор Cortex M4, которой дополнен инструкциями DSP, позволяющими существенно ускорить обработку потоковых данных. Возможности DSP, входящего в состав M4, позволяют параллельно выполнять две операции сложения/вычитания с16-ти разрядными операндами или целых четыре операции сложения/вычитания для 8-ми разрядных чисел. Также в данном процессоре реализовано умножение за один цикл, причём для 16-разрядных величин возможно параллельное исполнение двух операций. Также процессор Cortex M4, установленный в контроллерах серии F4, а точнее его версия Cortex M4F, позволяет работать аппаратно с плавающей точкой, что достигается наличием дополнительных регистров для хранения величин с плавающей точкой, а также ряда специальных дополнительных инструкций для работы с такими величинами. Надеюсь, в будущем, мы поработаем с данной технологией напрямую с использованием языка ассемблера.
С контроллерами серии STM32F4 мы уже и раньше работали с использованием возможностей библиотеки HAL, причём в самом начале цикла работы с контроллерами STM мы даже использовали библиотеку CMSIS. Поэтому, можно сказать, мы не начинаем цикл уроков по работе с данной серией, а продолжаем.
И на данном уроке мы начнём изучение написания кода для контроллеров линейки STM32F4 с использованием библиотеки LL. Мы уже знаем, что это за библиотека, так как мы с ней уже работали над программированием контроллеров серии STM32F1. Напомню, что данная библиотека, равно как и библиотека HAL, может спокойно использоваться в интерфейсе проектогенератора Cube MX, и позволяет более гибко и на более низком уровне работать с контроллером и его регистрами, чем HAL.
Контроллер для наших опытов мы возьмём не самый слабый из линейки F4, а именно STM32F429ZIT6, который установлен на отладочной плате STM32F429I-DISCOVERY.
Данная плата на борту имеет много чего, кроме контроллера. Также на ней распаян цветной дисплей LCD, который подключен как по шине SPI, так и по LTDC, что впоследствии нам позволит с ним поработать с использованием обоих интерфейсов. Есть пара светодиодов, пользовательская кнопка, микросхема памяти SRAM, 3-осевой гироскоп, так что есть с чем позаниматься. А самое главное, что на борту в данной отладочной платы находится программатор-отладчик ST-Link, что позволит нам обойтись без подключения внешнего программатора, что делает работу с данной платой очень удобной. Цена данной платы также недорогая, что также немаловажно.
Выглядит данная плата вот таким образом
Подключим данную плату к USB нашего ПК, запустим Cube MX и создадим новый проект выбрав для начала соответствующий контроллер из списка
Выберем отладчик
Включим HSE и задействуем кварцевый резонатор
В Clock Configuration внесем следующие настройки
Ножки PG13 и PG14 настроим на выход, так как именно к ним подключены светодиоды, свечением которых мы будем управлять
А ножку PA0 настроим на вход, ибо к ней подведена пользовательская кнопка
Все остальные настройки данных ножек оставим по умолчанию, в том числе и PA0, так как к кнопке уже подтянут резистор
Для GPIO и RCC применим использование библиотеки LL
Придумаем имя нашему проекту и выберем среду разработки
В качестве среды разработки Cube IDE был выбран по разным причинам, в том числе из-за того, что Keil последней версии на данный момент почему-то отказывается запускать проекты, сгенерированные с помощью Cube MX последней версии.
Сгенерируем проект, откроем его в Cube IDE. Настройки шрифтов и прочие здесь подобны настройкам System Workbench и прочим средам на основе Eclipse, поэтому на них останавливаться не будем.
В файле main.c добавим несколько удобных макросов для управления светодиодами
1 2 3 4 5 |
/* USER CODE BEGIN PM */ #define LED1_ON() LL_GPIO_SetOutputPin(GPIOG, LL_GPIO_PIN_13) #define LED1_OFF() LL_GPIO_ResetOutputPin(GPIOG, LL_GPIO_PIN_13) #define LED2_ON() LL_GPIO_SetOutputPin(GPIOG, LL_GPIO_PIN_14) #define LED2_OFF() LL_GPIO_ResetOutputPin(GPIOG, LL_GPIO_PIN_14) |
Перед тем, как мы начнём управлять нашими светодиодами, давайте посмотрим, как инициализируется GPIO.
В функции MX_GPIO_Init сначала объявляется переменная типа структуры LL_GPIO_InitTypeDef, затем включается тактирование трёх портов
1 2 3 |
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOH); LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA); LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOG); |
Давайте зайдём в тело функции LL_AHB1_GRP1_EnableClock и посмотрим, как именно включается тактирование порта.
Здесь сразу же включается нужный бит в регистре RCC_AHB1ENR
1 |
SET_BIT(RCC->AHB1ENR, Periphs); |
Например, для порта GPIOA включится вот этот бит
Затем для задержки данный бит читается
1 2 3 |
/* Delay after an RCC peripheral clock enabling */ tmpreg = READ_BIT(RCC->AHB1ENR, Periphs); (void)tmpreg; |
Вернёмся в тело функции MX_GPIO_Init и увидим, что далее там устанавливается низкий уровень на ножках управления светодиодами
1 |
LL_GPIO_ResetOutputPin(GPIOG, LL_GPIO_PIN_13|LL_GPIO_PIN_14); |
Зайдём в тело данной функции и увидим там единственный макрос, с помощью которого ножки переводятся в низкий уровень посредством установки надлежащих битов в регистре BSRR, в нашем случае в регистре GPIOG_BSRR установятся следующие биты
Регистр BSRR устроен так же, как и одноимённый регистр в серии F1. Напомню, что с помощью старшей половины посредством установки определённых битов мы сбрасываем соответствующие биты соответствующего регистра ODR, а с помощью младшей половины — устанавливаем.
Далее в функции MX_GPIO_Init идёт заполнение полей структуры и вызов функции инициализации LL_GPIO_ResetOutputPin
1 2 3 4 |
GPIO_InitStruct.Pin = LL_GPIO_PIN_0; GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOA, &GPIO_InitStruct); |
Посмотрим содержимое тела данной функции, в котором сначала вычисляется позиция первой ножки в структуре, в нашем случае ножка одна — нулевая, поэтому мы получим 0
1 2 |
/* Initialize pinpos on first pin set */ pinpos = POSITION_VAL(GPIO_InitStruct->Pin); |
Далее идёт цикл, в котором перебираются все задействованные ножки с помощью анализа установленных и сброшенных битов в соответствующем поле переменной структуры и в котором, если ножка настраивается на выход или на альтернативный режим, сначала устанавливается скорость с помощью вот такой функции
1 2 |
/* Speed mode configuration */ LL_GPIO_SetPinSpeed(GPIOx, currentpin, GPIO_InitStruct->Speed); |
В теле данной функции устанавливаются соответствующие биты в поле регистра GPIOx_OSPEEDR.
Мы сюда не попадём, так как наша ножка настраивается на вход, мы попадём сюда позже для настройки ножек управления светодиодом и у в регистре GPIOG_OSPEEDR не установятся никакие биты, так как мы оставили низкую скорость по умолчанию.
Затем с помощью вызова функции LL_GPIO_SetPinOutputType настаивается тип выхода посредством установки соответствующих битов в регистре GPIOx_OTYPER. У нас также для порта PORTG ничего не установится, так как мы оставили режим push-pull.
Далее уже независимо от направления ножек порта (вход или выход)устанавливается режим работы ножек с помощью вызова функции LL_GPIO_SetPinPull, вследствие чего устанавливаются соответствующие биты регистра GPIO_PUPDR. У нас там также ничего не установится, так как мы оставили всё по умолчанию (внутренние подтягивающие резисторы отключены).
Затем идёт условие, что ножка (ножки) настраивается на альтернативный режим, в теле которого при помощи функции LL_GPIO_SetAFPin_0_7 или LL_GPIO_SetAFPin_8_15 устанавливаются соответствующие ножам биты в соответствующих им регистрах GPIOx_AFRL или GPIOx_AFRH. В данное условие мы не попадаем, так как мы не включаем альтернативный режим ни на одну ножку порта.
Вот и все, в принципе настройки GPIO. Можно было бы, конечно, ещё посмотреть настройку RCC и Systick, но пока этим заморачиваться не будем, Скорее всего, мы этим займёмся, когда будем писать код для серии F4 с применением библиотеки CMSYS.
В функции main() мы не будем устанавливать на ножках светодиодов низкий уровень, так как мы видели, что он уже устанавливался в функции инициализации портов.
Поэтому сразу в бесконечном цикле напишем вот такую мигалку
1 2 3 4 5 6 7 |
/* USER CODE BEGIN 3 */ LED2_OFF(); LED1_ON(); LL_mDelay(500); LED1_OFF(); LED2_ON(); LL_mDelay(500); |
Соберём код, прошьём контроллер и увидим, что светодиоды наши начнут попеременно мигать
Теперь давайте задействуем нашу кнопку, чтобы светодиоды мигали только при условии, когда она будет нажата.
Для этого весь наш код в бесконечном цикле обернём вот в такое условие
1 2 3 4 5 6 7 8 9 |
if (LL_GPIO_ReadInputPort(GPIOA)&GPIO_IDR_IDR_0) { LED2_OFF(); LED1_ON(); LL_mDelay(500); LED1_OFF(); LED2_ON(); LL_mDelay(500); } |
Соберём код, прошьём контроллер. Теперь светодиоды мигают только при нажатой кнопке
Итак, на данном уроке мы начали изучение программирования контроллеров линейки STM32F4 с использованием библиотеки LL. С помощью данной библиотеки нам удалось управлять состоянием ножек порта, а также следить за данным состоянием.
Всем спасибо за внимание!
Предыдущий урок Программирование МК STM32 Следующий урок
Отладочную плату можно приобрести здесь STM32F429I-DISCO
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Добавить комментарий