The project builds using the free Altera edition of the ARM DS-5 Eclipse based IDE and the GCC compiler, both of which come as part of the Altera Embedded Development Suite (EDS). Note only the DS-5 and compiler components of the EDS are used - it is not necessary to install any FPGA tools to build or use this RTOS demo.
The project is pre-configured to execute on the Cyclone V SoC Development Kit hardware.
FreeRTOS+CLI is used to create a command console [Note the FreeRTOS+CLI license is not the same as the FreeRTOS license]
Source Code Organisation
Only a small subset of the files in the FreeRTOS .zip file download are are
required by the Altera Cyclone V SoC demo. The Source Code Organization page describes
the structure of the FreeRTOS zip file download.
The ARM DS-5 Eclipse project file is located in the FreeRTOS/Demo/CORTEX_A9_Cyclone_V_SoC_DK directory. Note the RTOS project includes files that are contained in the /FreeRTOS-Plus directory, so the projects will not build if the /FreeRTOS-Plus directory has been deleted or the directory structure has been changed.
A UART is used for console IO. The demo in the download uses UART 0 for this purpose. UART 0 uses a UART to USB converter, so is connected using a USB cable.
If it is necessary to use a UART other than UART 0 then update the FreeRTOS/Demo/CORTEX_A9_Cyclone_V_SoC_DK/Altera_Code/SoCSupport/uart0_support.c source file accordingly.
A digital output is used to toggle an LED. If it is necessary to use a different digital output then update FreeRTOS/Demo/CORTEX_A9_Cyclone_V_SoC_DK/LEDs.c accordingly.
main_blinky() creates a very simple demo that includes two tasks and one queue. One task repeatedly sends the value 100 to the other task through the queue. The receiving task toggles an LED each time it receives the message. The message is sent every 200 milliseconds, so the LED toggles every 200 milliseconds.
Most of the RTOS tasks created by the demo are from the set of standard demo RTOS tasks. These are used by all FreeRTOS demo applications, and have no specific functionality or purpose other than to demonstrate the FreeRTOS API being used and test the RTOS kernel port.
A 'check' RTOS task is also created. The check task periodically queries the standard demo tasks to ensure they are functioning as intended. The check task also toggles an LED to give a visual indication of the system status. If the LED toggles every 3 seconds then the check task has not discovered any problems with the executing demo. If the LED toggles every 200 milliseconds then the check task has discovered a problem in at least one task..
Select "Properties" from the IDE's "Project" menu to bring up the properties dialogue box. In the dialogue box select "C/C++Build->Settings-> Cross Settings", then set the path to the compiler to be correct for your installation.
Note: If the dialogue box tab shown in the image below is missing, or contains an error message, then it is likely your version of DS-5 does not have the CDT cross compiler plug in installed. If this is the case the plug in can be installed manually by following the instructions provided on the ARM website. It will be necessary to create a new workspace after the plug-in has been installed.
In this demo configSETUP_TICK_INTERRUPT is defined to call vConfigureTickInterrupt(), which in turn is implemented in main.c. vApplicationIRQHandler() is also implemented in main.c.
Configuration items specific to this demo are contained in FreeRTOS/Demo/CORTEX_A9_Cyclone_V_SoC_DK/FreeRTOSConfig.h. The constants defined in this file can be edited to suit your application.
/* * ulID - the ID of the interrupt as defined in the Altera provided * alt_interrupt_common.h header file. * * pxHandlerFunction - the C function being registered to handle the interrupt. * * pvContext - a reference to additional data of the application writer's choice * that can be used from within the interrupt handler. */ void vRegisterIRQHandler( uint32_t ulID, alt_int_callback_t pxHandlerFunction, void *pvContext ); vRegisterIRQHandler() function prototype
The C handlers themselves have the following prototype;
/*
* ulICCIAR - the value of the generic interrupt controller's (GIC's) IAR register
* at the time the hander is called.
*
* pvContext - the pointer to additional data for the handler that was passed into
* the call to vRegisterIRQHandler() used to register the handler.
*/
void vAnISRHandlingFunction( uint32_t ulICCIAR, void *pvContext );
The prototype of an interrupt handling function that can be registered using vRegisterIRQHandler()
If an ISR causes an RTOS task of equal or higher priority than the currently executing
task to leave the Blocked state (see description of the pxHigherPriorityTaskWoken
parameter in the API documentation for functions such as
xSemaphoreGiveFromISR())
then the ISR must request a context switch before
the ISR exits. When this is done the interrupt will interrupt one RTOS task,
but return to a different RTOS task.
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 semaphore to synchronise with a task (not shown), and calls portYIELD_FROM_ISR() to ensure the interrupt returns directly to the task. void Dummy_IRQHandler( uint32_t ulUnused, void *pvUnused ) { long lHigherPriorityTaskWoken = pdFALSE; /* The parameter is not used. */ ( void ) ulUnused; /* Clear the interrupt if necessary. */ Dummy_ClearITPendingBit(); /* This interrupt does nothing more than demonstrate how to synchronise a task with an interrupt. A semaphore is used for this purpose. Note lHigherPriorityTaskWoken is initialised to pdFALSE. */ xSemaphoreGiveFromISR( xTestSemaphore, &lHigherPriorityTaskWoken ); /* If there was a task that was blocked on the semaphore, and giving the semaphore caused the task to unblock, and the unblocked task has a priority higher than or equal to the currently Running task (the task that this interrupt interrupted), then lHigherPriorityTaskWoken will have been set to pdTRUE internally within xSemaphoreGiveFromISR(). Passing pdTRUE into the portYIELD_FROM_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 portYIELD_FROM_ISR() has no effect. */ portYIELD_FROM_ISR( lHigherPriorityTaskWoken ); } An example interrupt handler
Only FreeRTOS API functions that end in "FromISR" can be called from an interrupt service routine - and then only if the priority of the interrupt is less than or equal to that set by the configMAX_API_CALL_INTERRUPT_PRIORITY configuration constant (meaning a numerically higher value).