Микроконтроллер STM32F4 и FreeRTOS.

Помните, мы работали с операционной системой реального времени FreeRTOS? Вот эти статьи — ссылка. Там мы использовали микроконтроллеры серии STM32F10x, и вот теперь пришло время разобраться с работой FreeRTOS на контроллерах STM32F4. Собственно, приступаем к делу.

И для начала необходимо скачать архив с операционной системой FreeRTOS. Текущей версией является версия 7.5.3, ее и скачиваем =) Получаем стомегабайтный архив с кучей файлов, и сейчас будем разбираться, что же делать дальше.

Создаем В Keil’е новый проект. Я буду использовать плату STM32F4Discovery для экспериментов, поэтому выбрал при создании проекта контроллер STM32F407VG. Но принципиальной разницы тут нет 😉 Создадим несколько папок для файлов проекта, ну, например, вот так:
Создание проекта

В папках CMSIS и SPL будут файлы соответствующих библиотек, в папки Source и Header я поместил все файлы, необходимые для использования FreeRTOS. Давайте смотреть, какие же это файлы.

Итак, в скачанном архиве с FreeRTOS есть три папки:
FreeRTOS

Заходим в первую — Demo. Там куча папок, но нас интересует только одна, а именно — CORTEX_M4F_STM32F407ZG-SK. Берем из этой папки файл FreeRTOSConfig.h и копируем к нам в проект. На этом все, переходим дальше — а именно к папке Source. Из нее, а также из вложенной папки Include нам нужны абсолютно все файлы, а вот из папки portable лишь некоторые =) Заходим в эту папку:
Использование FreeRTOS

Нам нужны две — RVDS и MemMang. В первой из них заходим в папку ARM_CM4F и забираем оба, имеющихся там файла. Из MemMang берем файл heap_2.c и его тоже копируем к нам в проект.

Вот, что мы получаем в итоге:
Проект для FreeRTOS

Кроме уже упомянутых файлов, тут есть файл main.c — в него мы поместим наш собственный код. Как раз его написанием сейчас и займемся 😉 Только не забудьте добавить файлы из SPL и CMSIS в свой проект, я на этом останавливаться не буду, поскольку это уже далеко не первый наш проект для STM32F4, все есть в предыдущих статьях )

Итак, подключаем все нужные нам файлы:

/*******************************************************************/
#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"
#include "system_stm32f4xx.h"
#include "portmacro.h"
#include "FreeRTOSConfig.h"
#include "FreeRTOS.h"
#include "croutine.h"
#include "task.h"
#include "queue.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
 
 
 
/*******************************************************************/

Сразу же объявляем переменные:

/*******************************************************************/
GPIO_InitTypeDef port;
uint32_t state;
 
 
 
/*******************************************************************/

Важным моментом является то, что нам необходимо определить некоторые функции, без которых проект не соберется. Сделать это нужно обязательно, пусть даже в данном примере это будут просто функции-«заглушки»:

/*******************************************************************/
void vApplicationIdleHook( void )
{
}
 
 
 
/*******************************************************************/
void vApplicationMallocFailedHook( void )
{
    for( ;; );
}
 
 
 
/*******************************************************************/
void vApplicationStackOverflowHook( xTaskHandle pxTask, signed char *pcTaskName )
{
    ( void ) pcTaskName;
    ( void ) pxTask;
 
    for( ;; );
}
 
 
 
/*******************************************************************/
void vApplicationTickHook( void )
{
}
 
 
 
/*******************************************************************/

Давайте в этом проекте создадим задачу, которая будет вызываться через равные промежутки времени и изменять состояние светодиода. Соответственно, этот светодиод, а точнее ножку контроллера, нам нужно настроить:

/*******************************************************************/
void vFreeRTOSInitAll()
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
 
    GPIO_StructInit(&port);
    port.GPIO_Mode = GPIO_Mode_OUT;
    port.GPIO_Pin = GPIO_Pin_12;
    port.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOD, &port);
}
 
 
 
