FreeRtos tips & API Reference 10.4.6.chm

FreeRtos community creates only paid documentation in pdf and does not free in the chm. Because I have converted the FreeRtos source files in the chm file.

Now you can download chm files. Link at the bottom of the page.

Enjoy !

Маленькие Tips and Tricks по использованию FreeRtos and STM32Fxxx.

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

1. Настройка FreeRtos

-  Для правильной работы с FreeRtos надо пошагово выполнить все рекомендации написанные в документации по FreeROS и самое главное, надо взять правильный FreeRTOSConfig.h из демо примеров для СВОЕГО МК (больше собственно взять config негде).

- В FreeRTOSConfig.h в самом конце проверяем наличие строчек:

FreeRTOS interrupt handlers

#define vPortSVCHandler SVC_Handler

#define xPortPendSVHandler PendSV_Handler

#define xPortSysTickHandler SysTick_Handler

Это обработчики прерываний FreeRTOS привязанные на прерывания контроллера. Были случаи (особенно в ранних версиях RTOS) когда они не были привязаны.

- Немного про аппаратные требования. У меня FreeRtos себя очень хорошо чувствует на STM32F при FLASH >= 64k and RAM >=16k. Если меньше RAM, то работать с FreeRtos извращение, т.к. практически сразу надо поставить в конфиге #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 8 * 1024 ) ). 

2. Проблемы с прерываниями во FreeRtos и STM32Fxxx.

    Эта проблема описана уже везде (даже на заборе), но повторюсь, т.к. на эти грабли я тоже наступил. 

1. Во FreeRTOS чем выше число приоритета, тем выше приоритет, а у STM32 наоборот. И FreeRTOS использует только 4 бита для установки приоритета. От этого все проблемы и недопонимания.

2. В файле конфига написано:

/* The highest interrupt priority that can be used by any interrupt service routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER

PRIORITY THAN THIS! (higher priorities are lower numeric values. */

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

Что означает, что самые высокие приоритеты от 0 до 4 (по классификации ARM) не могут использовать функции RTOS. Мы можем использовать только от 5 до 15. Т.е. правильно писать присвоение приоритетов в своих прогах как:

configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY

   //Important for FreeRtos. You should use 4 bit for priority

   NVIC_InitStructure.NVIC_IRQChannel = USARTx_IRQn;

   NVIC_InitStructure.NVIC_IRQChannelPriority = 

        configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1;

   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

   NVIC_Init(&NVIC_InitStructure);

и не превышать числа 15, Ну и естественно 15 это самый низший приоритет.

Также надо обязательно вызвать подсистему NVIC и указать NVIC_PriorityGroup_4, т..к FreeRtosработает только с такой priority group.

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

это как раз и есть указание что используем 4 бита. Другое значение указывать нельзя !!!!

3. CubeMx RTOS and FreeRTOS.

    Сейчас CubeMx в своем составе включает RTOS - это FreeRTOS с оберткой функций в cmsis_os.h, документации мало и нет примеров, поэтому проще использовать стилистику FreeRTOS, т.к. все работает. Также компания ST сделала значительное упрощение по работе с симафорами и мьютексами, остальное не проверял, т.к. вернулся к стилистике FreeRTOS.

    Но самое плохое что в версии CubeMx 4.5.0 неправильно генерируется FreeRTOSConfig.h (по крайней мере для контроллера STM32F072, остальные не пробовал), не был указан один из обработчиков прерываний и соответственно ОС не запустилась.

4. Создание инфраструктуры отладки для FreeRTOS.

- Перед созданием своего первого проекта необходимо создать и настроить инфраструктуру для отладки и отлова ошибок, т.к. когда перестает работать OS то всегда трудно понять что произошло.

- Я сразу создаю задачу моргания светодиодом (обычно зелёный), что бы было понятно что ОС работает, и обработчик ошибок, который буду везде использовать, например вот так:

freertos_tips.c

#include "stm32f0xx_conf.h"

#include <string.h>

#include "FreeRTOS.h"

#include "task.h"

extern void vToggleBitGreen();

extern void vToggleBitRed();

//FreeRtos process control GOOD

void TaskLedToggleGood(void *param){

 static portTickType TicPos;

 (void)param;

 TicPos = xTaskGetTickCount();

 for(;;){

   vToggleBitGreen();

   vTaskDelayUntil(&TicPos,800);

 }

}

app_tips.c

#include "app_tips.h"

#include "stm32f0xx_conf.h"

#include "stm32f0xx_nucleo.h"

#include "FreeRTOS.h"

#include "task.h"

static int16_t gl_err_num;  // write error code

#define ERR_LED_PIN      GPIO_Pin_6

#define GOOD_LED_PIN     LED2_PIN

int32_t GetSysClk()

{

   RCC_ClocksTypeDef RCC_Clocks;

   RCC_GetClocksFreq(&RCC_Clocks);

   return RCC_Clocks.HCLK_Frequency;

}

void AppTipsInit()

