Помните, мы работали с операционной системой реального времени FreeRTOS? Вот эти статьи - ссылка. Там мы использовали микроконтроллеры STM32 серии STM32F10x, и вот теперь пришло время разобраться с работой FreeRTOS на контроллерах STM32F4. Собственно, приступаем к делу!
И для начала необходимо скачать архив с FreeRTOS. Текущей версией является версия 7.5.3, ее и скачиваем. Получаем стомегабайтный архив с кучей файлов, и сейчас будем разбираться, что же делать дальше.
Время традиционной вставки: поскольку компания STMicroelectronics прекратила поддержку библиотеки SPL, которая использовалась в этом курсе, я создал новый, посвященный работе уже с новыми инструментами, так что буду рад видеть вас там - STM32CubeMx. Кроме того, вот глобальная рубрика по STM32, а также статья на смежную тему из нового курса: STM32CubeMx. Быстрый старт с FreeRTOS для STM32.
Создаем в Keil'е новый проект. Я буду использовать плату STM32F4Discovery для экспериментов, поэтому выбрал при создании проекта контроллер STM32F407VG. Но принципиальной разницы тут нет. Создадим несколько папок для файлов проекта, например, вот так:
В папках CMSIS и SPL будут файлы соответствующих библиотек, в папки Source и Header я поместил все файлы, необходимые для использования FreeRTOS. Давайте смотреть, какие же это файлы. Итак, в скачанном архиве с FreeRTOS есть три папки:
Заходим в первую - Demo. Там куча папок, но нас интересует только одна, а именно - CORTEX_M4F_STM32F407ZG-SK. Берем из этой папки файл FreeRTOSConfig.h и копируем к нам в проект. На этом все, переходим дальше - а именно к папке Source. Из нее, а также из вложенной папки Include нам нужны абсолютно все файлы, а вот из папки portable лишь некоторые, заходим в эту папку:
Нам нужны две - RVDS и MemMang. В первой из них заходим в папку ARM_CM4F и забираем оба, имеющихся там файла. Из MemMang берем файл heap_2.c и его тоже копируем к нам в проект.
Вот, что мы получаем в итоге:
Кроме уже упомянутых файлов, тут есть файл 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); } /***************************************************************************************/
Тут все понятно, обычная работа с портами ввода-вывода. Настраиваем вывод PD12 на работу в режиме выхода. Далее пишем код нашей задачи:
/***************************************************************************************/ 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!
Добрый вечер!
Ещё раз большое Вам спасибо за очень хорошие статьи!
Я опять к Вам за помощью. 😉
Прочёл две статьи:
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?
Есть в планах такое, но очень со временем плохо сейчас..как только появится возможность, сразу сделаю, но не могу обещать, что совсем прям скоро..)
Ок!
Я пока попытаюсь с этим разобраться.
Может что-нибудь получится. 🙂
Жаль в FreeRTOS нет "abstract device drivers" как в ChibiOS/RT
http://www.chibios.org/dokuwiki/doku.php
Запустил uIP в связке с ENC28J60 и FreeRTOS на STM32F407IG. Девайс пингуется, WEB интерфейс из примера тоже работает. Следующая задача - научиться управлять девайсом через WEB. Хотя бы просто по-включать - по-выключать светодиоды.
Отлично! Пиши, как дальше будет продвигаться )
Ок!
Пока собираю платку для нормального теста и отладки. На проводках уже стало не удобно.
мне вот как простому обывателю весьма интерестно, зачем на такой шустренький МК ставить ОС ?
ведь там и так есть где конем разгулятся )))
растолкуйте, пАжалуйста )))
1.Проще писать и оталживать и поддерживать код в большых проэктах.
2. Проще,понятние и мощнее программа написана с исользованием RTOS:
например опрос клавыатруры,вывод на дисплей, Wi-Fi, Ethernet, карта памяти, опрос датчиков и управление исполнительными устройствами.
Собрал платку, запустил IP стек от LifeLover-а (пришлось немного переделать под STM32), помигал светодиодом... В общем, первоначальная задача выполнена. Теперь хочу сделать полноценный WEB интерфейс для управления и мониторинга портов процессора. Универсальный модуль для удалённого управления какими-нибудь устройствами или механизмами и получения информации о их состоянии.
Сделал всё как описано, но при компиляции port.c выдаёт ошибку:
Source\port.c(671): error: #20: identifier "SystemCoreClock" is undefined.
При этом SystemCoreClock в файле FreeRTOSConfig.h определён\---- #ifdef __ICCARM__
#include
extern uint32_t SystemCoreClock;
#endif
Подскажите пожалуйста.
#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
У меня такая же проблема с port c (..\FreeRTOS\Source_Files\port.c(671): error: #20: identifier "SystemCoreClock" is undefined). Пока не разобрался. Если кто в курсе, то буду благодарен за помощь
Вот выше ответ )
Прописал в файле port.c выше написанный код. Проект компилится, прошивается, светодиод загорается, и больше ничего не происходит, никакой реакции на нажатие кнопки и тому подобное... Заранее благодарю за ответ!
Немного ошибся с файлом. Надо было внести изменения в файл FreeRTOSConfig.h как написано выше. Все компилится и загружается, но светодиод по прежнему горит статично и не моргает (
Буду очень признателен, если кто-то поделится готовым рабочим проектом FreeRTOS+STM32F4DISCOVERY (мигание светодиодом)!!!! Плиз!!! 😉
Если у Вас всё компилится, то нужно создать саму задачу Task мигания светодиодом, а потом запустить шедулер. Перед функцией бесконечного цикла (for(;;)). Это делается в основном файле проекта (а вообще, кому как больше нравится).
Я сделал все так как написано в этой статье. Все компилится, но светодиод не горит и никак не реагирует. Хм... Интересно, в чем же загвоздка?
Просьба к автору выложить архив проекта. Было бы очень здорово!!! -;)
Он на другом компе ) Скорее всего все правильно работает, но состояние вывода меняется каждую миллисекунду (квант времени ОС). Можно посмотреть в отладчике меняется ли состояние вывода или поставить брейкпоинты в разные задачи (которые зажигают и гасят диод) и посмотреть попадает ли туда вообще программа. Визуально 1 мс нереально заметить )
У меня светодиод горит, но не мигает . Может быть это из-за того что мы не выставили период мигания? Как и где лучше это задать ? Заранее благодарю.
Может быть проблема в том, что мы не установили период мигания диодами? У меня проект запустился , но тоже не мигают.
Квант времени по умолчанию - 1 мс, изменить длительность можно, если не ошибаюсь, в файле FreeRTOSConfig.h
Гутен морген! Вот можно поморгать через такую функцию
void Delay(uint32_t a) //Функция задержки
{
uint32_t i;
for (i=0; iBSRRL = GPIO_BSRR_BS_12; // Установили на выводе 1
Delay(3000000);
GPIOD->BSRRH = (GPIO_BSRR_BR_12 >> 16);// Установили 0
Delay(3000000);
}
vTaskDelete(NULL);
}
Текст неправильно отформатировался
Вот
void Delay(uint32_t a)
{
uint32_t i;
for (i=0; iBSRRL = GPIO_BSRR_BS_12;
Delay(3000000);
GPIOD->BSRRH = (GPIO_BSRR_BR_12 >> 16);
Delay(3000000);
}
vTaskDelete(NULL);
}
Что за фигня с отображением комментариев? Короче, пишите e-mail, сброшу на почту
функция мигания светодиодом...
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();
в демо примере платы STM32F3 Discovery в main.c есть такие строки:
/** @addtogroup STM32F3-Discovery_Demo
* @{
*/
что это за колдовство в комментариях? объясните начинающему, пожалуйста...
Текст просто
вообще не похоже, ну да бох с ним.
спасибо за ответ, в любом случае.
Еще хотел спросить, компилятор выдает
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 тоже задействовал..
что ему не так, а?
Надо в настройках проекта, вкладка С/С++, в поле define прописать USE_STDPERIPH_DRIVER
Действительно, все работает. Спасибо!
Приветствую. Работаю в 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 )
Не помогло:
закомментировал строки в 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 );
^
А кстати Eclipse нормально реагирует на файлы С и С++ в одном проекте?
Добрый день, Aveal,
Есть интересная длительная работа по STM32F4 в Москве
Подробности в почту.
Приличные подборки статей.
Пишите
Добрый день, вот моя почта - Aveal.MicroTechnics@gmail.com
Спасибо за статью, всё запустил, для пущей наглядности сделал несколько разных "taskов" думаю как это реально с пользой применить.
Возможно кому-то пригодится еще....
Нужно в конце FreeRTOSConfig.h привязать диспетчер к прерыванию таймера.
Мой кусок конфига
..........................................................
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
#endif /* FREERTOS_CONFIG_H */
Всё сделал, всё работает на 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
Можете помочь разобраться если не трудно?)Или я что-то не так понимаю?
А vLedTask() с какими интервалами вызывается?
Добрый день. Пытаюсь запустить связку uip+freeRtos+web на камне
stm32l100 . Freertos работает, но как только подключаю остальные библиотеки устройство не работает. Хотя проект компилится в Keil без ошибок. Немог ли ты поделиться готовым рабочим примером.
Уже разобрался..))
Надо было в system_stm32f4xx.c изменить:
#define PLL_M 8 // стояло 25
Здесь 25 нужно заменить на 8 (внешний кварц 8МГц у Дисковери F4)
теперь всё чётко секунду в секунду))
спасибо)
Уже разобрался..))
Надо было в system_stm32f4xx.c изменить:
#define PLL_M 8 // стояло 25
Здесь 25 нужно заменить на 8 (внешний кварц 8МГц у Дисковери F4)
теперь всё чётко секунду в секунду))
спасибо)
=)
Здоровки.
Недавно поставил freeRTOS на STM32F407VG. Встала она без проблем. Четыре светодиодика мигают параллельно независимо друг от друга. В общем и целом - на лицо параллельность выполнения задач. Чуть позже, изучая очереди и семафоры, столкнулся с одной серьезной проблемой. При использовании API-функций в теле обработчика прерывания (например, функция разблокирования какой-либо задачи из обработчика - xTaskResumeFromISR) происходит зависание. Т.е., входя в обработчик и выполняя какую-либо API-функцию, программа больше никогда не выходит из этого обработчика и все встает. Но при попытке использовать аналоги этих функций в задачах (допустим функция vTaskResume) все работает прекрасно.
В чем кроется проблема? Кто знает, подскажите пожалуйста.
Добрый день!
Кто-нибудь подключал библиотеку USB+SDIO к RTOS? И как это должно выглядеть?
Спасибо!