/*******************************************************************/

Тут все понятно, обычная работа с портами ввода-вывода. Настраиваем вывод D12 на работу в режиме выхода. Далее пишем код нашей задачи:

/*******************************************************************/
void vLedTask (void *pvParameters)
{
    while(1)
    {
	if (state == 0)
	{
            GPIO_SetBits(GPIOD,GPIO_Pin_12);
	    state = 1;
	}
	else
	{
	    GPIO_ResetBits(GPIOD,GPIO_Pin_12);
	    state = 0;
	}
    }
    vTaskDelete(NULL);	
}
 
 
 
/*******************************************************************/

Осталось совсем немного, а именно функция main():

/*******************************************************************/
int main()
{
    vFreeRTOSInitAll();
    xTaskCreate(vLedTask,(signed char*)"LedTask", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
    vTaskStartScheduler();
}
 
 
 
/*******************************************************************/

Тут всего лишь вызываем функцию инициализации и создаем задачу, как и при использовании FreeRTOS для STM32F10x (ссылка на этот материал в самом начале сегодняшней статьи =) )

Теперь собираем проект и прошиваем микроконтроллер =) В отладчике можно видеть, как меняется состояние светодиода. Собственно, это все, что я хотел сегодня рассказать, теперь мы можем использовать FreeRTOS и на контроллерах STM32F4!

Понравилась статья? Поделись с друзьями!

