Both projects include build options that allow the creation of a simple blinky demo or a comprehensive demo, and use:
The e2studio Eclipse project file used to build the demo with GCC, and the IAR Embedded Workbench project file used to build the demo with the IAR compiler, are both located in the FreeRTOS/Demo/CORTEX_R4F_RZ_T_GCC_IAR directory.
The e2studio GCC and IAR projects build the same RTOS demo application, and both include files that are contained in the /FreeRTOS-Plus directory, so the projects will not build if the /FreeRTOS-Plus directory has been deleted or moved from its default location.
main_blinky() creates an RTOS queue, a queue send task, and a queue receive task, then starts the scheduler.
The queue send task is implemented by the prvQueueSendTask() function in main_blinky.c.
prvQueueSendTask() sends the value 100 to the RTOS queue every 200 milliseconds.
The queue receive task is implemented by the prvQueueReceiveTask() function in main_blinky.c.
prvQueueReceiveTask() blocks to wait for data to arrive on the RTOS queue. Each time the value 100 is received from the queue it toggles LED 0. As data is sent to the queue every 200ms, the LED will toggle every 200ms.
The comprehensive example is created when mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set
to 0 in main.c. When this is done, main() calls main_full():
main_full() creates a set of standard demo tasks, some application specific test tasks, a command line interface (CLI) task, a pseudo randomiser task, and then starts the scheduler. The pseudo randomiser task is just used to ensure some variation is added to the sequence in which the test tasks execute, and in so doing, improve the test coverage.
The CLI is implemented using the FreeRTOS+CLI extensible command line interface, and uses the UART to USB converter connector (J8) at 19200 baud for its input and output. As always with FreeRTOS+CLI, type "help" to see a list of registered commands.
The reg test tasks test the context switching mechanism by filling each embedded processor register with a known value, then continuously checking that each register maintains its expected value for the lifetime of the task.
The "Check" task monitors the status of all the other tasks in the system, looking for a task either stalling, or reporting an error. It toggles LED 0 each time it iterates around its implementing loop.
If the LED is toggling every three seconds then the check task has not detected any stalled tasks, or detected any errors. If the LED is toggling every 200ms then at least one error has been found.
Interrupt service routines
When an interrupt occurs, the RZ/T real time embedded processor hardware will
vector directly to a peripheral specific interrupt handler, rather than to the
ARM Cortex-R IRQ vector. Therefore, each interrupt handler installed by the
application must include an assembly file wrapper that performs some house keeping,
then branches to the FreeRTOS interrupt entry code. The FreeRTOS interrupt entry
code manages interrupt entry, including interrupt nesting, before calling a
standard C function in which the interrupting peripheral is serviced.
For the purpose of this example, assume the C portion of the interrupt handler is called InterruptHandler() - as shown below. A full example is provided after the sections that demonstrate how to write the assembly file wrappers: void InterruptHandler( void ) { /* Write the interrupt handler code here. */ } The C portion of the interrupt handler - this is where the interrupting peripheral is serviced
For the purposes of this
example, assume the assembly wrapper is called InterruptHandlerWrapper(). The
wrapper must save a pointer to the C portion of the handler function into a
variable called pxISRFunction, then branch to a function called
FreeRTOS_IRQ_Handler (which is provided by the RTOS).
The syntax required to add the assembly file wrapper to each C interrupt handler function is dependent on the compiler used (IAR or GCC). Examples and further references are provided below.
SECTION intvec:CODE:ROOT(2) ARM /* Variables and functions from the RTOS port. */ EXTERN pxISRFunction EXTERN FreeRTOS_IRQ_Handler /* The C portion of the interrupt handler. */ EXTERN InterruptHandler /* Functions implemented in this file. */ PUBLIC InterruptHandlerEntry /* The implementation of InterruptHandlerEntry. */ InterruptHandlerEntry: /* Save used registers (probably not necessary). */ PUSH {r0-r1} /* Save the address of the C portion of this handler into pxISRFunction. */ LDR r0, =pxISRFunction LDR R1, =InterruptHandler STR R1, [r0] /* Restore used registers. */ POP {r0-r1} Branch to the RTOS IRQ handler. */ B FreeRTOS_IRQ_Handler The assembly wrapper for the C interrupt handler function - IAR
#include "FreeRTOS.h" /* The prototype for the function that implements the assembly file wrapper must use the naked attribute - which prevents the compiler from adding any function prologue or epilogue assembly code. */ void InterruptHandlerWrapper( void ) __attribute__((naked)); /* The implementation of InterruptHandlerEntry. This is a naked function and must not include and C code! */ void InterruptHandlerWrapper( void ) { __asm volatile ( /* Save used registers (probably not necessary). */ "PUSH {r0-r1} \t\n" /* Save the address of the C portion of this handler in pxISRFunction. */ "LDR r0, =pxISRFunction \t\n" "LDR r1, =InterruptHandler \t\n" /* Restore used registers. */ "STR r1, [r0] \t\n" "POP {r0-r1} \t\n" Branch to the RTOS IRQ handler. */ "B FreeRTOS_IRQ_Handler " ); } The assembly wrapper for the C interrupt handler function - GCC
The macros portYIELD_FROM_ISR() (or portEND_SWITCHING_ISR()) can be used to request a context switch from within an ISR. The following source code snippet is provided as an example. The example ISR uses a direct to task notification to synchronise with a task (not shown), and calls portYIELD_FROM_ISR() to ensure the interrupt returns directly to the task. void InterruptHandler(void) { long lHigherPriorityTaskWoken = pdFALSE; /* Clear the interrupt if necessary. */ Dummy_ClearPendingInterrupt(); /* This interrupt does nothing more than demonstrate how to synchronise a task with an interrupt. A task notification is used for this purpose. Note lHigherPriorityTaskWoken is initialised to zero. */ vTaskNotifyGiveFromISR()( xTaskToNotify, &lHigherPriorityTaskWoken ); /* If the task with handle xTaskToNotify was blocked waiting for the notification then sending the notification will have removed the task from the Blocked state. If the task left the Blocked state, and if the priority of the task is higher than the current Running state task (the task that this interrupt interrupted), then lHigherPriorityTaskWoken will have been set to pdTRUE internally within vTaskNotifyGiveFromISR(). Passing pdTRUE into the portEND_SWITCHING_ISR() macro will result in a context switch being pended to ensure this interrupt returns directly to the unblocked, higher priority, task. Passing pdFALSE into portEND_SWITCHING_ISR() has no effect. */ portEND_SWITCHING_ISR( lHigherPriorityTaskWoken ); } The C portion of an interrupt service routine
Only FreeRTOS API functions that end in "FromISR" can be called from an
interrupt service routine.
Generating the RTOS tick interrupt
The RTOS Cortex-R port is a generic port that is tailored to specific embedded
processor implementation using macros and callback functions. The RTOS tick
interrupt is configured using the following two macros, which are defined in
the FreeRTOSConfig.h file supplied with the RTOS demo application:
This must call the function that configures a timer to generate the tick interrupt, and install FreeRTOS_Tick_Handler() as the timers interrupt service routine (via an assembly wrapper, as described above).
In the provided demo application the macro is set to call vConfigureTickInterrupt(), which is defined in FreeRTOS/Demo/CORTEX_R4F_RZ_T_GCC_IAR/src/FreeRTOS_tick_config.c, and configures the compare match timer 5 (CMT5) to generate the RTOS tick.
This must clear pending interrupts in whichever timer is used to generate the RTOS tick.
In the provided demo application the macro is set to clear the interrupt
in CMT5, as the RTOS tick interrupt is generated by CMT5.
Including the IRQ handling function
The RTOS Cortex-R port is a generic port that is tailored to a specific embedded
processor implementation using macros and callback function. In the RZ/T RTOS port
the generic IRQ handling code (the code that manages interrupt entry) calls
vApplicationIRQHandler(), and vApplicationIRQHandler() must be provided by the
application.
In the provided demo application vApplicationIRQHandler() is implemented in FreeRTOS/Demo/CORTEX_R4F_RZ_T_GCC_IAR/src/FreeRTOS_tick_config.c, and replicated below: /* The function called by the FreeRTOS IRQ handler, after it has managed interrupt entry. This function creates a local copy of pxISRFunction before re-enabling interrupts then calling the handler pointed to by pxISRFunction. pxISRFunction is set by the assembly wrapper added to each interrupt handler. */ void vApplicationIRQHandler( void ) { ISRFunction_t pxISRToCall = pxISRFunction; portENABLE_INTERRUPTS(); /* Call the installed ISR. */ pxISRToCall(); } The implementation of vApplicationIRQHandler() for the RZ/T RTOS port