{

   // For test LED

   GPIO_InitTypeDef GPIO_InitStructure;

   GPIO_StructInit(&GPIO_InitStructure);

   RCC_AHBPeriphClockCmd(LED2_GPIO_CLK, ENABLE);

   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

   //LED PINS

   GPIO_InitStructure.GPIO_Pin = ERR_LED_PIN | GOOD_LED_PIN;

   GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);

}

#ifdef STM32F0XX

void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin){

   // For test LED xor on bit

   GPIO_WriteBit(GPIOx,GPIO_Pin, GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) ^ 0x01);

}

#endif

void vToggleBitRed()

{

   GPIO_ToggleBits(LED2_GPIO_PORT,GPIO_Pin_6);

}

void vToggleBitGreen()

{

   // For test LED xor on bit

   GPIO_ToggleBits(LED2_GPIO_PORT,GOOD_LED_PIN);

}

void Delay_ms(uint32_t ms)

{

   volatile uint32_t nCount;

   nCount=GetSysClk()/10000*ms;

   for (; nCount!=0; nCount--);

}

void Error_Handler(uint16_t err_num)

{

 uint16_t i;

 gl_err_num = err_num;

 while(1)

 {

   GPIO_WriteBit(LED2_GPIO_PORT,ERR_LED_PIN, 1);

   Delay_ms(500);

   GPIO_WriteBit(LED2_GPIO_PORT,ERR_LED_PIN, 0);

   Delay_ms(500);

   for( i=0; i < err_num; ++i){

       GPIO_WriteBit(LED2_GPIO_PORT,ERR_LED_PIN, 1);

       Delay_ms(200);

       GPIO_WriteBit(LED2_GPIO_PORT,ERR_LED_PIN, 0);

       Delay_ms(200);

   }

   Delay_ms(1000);

 }

}

- Далее я переопределяю обработчик configASSERT() в файле FreeRTOSconfig.h И у нас на все configASSERT() в процессе отладки будут моргать светодиодом, один длинный, четыре коротких :)

FreeRTOSconfig.h configASSERT()

/* Normal assert() semantics without relying on the provision of an assert.h

header file. */

#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); Error_Handler(4); }

#include "app_tips.h" // for right redefine configASSERT();

- Во FreeRTOSConfig.h прописываю #include на .h файл с функцией обработки ошибок, чтобы компилятор не ругался:

app_tips.h

#ifndef _TIPS_

#define _TIPS_

#ifdef STM32F0XX

 #include "stm32f0xx.h"

#else

 #include "stm32f4xx.h"

#endif

int32_t GetSysClk();

void Delay_ms(uint32_t ms);

void AppTipsInit();

void vToggleBitRed();

void vToggleBitGreen();

void Error_Handler(uint16_t err_num);

#ifdef STM32F0XX

void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

#endif

#endif

Это мы всего лишь обработали и отобразили configASSERT(), которые заложили разработчики, ну и конечно которые можем использовать и мы. 

Далее в main() создаем задачу моргания зеленым светодиодом, так называемый GOOD сигнал.

int main(void)

{

 //SystemInit(); SystemInit() is called from startup_stm32f072xb_cubemx.s

  AppTipsInit();

 while(1)

 {

       // toggle GREEN led

       xTaskCreate( TaskLedToggleGood, (char *) "LedToggleGreen", configMINIMAL_STACK_SIZE,

               NULL, mainTIME_TASK_PRIORITY, &hTaskGreenLed );

      /* Start the scheduler. */

       vTaskStartScheduler();

       Error_Handler(1);

    }

}

Мы сделали главную часть работы, теперь пришло время во FreeRTOSConfig.h включить  обработку ошибок памяти FreeRTOS:

configFREETOS.h memory hooks

#define configCHECK_FOR_STACK_OVERFLOW          2

#define configUSE_MALLOC_FAILED_HOOK            1

далее создаем обработчики ошибок памяти, я это делаю прямо в файле main.c:

memory hooks

void vApplicationMallocFailedHook( void ) {

   Error_Handler(2);

}

void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )

{

   /* This function will get called if a task overflows its stack.   If the

   parameters are corrupt then inspect pxCurrentTCB to find which was the

   offending task. */

   ( void ) pxTask;

   ( void ) pcTaskName;

   Error_Handler(3);

}

Что мы получили в сухом остатке:

1. Обработали все configASSERT(), которые поставили разработчики FreeRtos. И на каждый assert у нас будет моргать светодиод (- . . . .), а если в отладчике нажать стоп, то мы можем по callstack увидеть откуда пришел вызов.

2. Если у нас произошли проблемы с памятью, то у нас будет также моргать светодиод ошибки.

3. Получили две функции для отладки configASSERT() and Error_Handler(err_num).

4. Когда все хорошо и задачи переключаются и работают, то мы видим моргающий зеленый светодиод.

5. Мы также можем поменять обработчик Assert для SPL, правда я этого не делаю.

Комментарии можно оставить вот тут.