Микроконтроллер STM32F4 и FreeRTOS.: 50 комментариев
  1. Добрый вечер!
    Ещё раз большое Вам спасибо за очень хорошие статьи!
    Я опять к Вам за помощью. 😉
    Прочёл две статьи:
    http://we.easyelectronics.ru/electro-and-pc/stm32-uip-enc28j60.html
    http://we.easyelectronics.ru/MrMisha/webserver-na-stm32enc28j60uiprtos.html
    http://zeroelectronics.ru/practics/enc28j60-uip-na-stm32.html

    Вроде всё написано просто и доходчиво.
    Но при практической сборке проекта он (проект) опять-таки выдаёт кучу ошибок.
    В Ваших статьях не упущены важные моменты, поэтому по ним учиться гораздо проще и понятнее.
    Не могли бы Вы написать статью и про подключение ENC28J60 и uIP к уже созданному проекту STM32F4 + FreeRTOC?

    • Есть в планах такое, но очень со временем плохо сейчас..как только появится возможность, сразу сделаю, но не могу обещать, что совсем прям скоро..)

  2. Запустил uIP в связке с ENC28J60 и FreeRTOS на STM32F407IG. Девайс пингуется, WEB интерфейс из примера тоже работает. Следующая задача — научиться управлять девайсом через WEB. Хотя бы просто по-включать — по-выключать светодиоды.

  3. Ок!
    Пока собираю платку для нормального теста и отладки. На проводках уже стало не удобно.

  4. мне вот как простому обывателю весьма интерестно, зачем на такой шустренький МК ставить ОС ?
    ведь там и так есть где конем разгулятся )))
    растолкуйте, пАжалуйста )))

  5. 1.Проще писать и оталживать и поддерживать код в большых проэктах.
    2. Проще,понятние и мощнее программа написана с исользованием RTOS:
    например опрос клавыатруры,вывод на дисплей, Wi-Fi, Ethernet, карта памяти, опрос датчиков и управление исполнительными устройствами.

  6. Собрал платку, запустил IP стек от LifeLover-а (пришлось немного переделать под STM32), помигал светодиодом… В общем, первоначальная задача выполнена. Теперь хочу сделать полноценный WEB интерфейс для управления и мониторинга портов процессора. Универсальный модуль для удалённого управления какими-нибудь устройствами или механизмами и получения информации о их состоянии.

  7. Сделал всё как описано, но при компиляции port.c выдаёт ошибку:
    Source\port.c(671): error: #20: identifier «SystemCoreClock» is undefined.
    При этом SystemCoreClock в файле FreeRTOSConfig.h определён\—- #ifdef __ICCARM__
    #include
    extern uint32_t SystemCoreClock;
    #endif
    Подскажите пожалуйста.

  8. #define configUSE_PREEMPTION 1
    #define configUSE_IDLE_HOOK 0
    #define configUSE_TICK_HOOK 1
    //#define configCPU_CLOCK_HZ ( SystemCoreClock )
    #define configCPU_CLOCK_HZ ( ( unsigned long )168000000)
    #define configTICK_RATE_HZ ( ( portTickType ) 1000 )
    #define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 )
    //#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 130 )
    #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 )
    //#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 75 * 1024 ) )
    #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 18 * 1024 ) )
    //#define configMAX_TASK_NAME_LEN ( 10 )
    #define configMAX_TASK_NAME_LEN ( 16)
    //#define configUSE_TRACE_FACILITY 1

  9. У меня такая же проблема с port c (..\FreeRTOS\Source_Files\port.c(671): error: #20: identifier «SystemCoreClock» is undefined). Пока не разобрался. Если кто в курсе, то буду благодарен за помощь

  10. Прописал в файле port.c выше написанный код. Проект компилится, прошивается, светодиод загорается, и больше ничего не происходит, никакой реакции на нажатие кнопки и тому подобное… Заранее благодарю за ответ!

  11. Немного ошибся с файлом. Надо было внести изменения в файл FreeRTOSConfig.h как написано выше. Все компилится и загружается, но светодиод по прежнему горит статично и не моргает (

  12. Буду очень признателен, если кто-то поделится готовым рабочим проектом FreeRTOS+STM32F4DISCOVERY (мигание светодиодом)!!!! Плиз!!! 😉

  13. Если у Вас всё компилится, то нужно создать саму задачу Task мигания светодиодом, а потом запустить шедулер. Перед функцией бесконечного цикла (for(;;)). Это делается в основном файле проекта (а вообще, кому как больше нравится).

  14. Я сделал все так как написано в этой статье. Все компилится, но светодиод не горит и никак не реагирует. Хм… Интересно, в чем же загвоздка?

  15. Просьба к автору выложить архив проекта. Было бы очень здорово!!! -;)

    • Он на другом компе ) Скорее всего все правильно работает, но состояние вывода меняется каждую миллисекунду (квант времени ОС). Можно посмотреть в отладчике меняется ли состояние вывода или поставить брейкпоинты в разные задачи (которые зажигают и гасят диод) и посмотреть попадает ли туда вообще программа. Визуально 1 мс нереально заметить )

  16. У меня светодиод горит, но не мигает . Может быть это из-за того что мы не выставили период мигания? Как и где лучше это задать ? Заранее благодарю.

  17. Может быть проблема в том, что мы не установили период мигания диодами? У меня проект запустился , но тоже не мигают.

    • Квант времени по умолчанию — 1 мс, изменить длительность можно, если не ошибаюсь, в файле FreeRTOSConfig.h

  18. Что за фигня с отображением комментариев? Короче, пишите e-mail, сброшу на почту

  19. функция мигания светодиодом…
    void vTask_led0(void *pvParameters)
    {
    for (;;)
    {
    GPIO_ToggleBits(GPIOA,led0);
    vTaskDelay(200);
    }
    }

    создаём задачу мигания светодиодом…
    xTaskCreate( vTask_led0, ( signed char * ) «led0», configMINIMAL_STACK_SIZE*2, NULL, 1, ( xTaskHandle * ) NULL);

    запускаем шедулер…
    vTaskStartScheduler();

  20. в демо примере платы STM32F3 Discovery в main.c есть такие строки:
    /** @addtogroup STM32F3-Discovery_Demo
    * @{
    */
    что это за колдовство в комментариях? объясните начинающему, пожалуйста…

  21. вообще не похоже, ну да бох с ним.
    спасибо за ответ, в любом случае.
    Еще хотел спросить, компилятор выдает
    Error: L6218E: Undefined symbol assert_param (referred from stm32f30x_rcc.o).
    и много предупреждений вроде все файлы подключил вроде:
    ..\..\Libraries\STM32F30x_StdPeriph_Driver\src\stm32f30x_spi.c(1337): warning: #223-D: function «assert_param» declared implicitly
    в компиляторе с99 тоже задействовал..
    что ему не так, а?

  22. Приветствую. Работаю в Eclipse.
    Вставил в main функции-заглушки:
    void vApplicationIdleHook( void )
    void vApplicationMallocFailedHook( void )
    void vApplicationStackOverflowHook( xTaskHandle pxTask, signed char *pcTaskName )
    void vApplicationTickHook( void )

    но при сборке проекта выдаются ошибки:

    /Users/Alexey/Documents/workspace/probeFreeRTOS/Release/../libs/freeRTOS/src/heap_2.c:228: undefined reference to `vApplicationMallocFailedHook’
    ./libs/freeRTOS/src/tasks.o: In function `prvIdleTask’:
    /Users/Alexey/Documents/workspace/probeFreeRTOS/Release/../libs/freeRTOS/src/tasks.c:2196: undefined reference to `vApplicationIdleHook’
    ./libs/freeRTOS/src/tasks.o: In function `xTaskIncrementTick’:
    /Users/Alexey/Documents/workspace/probeFreeRTOS/Release/../libs/freeRTOS/src/tasks.c:1717: undefined reference to `vApplicationTickHook’
    /Users/Alexey/Documents/workspace/probeFreeRTOS/Release/../libs/freeRTOS/src/tasks.c:1730: undefined reference to `vApplicationTickHook’
    ./libs/freeRTOS/src/tasks.o: In function `vTaskSwitchContext’:
    /Users/Alexey/Documents/workspace/probeFreeRTOS/Release/../libs/freeRTOS/src/tasks.c:1871: undefined reference to `vApplicationStackOverflowHook’
    /Users/Alexey/Documents/workspace/probeFreeRTOS/Release/../libs/freeRTOS/src/tasks.c:1872: undefined reference to `vApplicationStackOverflowHook’

    Не могу понять почему функции-заглушки не видны из main при сборке проекта. Прошу дать подсказку.

    • Можно попробовать в хэдерах для файлов, которые выдают ошибки, объявить (tasks.h итд):
      extern void vApplicationIdleHook( void )
      extern void vApplicationMallocFailedHook( void )
      extern void vApplicationStackOverflowHook( xTaskHandle pxTask, signed char *pcTaskName )
      extern void vApplicationTickHook( void )

  23. Не помогло:
    закомментировал строки в tasks.c в которых определяется функция обработки установок, описанных в FreeRTOSConfig.h.
    Например, для #define configUSE_IDLE_HOOK 1 в tasks.c было:

    #if ( configUSE_IDLE_HOOK == 1 )
    {
    extern void vApplicationIdleHook( void );

    vApplicationIdleHook();
    }
    #endif /* configUSE_IDLE_HOOK */
    стало:

    #if ( configUSE_IDLE_HOOK == 1 )
    {
    extern void vApplicationIdleHook( void );
    //Моя правка строчка ниже закомментирована
    //vApplicationIdleHook();
    }
    #endif /* configUSE_IDLE_HOOK */

    Так же сделал configUSE_TICK_HOOK 1 в tasks.s и configUSE_MALLOC_FAILED_HOOK 1 в heap_2.c.

    проблема с неверной ссылкой на vApplicationStackOverflowHook не решена. При определении в task.c:

    extern void vApplicationStackOverflowHook( xTaskHandle pxTask, signed char *pcTaskName );

    выдает ошибку:

    In file included from ../src/main.cpp:6:0:
    ../libs/freeRTOS/include/task.h:68:44: error: variable or field ‘vApplicationStackOverflowHook’ declared void
    extern void vApplicationStackOverflowHook( xTaskHandle pxTask, signed char *pcTaskName );
    ^
    ../libs/freeRTOS/include/task.h:68:44: error: ‘xTaskHandle’ was not declared in this scope
    ../libs/freeRTOS/include/task.h:68:64: error: expected primary-expression before ‘signed’
    extern void vApplicationStackOverflowHook( xTaskHandle pxTask, signed char *pcTaskName );
    ^

  24. Добрый день, Aveal,
    Есть интересная длительная работа по STM32F4 в Москве
    Подробности в почту.
    Приличные подборки статей.
    Пишите

  25. Спасибо за статью, всё запустил, для пущей наглядности сделал несколько разных «taskов» думаю как это реально с пользой применить.

  26. Возможно кому-то пригодится еще….
    Нужно в конце FreeRTOSConfig.h привязать диспетчер к прерыванию таймера.
    Мой кусок конфига
    ………………………………………………….
    #define vPortSVCHandler SVC_Handler
    #define xPortPendSVHandler PendSV_Handler
    #define xPortSysTickHandler SysTick_Handler

    #endif /* FREERTOS_CONFIG_H */

  27. Всё сделал, всё работает на f4Discovery, только вопрос к Aveal — почему если:
    configCPU_CLOCK_Hz = 168000000(168 мГц тактовая), а TICK_RATE_HZ = 1000 (1мс выходит), то при выставлении допустим TaskDelay(500) вот так:

    void vLedTask (void *pvParameters)
    {
    while(1)
    {
    if (state == 0)
    {
    GPIO_SetBits(GPIOD,GPIO_Pin_12);
    state = 5;
    }
    else
    {
    GPIO_ResetBits(GPIOD,GPIO_Pin_12);
    state = 0;
    }
    vTaskDelay(500);
    }
    vTaskDelete(NULL);
    }

    то диод моргает с частотой около 3 сек, хотя должно быть раз в секунду (через 500 тиков — гаснет ( state = 0), через 500 снова загорается(state = 1)) (тики по 1 мс)
    как пересчитывать тики в реальное время — мс?)
    ещё такой же точно вопрос был у парня тут:
    http://www.cyberforum.ru/microcontrollers/thread1277104.html

    Можете помочь разобраться если не трудно?)Или я что-то не так понимаю?

  28. Добрый день. Пытаюсь запустить связку uip+freeRtos+web на камне
    stm32l100 . Freertos работает, но как только подключаю остальные библиотеки устройство не работает. Хотя проект компилится в Keil без ошибок. Немог ли ты поделиться готовым рабочим примером.

  29. Уже разобрался..))
    Надо было в system_stm32f4xx.c изменить:
    #define PLL_M 8 // стояло 25
    Здесь 25 нужно заменить на 8 (внешний кварц 8МГц у Дисковери F4)
    теперь всё чётко секунду в секунду))
    спасибо)

  30. Уже разобрался..))
    Надо было в system_stm32f4xx.c изменить:
    #define PLL_M 8 // стояло 25
    Здесь 25 нужно заменить на 8 (внешний кварц 8МГц у Дисковери F4)
    теперь всё чётко секунду в секунду))
    спасибо)

  31. Здоровки.
    Недавно поставил freeRTOS на STM32F407VG. Встала она без проблем. Четыре светодиодика мигают параллельно независимо друг от друга. В общем и целом — на лицо параллельность выполнения задач. Чуть позже, изучая очереди и семафоры, столкнулся с одной серьезной проблемой. При использовании API-функций в теле обработчика прерывания (например, функция разблокирования какой-либо задачи из обработчика — xTaskResumeFromISR) происходит зависание. Т.е., входя в обработчик и выполняя какую-либо API-функцию, программа больше никогда не выходит из этого обработчика и все встает. Но при попытке использовать аналоги этих функций в задачах (допустим функция vTaskResume) все работает прекрасно.
    В чем кроется проблема? Кто знает, подскажите пожалуйста.

  32. Добрый день!
    Кто-нибудь подключал библиотеку USB+SDIO к RTOS? И как это должно выглядеть?
    Спасибо!

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *