FreeRTOS
Customized for ATmega 169p
git clone --recurse-submodules https://covail.cs.umbc.edu/gitlab/robucci/cmpe311-2022-spring-freertos.git
In MPLAB, File->Open Project… Navigate to subdirectory Demo
and there will be a project (directory) ending in _MPLAB
In README, connection of LEDs is described.
One sudent reported the need to install the ATmega_DFP v. 2.3.126 Pack (using the [resolve] link next to it) in order to change the compiler version I was using (XC8 v. 2.32 -> 2.35).
I updated my version in the repo to 2.4 since then.
FreeRTOS™ Real-time operating system for microcontrollers
Developed in partnership with the world’s leading chip companies over an 18-year period, and now downloaded every 170 seconds, FreeRTOS is a market-leading real-time operating system (RTOS) for microcontrollers and small microprocessors. Distributed freely under the MIT open source license, FreeRTOS includes a kernel and a growing set of IoT libraries suitable for use across all industry sectors. FreeRTOS is built with an emphasis on reliability and ease of use.
https://www.freertos.org/Documentation/RTOS_book.html
Features parts of OS for discussion
The OS is configured using a customized configuration file and a small number of "port" files.
The port files contain code for specific microcontrollers and compilers portable, such as setting up the hardware timers and associated interrupt service routines for the OS
/* * Setup Timer0 compare match A to generate a tick interrupt. */ static void prvSetupTimerInterrupt( void ) { uint32_t ulCompareMatch; uint8_t ucLowByte; /* Using 8bit Timer0 to generate the tick. Correct fuses must be selected for the configCPU_CLOCK_HZ clock.*/ ulCompareMatch = configCPU_CLOCK_HZ / configTICK_RATE_HZ; /* We only have 8 bits so have to scale 1024 to get our required tick rate. */ ulCompareMatch /= portCLOCK_PRESCALER; /* Adjust for correct value. */ ulCompareMatch -= ( uint32_t ) 1; /* Setup compare match value for compare match A. Interrupts are disabled before this is called so we need not worry here. */ ucLowByte = ( uint8_t ) ( ulCompareMatch & ( uint32_t ) 0xff ); portOCRL = ucLowByte; /* Setup clock source and compare match behaviour. */ portTCCRa = portCLEAR_COUNTER_ON_MATCH; portTCCRa |= portPRESCALE_1024; /* Enable the interrupt - this is okay as interrupt are currently globally disabled. */ ucLowByte = portTIMSK; ucLowByte |= portCOMPARE_MATCH_A_INTERRUPT_ENABLE; portTIMSK = ucLowByte; }
ISR(portSCHEDULER_ISR) { vPortYieldFromTick(); __asm__ __volatile__ ( "reti" ); }
FreeRTOSConfig.h full example from https://www.freertos.org/a00110.html
#ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H /* Here is a good place to include header files that are required across your application. */ #include "something.h" #define configUSE_PREEMPTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 #define configUSE_TICKLESS_IDLE 0 #define configCPU_CLOCK_HZ 60000000 #define configSYSTICK_CLOCK_HZ 1000000 #define configTICK_RATE_HZ 250 #define configMAX_PRIORITIES 5 #define configMINIMAL_STACK_SIZE 128 #define configMAX_TASK_NAME_LEN 16 #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 #define configUSE_TASK_NOTIFICATIONS 1 #define configTASK_NOTIFICATION_ARRAY_ENTRIES 3 #define configUSE_MUTEXES 0 #define configUSE_RECURSIVE_MUTEXES 0 #define configUSE_COUNTING_SEMAPHORES 0 #define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ #define configQUEUE_REGISTRY_SIZE 10 #define configUSE_QUEUE_SETS 0 #define configUSE_TIME_SLICING 0 #define configUSE_NEWLIB_REENTRANT 0 #define configENABLE_BACKWARD_COMPATIBILITY 0 #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 #define configSTACK_DEPTH_TYPE uint16_t #define configMESSAGE_BUFFER_LENGTH_TYPE size_t /* Memory allocation related definitions. */ #define configSUPPORT_STATIC_ALLOCATION 1 #define configSUPPORT_DYNAMIC_ALLOCATION 1 #define configTOTAL_HEAP_SIZE 10240 #define configAPPLICATION_ALLOCATED_HEAP 1 #define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 1 /* Hook function related definitions. */ #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCHECK_FOR_STACK_OVERFLOW 0 #define configUSE_MALLOC_FAILED_HOOK 0 #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 /* Run time and task stats gathering related definitions. */ #define configGENERATE_RUN_TIME_STATS 0 #define configUSE_TRACE_FACILITY 0 #define configUSE_STATS_FORMATTING_FUNCTIONS 0 /* Co-routine related definitions. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES 1 /* Software timer related definitions. */ #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY 3 #define configTIMER_QUEUE_LENGTH 10 #define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE /* Interrupt nesting behaviour configuration. */ #define configKERNEL_INTERRUPT_PRIORITY [dependent of processor] #define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application] #define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application] /* Define to trap errors during development. */ #define configASSERT( ( x ) ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) /* FreeRTOS MPU specific definitions. */ #define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 #define configTOTAL_MPU_REGIONS 8 /* Default value. */ #define configTEX_S_C_B_FLASH 0x07UL /* Default value. */ #define configTEX_S_C_B_SRAM 0x07UL /* Default value. */ #define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 1 #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1 /* ARMv8-M secure side port related definitions. */ #define secureconfigMAX_SECURE_CONTEXTS 5 /* Optional functions - most linkers will remove unused functions anyway. */ #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_xResumeFromISR 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 #define INCLUDE_xTaskGetSchedulerState 1 #define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_uxTaskGetStackHighWaterMark 0 #define INCLUDE_xTaskGetIdleTaskHandle 0 #define INCLUDE_eTaskGetState 0 #define INCLUDE_xEventGroupSetBitFromISR 1 #define INCLUDE_xTimerPendFunctionCall 0 #define INCLUDE_xTaskAbortDelay 0 #define INCLUDE_xTaskGetHandle 0 #define INCLUDE_xTaskResumeFromISR 1 /* A header file that defines trace macro can be included here. */ #endif /* FREERTOS_CONFIG_H */
Provided Initial Modified Config (
/* * FreeRTOS V202112.00 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * https://www.FreeRTOS.org * https://aws.amazon.com/freertos * * 1 tab == 4 spaces! */ #ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H #include <avr/io.h> #include <avr/interrupt.h> #include <portmacro.h> #define configCALL_STACK_SIZE 20 /*----------------------------------------------------------- * Application specific definitions. * * These definitions should be adjusted for your particular hardware and * application requirements. * * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. * * See http://www.freertos.org/a00110.html *----------------------------------------------------------*/ #define configUSE_PREEMPTION 1 #define configUSE_IDLE_HOOK 1 #define configUSE_TICK_HOOK 1 #define configCPU_CLOCK_HZ ( ( unsigned long ) 8000000 ) #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) #define configMAX_PRIORITIES ( 4 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 85 ) #define configTOTAL_HEAP_SIZE ( (size_t ) ( 500 ) ) #define configMAX_TASK_NAME_LEN ( 8 ) #define configUSE_TRACE_FACILITY 0 #define configUSE_16_BIT_TICKS 1 #define configIDLE_SHOULD_YIELD 1 #define configUSE_TIME_SLICING 1 #define configUSE_TICKLESS_IDLE 1 #define portBASE_TYPE char /* Co-routine definitions. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ #define INCLUDE_vTaskPrioritySet 0 #define INCLUDE_uxTaskPriorityGet 0 #define INCLUDE_vTaskDelete 0 #define INCLUDE_vTaskCleanUpResources 0 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 /* Memory allocation related definitions. */ #define configSUPPORT_STATIC_ALLOCATION 1 //#define configSUPPORT_DYNAMIC_ALLOCATION 1 //#define configTOTAL_HEAP_SIZE 10240 //#define configAPPLICATION_ALLOCATED_HEAP 1 //#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 1 // Force Removal/Update of Old API code by removing backward compat macros #define configENABLE_BACKWARD_COMPATIBILITY 0 #define configSTACK_DEPTH_TYPE uint16_t #define portUSING_MPU_WRAPPERS 0 /* Timers and Mutexes */ //#define configUSE_TIMERS 1 //#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) //#define configTIMER_QUEUE_LENGTH 2 //#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE+20 //#define INCLUDE_xTimerPendFunctionCall 1 //#define configUSE_MUTEXES 1 #endif /* FREERTOS_CONFIG_H */
May configure static and/or dynamic memory configuration
Dynamic
#define configSUPPORT_DYNAMIC_ALLOCATION 1
Static
#define configSUPPORT_STATIC_ALLOCATION as 1
Task Control: https://www.freertos.org/a00019.html
vTaskDelay()
#define INCLUDE_vTaskDelay 1
void vTaskDelay( const TickType_t xTicksToDelay );
xTaskDelayUntil()
#define INCLUDE_xTaskDelayUntil 1
BaseType_t xTaskDelayUntil( TickType_t *pxPreviousWakeTime, const TickType_t xTimeIncrement );
//source: https://www.freertos.org/xtaskdelayuntiltask-control.html // Perform an action every 10 ticks. void vTaskFunction( void * pvParameters ) { TickType_t xLastWakeTime; const TickType_t xFrequency = 10; BaseType_t xWasDelayed; // Initialise the xLastWakeTime variable with the current time. xLastWakeTime = xTaskGetTickCount (); for( ;; ) { // Wait for the next cycle. xWasDelayed = xTaskDelayUntil( &xLastWakeTime, xFrequency ); // Perform action here. xWasDelayed value can be used to determine // whether a deadline was missed if the code here took too long. } }
vTaskDelayUntil()
#define INCLUDE_xTaskDelayUntil 1
uxTaskPriorityGet()
void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );
#define INCLUDE_vTaskPrioritySet 1
vTaskPrioritySet()
void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );
#define INCLUDE_vTaskPrioritySet 1
Suspend and Resume
#define INCLUDE_vTaskSuspend 1
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle ); vTaskSuspend( xHandle );
void vTaskResume( TaskHandle_t xTaskToResume );
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xTaskResumeFromISR 1
xTaskAbortDelay
#define INCLUDE_xTaskAbortDelay 1
https://www.freertos.org/a00021.html
task.h
Notes:
xTaskGetTickCount
vTaskList
https://www.freertos.org/a00020.html
Notes
vTaskStartScheduler
void vTaskStartScheduler( void );
void vAFunction( void ) { // Tasks can be created before or after starting the RTOS scheduler xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); // Start the real time scheduler. vTaskStartScheduler(); // Will not get here unless there is insufficient RAM. }
taskYIELD
taskYIELD() is used to request a context switch to another task. However, if there are no other tasks at a higher or equal priority to the task that calls taskYIELD() then the RTOS scheduler will simply select the task that called taskYIELD() to run again.
If configUSE_PREEMPTION is set to 1 then the RTOS scheduler will always be running the highest priority task that is able to run, so calling taskYIELD() will never result in a switch to a higher priority task.
xTaskCatchUpTicks
BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp );
Corrects the tick count value after the application code has held interrupts disabled for an extended period. This function is similar to vTaskStepTick(), however, unlike vTaskStepTick(), this function may move the tick count forward past a time at which a task should be remove from the blocked state. That means xTaskCatchUpTicks() may remove tasks from the blocked state.
https://www.freertos.org/a00111.html
Quoted from that webpage:
if( __malloc_heap_end == 0 ) __malloc_heap_end = (char *)(RAMEND - __malloc_margin);I found that
__malloc_margin
was not definedAPI
Note that there are variants to be called from ISRs
Example
SemaphoreHandle_t xSemaphore = NULL; /* A task that creates a semaphore. */ void vATask( void * pvParameters ) { /* Create the semaphore to guard a shared resource. As we are using the semaphore for mutual exclusion we create a mutex semaphore rather than a binary semaphore. */ xSemaphore = xSemaphoreCreateMutex(); }
Static:
SemaphoreHandle_t xSemaphore = NULL; StaticSemaphore_t xMutexBuffer; void vATask( void * pvParameters ) { /* Create a mutex semaphore without using any dynamic memory allocation. The mutex's data structures will be saved into the xMutexBuffer variable. */ xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer ); /* The pxMutexBuffer was not NULL, so it is expected that the handle will not be NULL. */ configASSERT( xSemaphore ); /* Rest of the task code goes here. */ }
Example usage:
/* A task that uses the semaphore. */ void vAnotherTask( void * pvParameters ) { /* ... Do other things. */ if( xSemaphore != NULL ) { /* See if we can obtain the semaphore. If the semaphore is not available wait 10 ticks to see if it becomes free. */ if( xSemaphoreTake( xSemaphore, ( TickType_t ) 10 ) == pdTRUE ) { /* We were able to obtain the semaphore and can now access the shared resource. */ /* ... */ /* We have finished accessing the shared resource. Release the semaphore. */ xSemaphoreGive( xSemaphore ); } else { /* We could not obtain the semaphore and can therefore not access the shared resource safely. */ }
https://www.freertos.org/FreeRTOS-Software-Timer-API-Functions.html
Notes
TimerHandle_t xTimerCreateStatic ( const char * const pcTimerName, const TickType_t xTimerPeriod, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction StaticTimer_t *pxTimerBuffer );
pxTimerBuffer #define NUM_TIMERS 5 /* An array to hold handles to the created timers. */ TimerHandle_t xTimers[ NUM_TIMERS ]; /* An array of StaticTimer_t structures, which are used to store the state of each created timer. */ StaticTimer_t xTimerBuffers[ NUM_TIMERS ]; /* Define a callback function that will be used by multiple timer instances. The callback function does nothing but count the number of times the associated timer expires, and stop the timer once the timer has expired 10 times. The count is saved as the ID of the timer. */ void vTimerCallback( TimerHandle_t xTimer ) { const uint32_t ulMaxExpiryCountBeforeStopping = 10; uint32_t ulCount; /* Optionally do something if the pxTimer parameter is NULL. */ configASSERT( pxTimer ); /* The number of times this timer has expired is saved as the timer's ID. Obtain the count. */ ulCount = ( uint32_t ) pvTimerGetTimerID( xTimer ); /* Increment the count, then test to see if the timer has expired ulMaxExpiryCountBeforeStopping yet. */ ulCount++; /* If the timer has expired 10 times then stop it from running. */ if( ulCount >= ulMaxExpiryCountBeforeStopping ) { /* Do not use a block time if calling a timer API function from a timer callback function, as doing so could cause a deadlock! */ xTimerStop( xTimer, 0 ); } else { /* Store the incremented count back into the timer's ID field so it can be read back again the next time this software timer expires. */ vTimerSetTimerID( xTimer, ( void * ) ulCount ); } } void main( void ) { long x; /* Create then start some timers. Starting the timers before the RTOS scheduler has been started means the timers will start running immediately that the RTOS scheduler starts. */ for( x = 0; x < NUM_TIMERS; x++ ) { xTimers[ x ] = xTimerCreateStatic ( /* Just a text name, not used by the RTOS kernel. */ "Timer", /* The timer period in ticks, must be greater than 0. */ ( 100 * x ) + 100, /* The timers will auto-reload themselves when they expire. */ pdTRUE, /* The ID is used to store a count of the number of times the timer has expired, which is initialised to 0. */ ( void * ) 0, /* Each timer calls the same callback when it expires. */ vTimerCallback, /* Pass in the address of a StaticTimer_t variable, which will hold the data associated with the timer being created. */ &( xTimerBuffers[ x ] ); ); if( xTimers[ x ] == NULL ) { /* The timer was not created. */ } else { /* Start the timer. No block time is specified, and even if one was it would be ignored because the RTOS scheduler has not yet been started. */ if( xTimerStart( xTimers[ x ], 0 ) != pdPASS ) { /* The timer could not be set into the Active state. */ } } } /* ... Create tasks here. ... */ /* Starting the RTOS scheduler will start the timers running as they have already been set into the active state. */ vTaskStartScheduler(); /* Should not reach here. */ for( ;; ); }
void prvMyTask0 ( void *pvParameters ) { ( void ) pvParameters; while(1) { vTaskDelay(500); PORTB^=1; //taskYIELD(); } } void prvMyTask1( void *pvParameters ) { ( void ) pvParameters; vTaskDelay(250); while(1) { vTaskDelay(500); PORTD^=1; //taskYIELD(); } }
In FreeRTOSConfig.h:
#define configUSE_MUTEXES 1 #define configUSE_TASK_NOTIFICATIONS 0
In main.c
#include "semphr.h" //mutex
before main
/*----------------------------------------------------------------------------*/ /* Mutex */ // SemaphoreHandle_t myMutex; // StaticSemaphore_t myMutexBuffer; // /*----------------------------------------------------------------------------*/
in main
/* Mutex */ myMutex = xSemaphoreCreateMutexStatic(&myMutexBuffer); if( myMutex != NULL ) { /* The semaphore was created successfully and can be used. */ /* In this port, to use preemptive scheduler define configUSE_PREEMPTION as 1 in portmacro.h. To use the cooperative scheduler define configUSE_PREEMPTION as 0. */ vTaskStartScheduler(); }
New Tasks at end of main.c
static void prvMyTask0( void *pvParameters ) { ( void ) pvParameters; while(1){ vTaskDelay(250); xSemaphoreGive( myMutex); vTaskDelay(250); PORTB^=1; } } static void prvMyTask1( void *pvParameters ) { ( void ) pvParameters; while(1){ xSemaphoreTake( myMutex,portMAX_DELAY); //** PORTD^=1; } }
If INCLUDE_vTaskSuspend is set to '1' then specifying the block time as portMAX_DELAY will cause the task to block indefinitely (without a timeout).
In FreeRTOSConfig.h:
/* Timers and Mutexes */ #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY (tskIDLE_PRIORITY+1) #define configTIMER_QUEUE_LENGTH 1 #define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE+20 #define INCLUDE_xTimerPendFunctionCall 0
main.c:
#include "timers.h"
Before main
/*----------------------------------------------------------------------------*/ // static StaticTask_t xTimerTaskTCB; // static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; // // /* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, // so the application must provide an implementation of // vApplicationGetTimerTaskMemory() to provide the memory that is used by the // Timer service task. */ // void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, // StackType_t **ppxTimerTaskStackBuffer, // uint32_t *pulTimerTaskStackSize ) // { // /* If the buffers to be provided to the Timer task are declared inside this // function then they must be declared static - otherwise they will be allocated // on the stack and so not exists after this function exits. */ // //static StaticTask_t xTimerTaskTCB; // //static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; // // /* Pass out a pointer to the StaticTask_t structure in which the Timer // task's state will be stored. */ // *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; // // /* Pass out the array that will be used as the Timer task's stack. */ // *ppxTimerTaskStackBuffer = uxTimerTaskStack; // // /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. // Note that, as the array is necessarily of type StackType_t, // configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */ // *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; // } // // /*----------------------------------------------------------------------------*/
Also before Main:
/*----------------------------------------------------------------------------*/ //Timer Callback // void myTimerCallback( TimerHandle_t xTimer ); // // //Static Allocation // TimerHandle_t myTimer; // StaticTimer_t myStaticTimerState; // /*----------------------------------------------------------------------------*/
New task definitions in main.c (provided below Main):
Task 0 modified to create and start a software, Task1 will do nothing, since LED D0 will be toggle by the timer task
static void prvMyTask0( void *pvParameters ) { ( void ) pvParameters; myTimer = xTimerCreateStatic ( /* Just a text name, not used by the RTOS kernel. */ "Timer", /* The timer period in ticks, must be greater than 0. */ 300, /* The timers will auto-reload themselves when they expire. */ pdTRUE, (void*)0, /* Each timer calls the same callback when it expires. */ myTimerCallback, &myStaticTimerState ); vTaskDelay(250); BaseType_t flag = xTimerStart( myTimer, 0 ); if (flag){ while(1){ vTaskDelay(250); xSemaphoreGive( myMutex); vTaskDelay(250); PORTB^=1; } } } static void prvMyTask1( void *pvParameters ) { ( void ) pvParameters; while(1){ taskYIELD(); } }
Callback function for timer to call every 300 ticks to toggle LED
/*----------------------------------------------------------------------------*/ //Timer Callback // void myTimerCallback( TimerHandle_t xTimer ){ // volatile static uint8_t c; //just for demonstration // PORTD^=1; // c=c+1; //just for demonstration // } // /*----------------------------------------------------------------------------*/
You will need to modify the stack size for each task according to needs
configMINIMAL_STACK_SIZE
is a port-specific quantity
Therefore, the following code would support a stack with, FOR EXAMPLE, an additional TEN 2-byte int16_t for Task0 and for Task1 FIVE two-byte uint16_t and THREE uint8_t
#define STACK_SIZE_T0 configMINIMAL_STACK_SIZE+20 #define STACK_SIZE_T1 configMINIMAL_STACK_SIZE+13 StackType_t xStack0[ STACK_SIZE_T0 ]; StackType_t xStack1[ STACK_SIZE_T1 ];
Each task creation call requires passing the allocated stack size as a parameter
/* Create the task without using any dynamic memory allocation. */ xHandle0 = xTaskCreateStatic( prvMyTask0, /* Function that implements the task. */ "T0", /* Text name for the task. */ STACK_SIZE_T0, /* Number of indexes in the xStack array. */ ( void * ) NULL, /* Parameter passed into the task. */ tskIDLE_PRIORITY+1,/* Priority at which the task is created. */ xStack0, /* Array to use as the task's stack. */ &xTask0TCB ); /* Variable to hold the task's data structure. */
For the Timer Callback function stack, a single configuration line change is required in FreeRTOSConfig.h
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE+20
it is used both in the addition required code that allocates the buffer, static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
, and by the FreeRTOS library.
The tasks are tracked in multiple priority queues.
Higher index priorities are higher priority and are selected over any lower priority tasks.
You can change the number of priority levels by changing this line in FreeRTOSConfig.h
#define configMAX_PRIORITIES ( 4 )
The task creation function accepts priority as a parameter
Here, the priority is set to 1 higher than the idleTask:
/* Create the task without using any dynamic memory allocation. */ xHandle0 = xTaskCreateStatic( prvMyTask0, /* Function that implements the task. */ "T0", /* Text name for the task. */ STACK_SIZE_T0, /* Number of indexes in the xStack array. */ ( void * ) NULL, /* Parameter passed into the task. */ tskIDLE_PRIORITY+1,/* Priority at which the task is created. */ xStack0, /* Array to use as the task's stack. */ &xTask0TCB ); /* Variable to hold the task's data structure. */
Note that Source/include/task.h provides the definition for tskIDLE_PRIORITY
#define tskIDLE_PRIORITY ( ( UBaseType_t ) 0U )`
Change this line in FreeRTOSConfig.h
In the example, the timer is set to the higest priority
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
Be careful to not starve lower priority tasks by delaying or suspending higher-priority tasks at times. Be mindful of both regular tasks and timer tasks. Coroutines (not that you would to use them) are lower priority than tasks.