You are on page 1of 34

QP state machine frameworks for FreeRTOS.

org

QDK FreeRTOS.org
Document Revision B September 2008

Copyright Quantum Leaps, LLC www.quantum-leaps.com www.state-machine.com

Table of Contents
1 1.1 1.2 Introduction.................................................................................................... 1 Whats Included in the QDK-FreeRTOS? ............................................................... 2 Licensing QDK-MSP430-IAR................................................................................ 2

Getting Started ............................................................................................... 3 2.1 Installation ...................................................................................................... 3 2.2 Building the QP Libraries .................................................................................... 4 2.3 Building the Examples ....................................................................................... 5 2.4 Running the Examples ....................................................................................... 6 2.4.1 Minimal FreeRTOS.org Demo Application ........................................................ 7 2.4.2 Dining Philosopher Problem (DPP) Example Application .................................... 7 3.1 3.2 3.3 3.4 3.5 The Modified FreeRTOS.org Port STR9x_IAR................................................... 9 Augmented FreeRTOS.org Interrupt Processing ..................................................... 9 General Limitations of FreeRTOS.org Ports.......................................................... 10 Changes in the portmacro.h file ......................................................................... 10 Changes in the port.c File................................................................................ 13 Demo Application for the Updated FreeRTOS.org Port........................................... 14

The QP Port to FreeRTOS.org ........................................................................ 15 4.1 The FreeRTOSConfig.h Header File .................................................................... 15 4.2 The qep_port.h Header File .............................................................................. 16 4.3 The qf_port.h Header File................................................................................. 16 4.3.1 The Active Object Event Queue and Thread .................................................. 17 4.3.2 The QF Critical Section .............................................................................. 17 4.3.3 FreeRTOS.org Include Files ........................................................................ 17 4.3.4 QP Include Files........................................................................................ 17 4.3.5 Memory Pool ............................................................................................ 18 4.4 The qf_port.c Source File ................................................................................. 18 4.5 ARM/THUMB Compilation ................................................................................. 22 5.1 5.2 5.3 5.4 5.5 The Example QP Application.......................................................................... 23 The main() Function ........................................................................................ 23 ISRs ............................................................................................................. 24 Starting Interrupts in vStartInterrupts()............................................................. 25 Idle Processing in vApplicationIdleHook() ........................................................... 25 Assertion Handling Policy in Q_onAssert() .......................................................... 26 The Quantum Spy (QS) Instrumentation....................................................... 27 QS Time Stamp Callback QS_onGetTime().......................................................... 29 Invoking the QSpy Host Application ................................................................... 30 Related Documents and References .............................................................. 31 Contact Information...................................................................................... 32

6 6.1 6.2 7 8

Copyright Quantum Leaps, LLC. All Rights Reserved.

1 Introduction
This QP Development Kit (QDK) describes how to use QP event-driven platform with the FreeRTOS.org real-time kernel. The actual hardware/software used in this QDK is described below (see also Figure 1): 1. IAR STR912-SK board with STR912F device (ARM966E-S core, 96KB RAM, 512KB ROM). 2. IAR Embedded Workbench for ARM (EWARM) KickStart edition version 5.11. 3. FreeRTOS.org version 5.0.0 or higher. 4. QP/C/C++ v4.0 or higher. J-Link USB Debugger QS trace data (UART0) LED/Peripheral Jumpers

Two groups of user LEDs 8 LEDs each STR912F Target Device

USB to PC

External power

Power source selection Jumper

Figure 1 IAR STR912-SK evaluation board with the J-Link JTAG pod.

Copyright Quantum Leaps, LLC. All Rights Reserved.

1 of 32

QDK FreeRTOS.org www.state-machine.com/freertos As shown in Figure 1, the STR912-SK board is connected via a 20-pin ribbon cable to the J-Link USB debugger. Additionally, the UART0 connector of the STR912-SK board is used in this QDK for QS (Spy) software tracing of the live QP applications. You need a straight serial cable with DB9 connectors to connect UART0 to the COM port of your PC. NOTE: Even though the QDK uses a specific target board (STR912-SK in this case), the QDK has been designed generically to rely on the FreeRTOS.org to access the hardware. In other words, the QDK should require minimal adaptation for any other platform supported by FreeRTOS.org.

1.1 Whats Included in the QDK-FreeRTOS?


This QDK provides a modified FreeRTOS port to STR91-IAR, a minimal demo application that tests this updated FreeRTOS.org port, as well as QP port to FreeRTOS and the Dining Philosopher Problem (DPP) application to test the QP port to FreeRTOS. The DPP example application is described in the Application Note Dining Philosophers Application [QL AN-DPP 08] (included in this DPP). The DPP application also demonstrates the QS (Spy) software tracing. NOTE: This QDK covers both the C and C++ version of QP. The concrete code examples are taken from the C version, but the C++ version is essentially identical except for some trivial syntax differences.

1.2 Licensing QDK-MSP430-IAR


The Generally Available (GA) distribution of QDK-MSP430-IAR available for download from the www.quantum-leaps.com/msp430 website is offered with the following two licensing options: The GNU General Public License version 2 (GPL) as published by the Free Software Foundation and appearing in the file GPL.TXT included in the packaging of every Quantum Leaps software distribution. The GPL open source license allows you to use the software at no charge under the condition that if you redistribute the original software or applications derived from it, the complete source code for your application must be also available under the conditions of the GPL (GPL Section 2[b]). One of several Quantum Leaps commercial licenses, which are designed for customers who wish to retain the proprietary status of their code and therefore cannot use the GNU General Public License. The customers who license Quantum Leaps software under the commercial licenses do not use the software under the GPL and therefore are not subject to any of its terms.

For more information, please visit the licensing section of our website at: www.quantumleaps.com/licensing.

Copyright Quantum Leaps, LLC. All Rights Reserved.

2 of 32

QDK FreeRTOS.org www.state-machine.com/freertos

2 Getting Started
This section describes how to install, build, and use QDK-FreeRTOS. This information is intentionally included early in this document, so that you could start using the QDK as soon as possible. NOTE: This QDK assumes that the standard QP distribution, consisting of QEP, QF, and QS, has been installed, before installing this QDK. It is also strongly recommended that you read the QP Tutorial (www.quantum-leaps.com/doxygen/qpc/tutorial_page.html) before you start experimenting with this QDK.

2.1 Installation
The QDK code is distributed in a ZIP archive (qdkc_freertos_<ver>.zip, where <ver> stands for a specific QDK-FreeRTOS version, such as 4.0.01). You should uncompress the archive into the same directory into which youve installed all the standard QP components. The installation directory you choose will be referred henceforth as QP Root Directory (<qp>). The following Listing 1 shows the directory structure and selected files included in the QDK-FreeRTOS distribution. (Please note that the QP directory structure is described in detail in a separate Application Note: QP Directory Structure [QL AN-Directory 07]): doc\ | +-AN_DPP.pdf +-QDK_FreeRTOS.pdf - Documentation for this QDK - Application Note Dining Philosophers Application - This QDK Programmers Manual FreeRTOS.org root directory FreeRTOS.org demo applicaitons Modified ARM9_STR91X_IAR demo application the main() function of the application FreeRTOS configuration IAR workspace to build the application other files in the application FreeRTOS.org source files FreeRTOS.org ports ports for the IAR toolset ports for the STR9x MCUs (!! MODIFIED from the original !!) port-specific code (!! MODIFIED from the original !!) port-specific macros (!! MODIFIED from the original !!) context-switch support (unchanged) vPortStartFirstTask and vPortYieldProcessor (unchanged)

FreeRTOS/ | +-Demo/ | +-ARM9_STR91X_IAR_light/ | | +-main.c | | +-FreeRTOSConfig.h | | +-RTOSDemo.eww | | +-. . . | +-Source/ | +-portable/ | | +-IAR/ | | | +-STR9x/ | | | | +-port.c | | | | +-portmacro.c | | | | +-ISR_Support.h | | | | +-portasm.s79 <qp>/ | +-include/ | +-qassert.h | +-qep.h | +-qf.h | +-qequeue.h | +-qmpool.h | +-qpset.h | +-ports/ | +-arm/ | | +-freertos/ | | | +-iar/ | | | | +-dbg/

- QP root directory (qpcpp for QP/C++) QP public include files Quantum Assertions platform-independent public include QEP platform-independent public include QF platform-independent public include native QF event queue include native QF memory pool include native QF priority set include QP ports ARM port FreeRTOS.org ports IAR compiler QP libraries for Debug configuration 3 of 32

Copyright Quantum Leaps, LLC. All Rights Reserved.

QDK FreeRTOS.org www.state-machine.com/freertos | | | | +-rel/ - QP libraries for Release configuration | | | | +-spy/ - QP libraries for Spy configuration | | | | +-make_ARM966E-S.bat - make script for building QP libraries (ARM966E-S core) | | | | +-FreeRTOSConfig.h - FreeRTOS.org configuration to use in the QP port | | | | +-qep_port.h - QEP port | | | | +-qf_port.h - QF port to FreeRTOS.org | | | | +-qs_port.h - QS port | | | | +-qp_port.h - QP port | +-examples/ - subdirectory containing the examples | +-arm/ - ARM examples | | +-freertos/ - FreeRTOS examples | | | +-iar/ - IAR EWARM examples | | | | +-dpp-str912-sk/ - Dining Philosophers example for STR912-SK | | | | | +-dbg/ - directory containing the Debug build | | | | | +-rel/ - directory containing the Release build | | | | | +-spy/ - directory containing the Spy build | | | | | +-STR91xlibrary/ - directory containing the ST driver library for STR91x | | | | | | +-include/ - driver library header files | | | | | | +-source/ - driver library source files | | | | | +-dpp-freertos.eww - IAR workspace to build the DPP example | | | | | +-bsp.c - Board Support Package for MSP430 | | | | | +-bsp.h - BSP header file | | | | | +-main.c - the main function | | | | | +-philo.c - the Philosopher active object | | | | | +-dpp.h - the DPP header file | | | | | +-table.c - the Table active object | | | | | +-freertos_task.h - raw FreeRTOS.org task header file | | | | | +-freertos_task.c - raw FreeRTOS.org task implementation Listing 1 Selected QP directories and files after installing QDK-FreeRTOS. The highlighted elements are included the files included in QDK-FreeRTOS.

2.2 Building the QP Libraries


QP is deployed as a set of libraries that you statically link to your application. The pre-built libraries for QEP, QF, and QS are provided inside the <qp>\ports\arm\freertos\iar\ directory (see Listing 1). This section describes steps you need to take to rebuild the libraries yourself. NOTE: To streamline and simplify the QP-library build process, Quantum Leaps software does not use the vendor-specific IDEs, such as the IAR Embedded Workbench IDE, for building the QP libraries. Instead, this QDK provides command-line build process based on simple batch scripts. The build process for your application is largely independent on the QP-library builds. In fact, once you have the QP libraries, you typically dont need to rebuild themat least not on the daily basis as you work on your application. This QDK uses the IAR EWARM IDE to build the example applications, but you are free to use any other build strategy. The code distribution contains all the batch file make_ARM966E-S.bat for building all the libraries located in <qp>\ports\arm\freertos\iar\ directory. For example, to build the debug version of all the QP libraries for FreeRTOS.org with the IAR ARM compiler, you open a console window on a Windows PC, change directory to <qp>\ports\freertos\iar\, and invoke the batch script by typing at the command prompt the following command: make_ARM966E-S.bat

Copyright Quantum Leaps, LLC. All Rights Reserved.

4 of 32

QDK FreeRTOS.org www.state-machine.com/freertos The make process should produce the QP libraries in the location: <qp>\ports\arm\freertos\iar\dbg\. The make_ARM966E-S.bat assumes that the IAR ARM toolset has been installed in the directory c:\tools\IAR\ARM_KS_5.11. The batch script also assumes that FreeRTOS is installed in the directory ..\..\..\..\..\FreeRTOS\Source\include relative to the QP port directory (see Listing 1). NOTE: You need to adjust the symbol IAR_ARM at the top of the make_ARM966E-S.bat file if youve installed the IAR toolset in a different directory. You also need to adjust the symbol RTOS_INCDIR if youve installed FreeRTOS.org in a different directory. In order to take advantage of the Q-SPY instrumentation, you need to build the Spy version of the QP libraries. You achieve this by invoking the make_ARM966E-S.bat utility with the spy target, like this: make_ARM966E-S spy The make process should produce the QP libraries in the directory: <qp>\ports\arm\freertos\iar\spy\. You choose the build configuration by providing a target to the make_ARM966E-S.bat utility. The default target is dbg. Other targets are rel, and spy respectively. The following table summarizes the targets accepted by make.bat. Software Version Debug (default) Release Spy Build command make_ARM966E-S make_ARM966E-S rel make_ARM966E-S spy

Table 1 Make targets for the debug, release, and spy software versions

2.3 Building the Examples


This QDK-FreeRTOS uses the DPP (Dining Philosophers Problem) example described in Application Note [QP AN-DPP 08]. The QDK contains the IAR Embedded Workbench workspaces to build the examples. Each workspace contains three build configurations: Debug, Release, and Spy. The workspaces are located in <qp>\examples\arm\freertos\iar\dpp-str92-sk\dpp-freertos.esw. As shown in Figure 2, you select the build configuration from the drop-down box in the top-left corner of the IDE.

Copyright Quantum Leaps, LLC. All Rights Reserved.

5 of 32

QDK FreeRTOS.org www.state-machine.com/freertos

Use the drop-down list to select one of the build configurations: Debug, Release, or Spy

Figure 2 IAR Embedded Workbench with the dpp-freertos.eww workspace.

2.4 Running the Examples


As mentioned before, this QDK contains two example applications for the STR912-SK board. Both of these examples require setting up the jumpers as shown in Figure 1 and in greater detail in Figure 3.

LED 16

LED 15

LED 14

LED 13

LED 12

LED 11

LED 10

LED 9

LED 8

LED 7

LED 6

LED 5

LED 4

LED 3

LED 2

Figure 3 LED/Peripheral jumper setting on the STR912-SK board.

Copyright Quantum Leaps, LLC. All Rights Reserved.

LED 1

6 of 32

QDK FreeRTOS.org www.state-machine.com/freertos

2.4.1 Minimal FreeRTOS.org Demo Application


The first example included in this QDK is a minimal FreeRTOS.org demo application for the updated port to the STR1x processor. This example does not use QP and its purpose is to validate the modified FreeRTOS port. This demo application is located in the directory FreeRTOS\Demo\ARM9_STR91X_IAR_light (see Listing 1).

Figure 4 The RTOSDemo demo application stopped at the IAR debugger You load and debug the application using the IAR Embedded Workbench (see Figure 4). The application uses the User LEDs 9-11 to display the status of the three tasks LED-flashing tasks (the standard minimal FreeRTOS.org demo). LED 16 is toggled within the idle callback (vApplicationIdleHook()).

2.4.2 Dining Philosopher Problem (DPP) Example Application


The second example included in this QDK is the Dining Philosopher Problem (DPP) Example Application described in the Application Note Dining Philosophers Application [QL AN-DPP 08]. This example demonstrates QP and its purpose is to validate the QP port to FreeRTOS.org. This example application is located in the directory <qp>\examples\arm\freertos\iar\dpp-str912-sk\ (see Listing 1). Copyright Quantum Leaps, LLC. All Rights Reserved.

7 of 32

QDK FreeRTOS.org www.state-machine.com/freertos As the DPP application is running, the user LEDs 9-13 (see Figure 1) should blink indicating the changing status of the Dining Philosophers. Additionally LED 15 should blink once per second with 50% duty cycle. LED 15 is driven from a raw FreeRTOS task running outside the QP framework. Finally, LED 16 should glow at lower intensity than the rest of the LEDs. LED 16 is toggled from the FreeRTOS idle callback (vApplicationIdleHook()) If you downloaded the Spy build configuration to the target board and connected the UAR0 of the STR912-SK board to the COM port on your PC, you could launch the QSPY host utility to observe the output in the human-readable format. You launch the QSPY utility on a Windows PC as follows. Change the directory to the QSPY host utility <qp>\tools\qspy\win32\mingw\rel and execute: qspy c COM1 b 115200 This will start the QSPY host application to listen on COM1 serial port with baud rate 115200. (Please use the actual COM port number on your PC.) The following screen shot shows the QSPY output from the DPP run:

command-line options used

timestamp

QS trace record Figure 5 Screen shot from the QSPY output.

Copyright Quantum Leaps, LLC. All Rights Reserved.

8 of 32

QDK FreeRTOS.org www.state-machine.com/freertos

3 The Modified FreeRTOS.org Port STR9x_IAR


The standard FreeRTOS.org ports must be modified to work with QP for the following two reasons: 1. FreeRTOS.org uses different APIs for posting to message queues from tasks and ISRs. In contrast, QP uses the same API in all contexts. 2. FreeRTOS.org generally does not support interrupt nesting and consequently interrupts should never be unlocked inside ISRs. To be able to use the FreeRTOS.org critical section mechanism, QP must not inadvertently unlock interrupts within ISRs (again, because QP uses the same API inside tasks and ISRs). Unfortunately, because all FreeRTOS ports are hard-coded in the FreeRTOS.h master include file, it is not possible to define the updated port in a different location than the hardwired directory. NOTE: Because of this design aspect of FreeRTOS.org, you need to manually update the FreeRTOS.org ports each time you update FreeRTOS.org to a newer version.

3.1 Augmented FreeRTOS.org Interrupt Processing


The solution to both these issues is to augment FreeRTOS.org ISR processing to keep track of interrupt nesting as well as critical section established automatically in hardware upon the interrupt entry. The following (1) void Your_ISR(void) { (2) portISR_ENTRY(); (3) (4)

/* always inform FreeRTOS about entering an ISR */

/* clear the interrupt source... */ Call one of FreeRTOS services allowed in ISRs: vTaskIncrementTick(); vTaskResumeFromISR(); xQueueSendFromISR(); xQueueSendToFrontFromISR(); xQueueSendToBackFromISR(); xQueueReceiveFromISR(); xSemaphoreGiveFromISR(); Call one of QP services allowed in ISRs: QF_tick(); QF_publish(); QActive_postFIFO(); QACtive_postLIFO(); Q_NEW(); QEQueue_get(); QEQueue_postFIFO(); QEQueue_postLIFO(); portISR_EXIT(); } /* always inform FreeRTOS about exiting an ISR */

(5)

(6)

Listing 2 Augmented interrupt processing for FreeRTOS.org (1) The ISR is typically entered with interrupts locked in hardware (some CPUs, such as ARM Cortex-M3 dont lock interrupts, but this is an exception). In particular, ARM7/ARM9 processors enter the IRQ exception with IRQs locked at the ARM core level. Copyright Quantum Leaps, LLC. All Rights Reserved. 9 of 32

QDK FreeRTOS.org www.state-machine.com/freertos (2) The macro portISR_ENTRY() informs FreeRTOS.org (and QP) about entering the ISR. This macro is shown in Listing 3. NOTE: Calling postISR_ENTRY() at the beginning of every ISR is necessary for correct performance of the QP framework. (3) If your interrupt source requires clearing, you should perform it right after portISR_ENTRY(). (4) You may call any of the FreeRTOS.org services allowed in the ISR context. (5) You may also call any of the QP services allowed in the ISR context. Please note that most QP services allowed in ISRs can also be called from the task level. (2) The macro portISR_EXIT() informs FreeRTOS.org (and QP) about exiting the ISR. This macro is shown in Listing 3. This macro performs also FreeRTOS.org context switch, if preemptive configuration is selected. NOTE: Calling postISR_EXIT() at the beginning of every ISR is necessary for correct performance of the QP framework.

3.2 General Limitations of FreeRTOS.org Ports


As of Version 5.0, FreeRTOS.org does not support nesting of interrupts for most CPU architectures, including ARM7/ARM9. This means that you should never enable interrupts inside ISRs, either directly or indirectly inside any function you call from ISRs. Additionally, specifically to ARM7/ARM9 architectures, you should not call any FreeRTOS.org services from FIQ (fast interrupt). Preferably, you should not use FIQ at all. The ARM architecture has no means to protect IRQs from preemption by the FIQ and consequently interrupt nesting cannot be prevented when FIQ is used.

3.3 Changes in the portmacro.h file


Listing 3 shows the portmacro.h header file located in the port directory (<FreeRTOS>\Source\portable\IAR\STR91x\) in this case. The explanation section immediately following Listing 3 describes the changes made with respect to the original portmacro.h header file from the standard FreeRTOS distribution. Note that the changes are fairly generic, so they can be copied verbatim to other FreeRTOS.org ports. #include <intrinsics.h> #ifdef __cplusplus extern "C" { #endif /* Type #define #define #define #define #define #define #define definitions. */ portCHAR portFLOAT portDOUBLE portLONG portSHORT portSTACK_TYPE portBASE_TYPE char float double long short unsigned portLONG portLONG 10 of 32

Copyright Quantum Leaps, LLC. All Rights Reserved.

QDK FreeRTOS.org www.state-machine.com/freertos #if( configUSE_16_BIT_TICKS == 1 ) typedef unsigned portSHORT portTickType; #define portMAX_DELAY ( portTickType ) 0xffff #else typedef unsigned portLONG portTickType; #define portMAX_DELAY ( portTickType ) 0xffffffff #endif /*-----------------------------------------------------------*/ /* Hardware specifics. */ #define portSTACK_GROWTH ( -1 ) #define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ ) #define portBYTE_ALIGNMENT 4 #define portYIELD() asm ( "SWI 0" ) #define portNOP() asm ( "NOP" ) /*-----------------------------------------------------------*/ #define portDISABLE_INTERRUPTS() __disable_interrupt() #define portENABLE_INTERRUPTS() __enable_interrupt() /* Critical section handling. */ (1) #define portENTER_CRITICAL() do { \ (2) __disable_interrupt(); \ (3) ++ulCriticalNesting; \ } while (0) (4) #define portEXIT_CRITICAL() \ (5) if ((--ulCriticalNesting) == portNO_CRITICAL_NESTING) { \ (6) __enable_interrupt(); \ (7) } else ((void)0) (8) #define portISR_ENTRY() do { \ (9) ++ulInterruptNesting; \ (10) ++ulCriticalNesting; \ } while (0) (11) #if configUSE_PREEMPTION == 1 #define portISR_EXIT() do { \ (12) --ulInterruptNesting; \ (13) --ulCriticalNesting; \ (14) vTaskSwitchContext(); \ } while (0) #else #define portISR_EXIT() do { \ (15) --ulInterruptNesting; \ (16) --ulCriticalNesting; \ } while (0) #endif /* externals and constants required to handle critical sections */ (17) extern volatile unsigned portLONG ulCriticalNesting; (18) extern volatile unsigned portLONG ulInterruptNesting; (19) #define portNO_CRITICAL_NESTING ((unsigned portLONG)0) /* application-specific function to start interrupts, including the timer that generates the tick ISR */ (20) void vStartInterrupts(void); /*-----------------------------------------------------------*/ /* Task utilities. */ #define portEND_SWITCHING_ISR(xSwitchRequired) \ if (xSwitchRequired) { \ Copyright Quantum Leaps, LLC. All Rights Reserved. 11 of 32

QDK FreeRTOS.org www.state-machine.com/freertos extern void vTaskSwitchContext(void ); \ vTaskSwitchContext(); \

} \ else ((void)0)

/*-----------------------------------------------------------*/ /* Compiler specifics */ #define inline /* Task function macros as described on the FreeRTOS.org WEB site. */ #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) \ void vFunction( void * pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) \ void vFunction( void * pvParameters ) #ifdef __cplusplus } #endif Listing 3 Updated portmacro.h header file located in the <FreeRTOS>\Source\portable\IAR\STR91x\ directory. (1) The macro portENTER_CRITICAL() has been re-defined to perform all actions inline to eliminate the function call overhead from the original implementation. This slightly increases code size, but avoids flushing the pipeline (5-stage pipeline in ARM9 devices) twice per each portENTER_CRITICAL() invocation. The do { } while(0) loop around the body of the macro is the standard way of syntactically-correct grouping instructions without creating the dangling-else problem. (2) The IAR intrinsic function __disable_interrupt() expands inline to 3 ARM instructions, when the code is compiled to ARM. (The source code of FreeRTOS.org and the QF component of QP are compiled to ARM for best performance.) (3) The global variable ulCriticalNesting is incremented to account for entering a critical section. (4) The macro portEXIT_CRITICAL() has been re-defined to perform all actions inline to eliminate the function call overhead from the original implementation. (5) The global variable ulInterruptNesting is first decremented and then compared to the portNO_CRITICAL_NESTING constant. (6) When ulInterruptNesting drops down to the portNO_CRITICAL_NESTING level it means that the last level of critical section nesting is being exited. Only in this case the interrupts can be unlocked by means of the IAR intrinsic function __enable_interrupt(), which expands inline to 3 ARM instructions, when the code is compiled to ARM. (7) Terminating the if branch with else ((void)0) is the standard way of syntactically-correct grouping instructions without creating the dangling-else problem. (8) The macro portISR_ENTRY() has been introduced in this updated FreeRTOS.org port, as described in Section 3.1. (9) The global variable ulInterruptNesting is incremented to account for entering an interrupt level. (10) The global variable ulCriticalNesting is incremented to account for entering a critical section already established automatically in hardware. NOTE: Incrementing of ulCriticalNesting should only be done for processors that actually lock interrupts in hardware before entering an ISR. ARM7/ARM9 cores do lock interrupts. Copyright Quantum Leaps, LLC. All Rights Reserved. 12 of 32

QDK FreeRTOS.org www.state-machine.com/freertos (11) The behavior of the portISR_EXIT() macro (see Section 3.1) depends whether preemptions are configured or not. (12) The global variable ulInterruptNesting is decremented to account for exiting an interrupt level. This step is the exact reverse of step (2). (13) The global variable ulCriticalNesting is decremented to account for exiting the critical section, as the ISR return restores the CPU status before the interrupt. This step is the exact reverse of step (9). NOTE: Decrementing of ulCriticalNesting should only be done for processors that actually unlock interrupts in hardware after exiting an ISR. ARM7/ARM9 cores do unlock interrupts by restoring CPSR from SPSR. (14) When preemptions are configured, the FreeRTOS.org context switch is requested by calling vTaskSwitchContext(), to check if a higher-priority task was made ready-to-run and needs to preempt the interrupted task. (15-16) When preemptions are not configured, only the nesting levels are decremented, but the FreeRTOS.org context switch is not requested. (17-18) The global nesting levels are declared as external and volatile, because they can be asynchronously modified inside ISRs. (19) The constant portNO_CRITICAL_NESTING is defined for the port (typically zero). (20) The prototype of the new callback function vStartInterrupts() is declared. This function replaces the private function prvSetupTimerInterrupt() defined in the original FreeRTOS.org port. The vStartInterrupts() function is called from the modified port.c file to configure and start interrupts, including the system clock tick. This function is application-specific and cannot be defined at the port level (callback function).

3.4 Changes in the port.c File


The changes required in port.c file are just simple consequence of the augmented interrupt handling policy described in Section 3.1. In fact, the port.c file has been drastically simplified by removing system clock tick ISRs from the port level. Its more convenient to define all ISRs consistently at the application level, including the system clock tick ISR. The following Listing 4 shows how the modified port.c file calls the vStartInterrupts() function from xPortStartScheduler(). portBASE_TYPE xPortStartScheduler( void ) { extern void vPortStartFirstTask ( void ); /* Start interrupts, including the timer that generates the tick ISR. Interrupts are disabled here already. */ vStartInterrupts(); /* Start the first task. */ vPortStartFirstTask(); /* Should not get here! */ return 0; } Copyright Quantum Leaps, LLC. All Rights Reserved. 13 of 32

QDK FreeRTOS.org www.state-machine.com/freertos Listing 4 Calling vStartInterrupts() from the updated port.c source file.

3.5 Demo Application for the Updated FreeRTOS.org Port


The demo application for the updated FreeRTOS.org port has been derived from the demo included in the standard FreeRTOS distribution for the STR91x processor. The demo application is located in the directory <FreeRTOS>\Demo\ARM9_STR91X_IAR_light\. Section 2.4.1 describes how to build and run the demo application. The ARM9_STR91X_IAR_light demo application is minimal and simply spawns three LED-flashing tasks, as implemented in <FreeRTOS>\Demo\Common\Minimal\falsh.c. The application also shows how to crrect the LED interface for the STR912-SK board, which was not working in the original demo. The ARM9_STR91X_IAR_light demo also uses Timer3 as the source of the system clock tick interrupt. The most interesting modifications from the original demo include the augmented interrupt processing, as shown below: __arm void TIM3_IRQHandler(void) { portISR_ENTRY(); /* always inform FreeRTOS about entering an ISR */ TIM3->OC1R += BSP_TIM3_PERIOD - 1; TIM3->SR &= ~TIM_IT_OC1; vTaskIncrementTick(); } portISR_EXIT(); /* set the output compare register */ /* clear interrupt source (Timer3) */

/* handle the FreeRTOS.org system clock tick */ /* always inform FreeRTOS about exiting an ISR */

NOTE: The ARM9_STR91X_IAR_light demo uses the modified FreeRTOSConfig.h header file, as described in Section 4.1.

Copyright Quantum Leaps, LLC. All Rights Reserved.

14 of 32

QDK FreeRTOS.org www.state-machine.com/freertos

4 The QP Port to FreeRTOS.org


The QP port to FreeRTOS.org allows running QP on top of FreeRTOS.org real-time kernel, using the modified FreeRTOS.org port as described in Section 3.

4.1 The FreeRTOSConfig.h Header File


As described in the FreeRTOS.org online documentation [FreeRTOS.org 08] (User Documentation/Configuration section), every FreeRTOS application customizes the FreeRTOS by means of the FreeRTOSConfig.h header file. Consequently, the FreeRTOSConfig.h header file is typically located in the application directory. In the QP port, however, some configuration information contained in the FreeRTOSConfig.h header file is required to build the QP components, because QP depends on FreeRTOS.org for critical section mechanism, tasks, and queues. Therefore, in case of the QP port, the FreeRTOSConfig.h header file is located in the QP port directory, which is <qp>\ports\arm\freertos\iar\ in case of this QDK. The QP applications dont provide their own FreeRTOSConfig.h header files, but rather must consistent with the configuration contained in the QP port directory. NOTE: To ensure consistency of configuration you need to rebuild the QP libraries after modifying the FreeRTOSConfig.h header file in the QP port directory. Section 2.2 describes how to build QP libraries. (1) (2) (3) (4) (5) #define #define #define #define #define #define #define #define #define #define #define #define configUSE_PREEMPTION configUSE_IDLE_HOOK configUSE_TICK_HOOK configTICK_RATE_HZ configMAX_PRIORITIES configMINIMAL_STACK_SIZE configTOTAL_HEAP_SIZE configMAX_TASK_NAME_LEN configUSE_TRACE_FACILITY configUSE_16_BIT_TICKS configIDLE_SHOULD_YIELD configUSE_MUTEXES 1 1 0 ( ( ( ( ( 1 0 1 1

( portTickType ) 100 ) ( unsigned portBASE_TYPE ) 64 ) ( unsigned portSHORT ) 64 ) ( size_t ) 32000 ) 16 )

/* Co-routine definitions. */ #define configUSE_CO_ROUTINES #define configMAX_CO_ROUTINE_PRIORITIES

0 ( 2 )

/* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ #define #define #define #define #define #define #define #define INCLUDE_vTaskPrioritySet INCLUDE_uxTaskPriorityGet INCLUDE_vTaskDelete INCLUDE_vTaskCleanUpResources INCLUDE_vTaskSuspend INCLUDE_vTaskDelayUntil INCLUDE_vTaskDelay INCLUDE_xTaskGetCurrentTaskHandle 1 1 1 0 1 1 1 1

Listing 5 FreeRTOSConfig.h header file located in <qp>\ports\arm\freertos\iar\ directory. (1) QP can work with either preemptive or cooperative kernel. In this QDK FreeRTOS.org is configured to operate in preemptive mode. Copyright Quantum Leaps, LLC. All Rights Reserved. 15 of 32

QDK FreeRTOS.org www.state-machine.com/freertos (2) QP uses the FreeRTOS.org idle hook to implement software tracing (Q-SPY). (3) The time tick hook is not used, because the modified FreeRTOS port leaves the system clock tick interrupt to be implemented at the application level (see Section 3). The application then is responsible to place the QF_tick() call inside the system clock tick ISR (e.g., see Section ???). (4) The system clock tick rate is only necessary to build FreeRTOS, but is not relevant for QP. (5) The number of FreeRTOS.org priorities is configured to the maximum number of active objects supported in QP, because each active object in QP assumes a unique priority level. This is an unusually high number of priorities for FreeRTOS, which supports priority sharing. This number can be reduced to save RAM. NOTE: You can reduce configMAX_PRIORITIES to save RAM.

4.2 The qep_port.h Header File


The only platform-specific aspect used inside the QEP event processor is exact-width integer types. The IAR compiler is C99-compliant compiler and provides the standard <stdint.h> header file. #include <stdint.h> #include "qep.h" /* exact-width integers, WG14/N843 C99, 7.18.1.1 */ /* QEP platform-independent public interface */

Listing 6 The mechanism of allocating and accessing data in ROM in qep_port.h

NOTE: The standard exact-width integer types are closely related to the FreeRTOS.org data types portCHAR, portSHORT, and portLONG (see Listing 3). For pre-standard compilers (no standard <stdint.h> file), it would be very convenient to define standard exact-width types in terms of portCHAR, portSHORT, and portLONG, thus making the qep_port.h header file adapt automatically to any FreeRTOS.org port. However, the FreeRTOS.org documentation is not clear about the semantics of portCHAR, portSHORT, and portLONG, so its not clear if they correspond to the standard types int8_t, int16_t, and int32_t, respectively.

4.3 The qf_port.h Header File


The QF header file for the FreeRTOS port to STR91x with the IAR compiler is located in <qp>\ports\arm\freertos\iar\qf_port.h. This QF port is generic, because all platform-specific elements are defined in terms of FreeRTOS.org. Typically, you should not need to modify the qf_port.h header file to adapt it to a different CPU or compiler. The complete qf_port.h header file is shown in Listing 7. The subsections following the listing explain how QF integrates with FreeRTOS.org. NOTE: Porting of QF to third-party RTOS is explained in Chapter 9 of [PSiCC2].

(1) #define QF_EQUEUE_TYPE (2) #define QF_THREAD_TYPE

/* FreeRTOS.org event queue and thread types */ xQueueHandle xTaskHandle

/* The maximum number of active objects in the application */ Copyright Quantum Leaps, LLC. All Rights Reserved. 16 of 32

QDK FreeRTOS.org www.state-machine.com/freertos #define QF_MAX_ACTIVE (3) /* #define QF_INT_KEY_TYPE */ (4) #define QF_INT_LOCK(dummy) (5) #define QF_INT_UNLOCK(dummy) (6) #include "FreeRTOS.h" (7) #include "task.h" (8) #include "queue.h" (9) (10) (11) (12) #include #include #include #include "qep_port.h" "qmpool.h" "qequeue.h" "qf.h" 63 /* FreeRTOS critical section operations */ portENTER_CRITICAL() portEXIT_CRITICAL() /* FreeRTOS.org master include file */ /* FreeRTOS.org task management */ /* FreeRTOS.org queue management */ /* QEP port /* FreeRTOS uses native QF memory-pool /* native QF event queue for deferring events /* QF platform-independent public interface */ */ */ */

/***************************************************************************** * interface used only inside QF, but not in applications */ /* native QF event pool operations */ (13) #define QF_EPOOL_TYPE_ QMPool #define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_) \ QMPool_init(&(p_), poolSto_, poolSize_, evtSize_) #define QF_EPOOL_EVENT_SIZE_(p_) ((p_).blockSize) #define QF_EPOOL_GET_(p_, e_) ((e_) = (QEvent *)QMPool_get(&(p_))) #define QF_EPOOL_PUT_(p_, e_) (QMPool_put(&(p_), e_)) Listing 7 The qf_port.h header file with the generic QF port to FreeRTOS.org.

4.3.1 The Active Object Event Queue and Thread


As shown in Listing 7(1-2), QF uses the FreeRTOS.org message queue as event queue for active objects (accessed via xQueueHandle) and each active object executes in a separate FreeRTOS.org task (accessed via xTaskHandle).

4.3.2 The QF Critical Section


The most important aspect of the port is the interrupt locking/unlocking policy (QF critical section), which is defined in Listing 7(3-5). The QF critical section is defined in terms of the FreeRTOS.org critical section. NOTE: The FreeRTOS.org critical section mechanism allows for nesting critical sections.

4.3.3 FreeRTOS.org Include Files


To compile QP, the qf_port.h header file must include the following FreeRTOS.org include files: FreeRTOS.h, task.h, and queue.h, as shown in Listing 7(6-8).

4.3.4 QP Include Files


The qf_port.h header file includes the QEP port, native QF memory pool, raw event queue for deferring events, and the platform-independent QF interface, as shown in Listing 7(9-12).

Copyright Quantum Leaps, LLC. All Rights Reserved.

17 of 32

QDK FreeRTOS.org www.state-machine.com/freertos

4.3.5 Memory Pool


FreeRTOS.org does not provide a fast and deterministic memory pool for events. The QF port uses the native QF memory pool, as shown in Listing 7(10, 13).

4.4 The qf_port.c Source File


The QF port to FreeRTOS.org, as most QF ports to third-party RTOSs, require some glue-code to bolt the framework to the external RTOS. You place such code in the qf_port.c source file, which is located in <qp>\ports\arm\freertos\iar\src\, as shown in Listing 8. You typically dont need to change this file for different FreeRTOS.org ports. #include "qf_pkg.h" #include "qassert.h" Q_DEFINE_THIS_MODULE(qf_port) /* Global objects ----------------------------------------------------------*/ /*..........................................................................*/ char const Q_ROM * Q_ROM_VAR QF_getPortVersion(void) { static const char Q_ROM Q_ROM_VAR version[] = "4.0.01"; return version; } /*..........................................................................*/ void QF_init(void) { /* no special initialization required by FreeRTOS.org */ } /*..........................................................................*/ void QF_run(void) { vTaskStartScheduler(); /* start the FreeRTOS.org scheduler */ Q_ERROR(); /* the FreeRTOS.org scheduler should never return */ } /*..........................................................................*/ void QF_stop(void) { } /*..........................................................................*/ static __arm void task_function(void *pvParameters) { /* FreeRTOS signature */ ((QActive *)pvParameters)->running = (uint8_t)1; /* enable thread-loop */ while (((QActive *)pvParameters)->running) { QEvent const *e = QActive_get_((QActive *)pvParameters); QF_ACTIVE_DISPATCH_(&((QActive *)pvParameters)->super, e); QF_gc(e); /* check if the event is garbage, and collect it if so */ } QF_remove_((QActive *)pvParameters); /* remove AO from the framework */ vTaskDelete(((QActive *)pvParameters)->thread); /* delete FreeRTOS task */

(1)

(2) (3)

(4) (5) (6) (7) (8) (9) (10) (11) (12)

} /*..........................................................................*/ void QActive_start(QActive *me, uint8_t prio, QEvent const *qSto[], uint32_t qLen, void *stkSto, uint32_t stkSize, QEvent const *ie) { portBASE_TYPE err; unsigned portBASE_TYPE freeRTOS_prio; Q_REQUIRE((qSto == (QEvent const **)0) && (qLen > 0) && (stkSto == (void *)0) && (stkSize > 0)); me->eQueue = xQueueCreate(qLen, sizeof(QEvent*)); /* create event queue */ 18 of 32

(13) (14) (15)

Copyright Quantum Leaps, LLC. All Rights Reserved.

QDK FreeRTOS.org www.state-machine.com/freertos (16) (17) (18) (19) Q_ASSERT(me->eQueue != (xQueueHandle)0); /* FreeRTOS queue created me->prio = prio; /* save the QF priority QF_add_(me); /* make QF aware of this active object QF_ACTIVE_INIT_(&me->super, ie); /* execute initial transition QS_FLUSH(); (20) (21) */ */ */ */

/* flush the trace buffer to the host */ */ */ */ */ */ */ */ */ */

(22)

freeRTOS_prio = tskIDLE_PRIORITY + me->prio; /* FreeRTOS task priority /* create the FreeRTOS.org task for the AO err = xTaskCreate(&task_function, /* the task function (signed portCHAR *)"AO", /* the name of the task (unsigned portSHORT)stkSize/sizeof(portSTACK_TYPE), /* stack me, /* the 'pvParameters' parameter freeRTOS_prio, /* FreeRTOS task priority &me->thread); /* task handle Q_ASSERT(err == pdPASS); /* FreeRTOS.org task created

(23) (24)

(25) (26)

} /*..........................................................................*/ void QActive_stop(QActive *me) { me->running = (uint8_t)0; /* stop the thread loop */ vQueueDelete(me->eQueue); /* cleanup the queue */ } /*..........................................................................*/ void QActive_postFIFO(QActive *me, QEvent const *e) { portBASE_TYPE err; QF_INT_LOCK_KEY_ QF_INT_LOCK_(); if (e->dynamic_ != (uint8_t)0) { ++((QEvent *)e)->dynamic_; } QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_POST_FIFO, QS_aoObj_, me) QS_TIME_(); /* timestamp QS_SIG_(e->sig); /* the signal of the event QS_OBJ_(me); /* this active object QS_U8_(e->dynamic_); /* the dynamic attribute of the event QS_EQC_(0); /* number of free entries (unknown) QS_EQC_(0); /* min number of free entries (unknown) QS_END_NOLOCK_() */ */ */ */ */ */

(27) (28)

(29) (30)

} /*..........................................................................*/ void QActive_postLIFO(QActive *me, QEvent const *e) { portBASE_TYPE err; QF_INT_LOCK_KEY_ QF_INT_LOCK_(); if (e->dynamic_ != (uint8_t)0) { ++((QEvent *)e)->dynamic_; } QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_POST_LIFO, QS_aoObj_, me) QS_TIME_(); /* timestamp QS_SIG_(e->sig); /* the signal of the event QS_OBJ_(me); /* this active object QS_U8_(e->dynamic_); /* the dynamic attribute of the event */ */ */ */ 19 of 32

QF_INT_UNLOCK_(); if (ulInterruptNesting == (unsigned portLONG)0) { /* task level? */ err = xQueueSendToBack(me->eQueue, &e, (portTickType)0); } else { /* must be ISR level */ portBASE_TYPE xHigherPriorityTaskWoken; err = xQueueSendToBackFromISR(me->eQueue, &e, &xHigherPriorityTaskWoken); } Q_ASSERT(err == pdPASS);

Copyright Quantum Leaps, LLC. All Rights Reserved.

QDK FreeRTOS.org www.state-machine.com/freertos QS_EQC_(0); QS_EQC_(0); QS_END_NOLOCK_() /* number of free entries (unknown) */ /* min number of free entries (unknown) */

} /*..........................................................................*/ QEvent const *QActive_get_(QActive *me) { QEvent const *e; /* wait indefinitely, INCLUDE_vTaskSuspend must be set to '1' */ (31) Q_ALLEGE(xQueueReceive(me->eQueue, &e, portMAX_DELAY) == pdPASS); QS_BEGIN_(QS_QF_ACTIVE_GET, QS_aoObj_, me) QS_TIME_(); /* timestamp QS_SIG_(e->sig); /* the signal of this event QS_OBJ_(me); /* this active object QS_U8_(e->dynamic_); /* the dynamic attribute of the event QS_EQC_(0); /* number of free entries (unknown) QS_END_() return e; } Listing 8 The qf_port.c source file for the FreeRTOS.org port. (1) The function QF_init() initializes the framework. In the case of QF port to FreeRTOS.org, the function has nothing to do. (2-3) The function QF_run() transfers control to the framework to run the application. In the case of QF port to FreeRTOS.org, the function starts multitasking by the FreeRTOS call vTaskStartScheduler(). (4) The function QF_stop() stops the framework. There is nothing you can do to stop FreeRTOS.org, you simply abort. Therefore the only action is to call the cleanup callback. (5) Under a traditional RTOS, all active object threads execute the same function task_function(), which is always structured as an endless loop. The task function has the exact signature expected by FreeRTOS.org. The parameter pvParameters is set to the active object owning in the task. NOTE: The original FreeRTOS.org port can be configured to execute tasks either in ARM (default) or THUMB. The __arm keyword in front of the task function means that QF port assumes that all FreeRTOS.org tasks will be executed in the ARM state. (6) The task function sets the QActive.running flag to continue the local event loop. (7) The event loop continues as long as the QActive.running flag is set. (8-10) These are the three steps of the active object thread (waiting for an event, dispatching the event, and recycling the event, see Chapter 7 in [PSiCC2]). (11) After the event loop terminates, the active object is removed from the framework. 20 of 32 */ */ */ */ */

QF_INT_UNLOCK_(); if (ulInterruptNesting == (unsigned portLONG)0) { /* task level? */ err = xQueueSendToFront(me->eQueue, &e, (portTickType)0); } else { /* must be ISR level */ portBASE_TYPE xHigherPriorityTaskWoken; err = xQueueSendToFrontFromISR(me->eQueue, &e, &xHigherPriorityTaskWoken); } Q_ASSERT(err == pdPASS);

Copyright Quantum Leaps, LLC. All Rights Reserved.

QDK FreeRTOS.org www.state-machine.com/freertos (12) The task is deleted by the FreeRTOS.org call vTaskDelete().

(13-14) The assertions makes sure that neither event queue storage nor the stack storage are provided by the caller, because FreeRTOS.org allocates the storage internally. (15) The first step in starting an active object is creating the event queue by the FreeRTOS.org call xQueueCreate(). (16) (17) (18) (19) (20) The queue creation must be successful, otherwise the application cannot continue. The active objects priority is set. The active object is registered with the QF framework. The active objects state machine is initialized. The QF priority is mapped to the C/OS-II task priority.

FreeRTOS.org uses a priority numbering scheme in which tskIDLE_PRIORITY represents the lowest possible priority assigned to the idle task, and higher numerical values represent higher task urgency. This happens to be very similar priority numbering as used in the QF framework. (21) The active object thread is created by the FreeRTOS.org call xTaskCreate().

NOTE: Traditional RTOSs, such as FreeRTOS.org, require per-task stacks. The size of the size is provided in the stkSize parameter, but FreeRTOS allocates the stack storage internally, so the parameter stkSto is not used. (22) The task creation must be successful, otherwise the application cannot continue.

(23) Clearing the QActive.running flag terminates the event loop and exits the active object thread (see line (6)). (24) The event queue is deleted by the FreeRTOS.org call vQueueDelete().

The QF port to FreeRTOS.org does not use the native QF active object queues. Therefore, the QF implementation of QActive_postFIFO(), QActive_postLIFO(), and QActive_get_() must be replaced by the FreeRTOS-specific code. The rest of the qf_port.c source file defines these three functions for FreeRTOS.org (see also Chapter 8 in [PSiCC2]). (25-26) Posting an event to a queue must always increment the reference counter of a dynamic event. This must happen exactly as shown. (27) The choice of the right FreeRTOS.org API to post an event to the queue depends on the context (interrupt nesting of zero indicates task level, otherwise it is the ISR level). As described in Section 3.1, FreeRTOS.org requires using different APIs when accessing a queue from an ISR or from a task. Therefore the function QActive_postFIFO() must distinguish between these two contexts to use the correct FreeRTOS.org API. This determination is based on the ulInterruptNesting variable introduced in the augmented FreeRTOS.org port (again see Section 3.1) NOTE: The variable ulInterruptNesting will distinguish correctly between the ISR and the task contexts only when all ISRs, without exceptions, consistently call the macros portISR_ENTRY() upon entry and portISR_EXIT() upon the exit. Copyright Quantum Leaps, LLC. All Rights Reserved. 21 of 32

QDK FreeRTOS.org www.state-machine.com/freertos (28) In the task level, the pointer to the event is posted to the FreeRTOS.org message queue with the call xQueueSendToBack(), which uses the standard FIFO policy. The queue is not supposed to block if it cannot accept the message (event pointer). (29) In the ISR level, the pointer to the event is posted to the FreeRTOS.org message queue with the call xQueueSendToBackFromISR(), which uses the standard FIFO policy. (30) The assertion makes sure that the event is posted successfully. (31) The event is retrieved from the message queue with the FreeRTOS.org call xQueueReceive(). The second argument to this function is the timeout, whereas timeout of portMAX_DELAY indicates indefinite waiting on an empty event queue. The Q_ALLEGE() macro surrounding the FreeRTOS call asserts that the receive operation executed successfully.

4.5 ARM/THUMB Compilation


Contrary to some misconceptions THUMB code is not inherently slower than ARM. To the contrary, the higher code density of the THUMB instruction set often makes it actually execute faster. Most QP source files (.C files) that comprise the QP libraries (linked later statically with the applications) can be compiled either to ARM or THUMB. NOTE: The QP libraries as well as application code must be compiled with the ARM/THUMB interworking enabled (IAR option -interwork). Generally, code that must often lock/unlock interrupts, or the code that can be executed in the ISR context (both requires ARM instruction set) is certainly faster if compiled to ARM. Therefore, most of the QF modules as well as FreeRTOS modules are compiled to ARM. On the other hand, the QEP event processor, and consequently all state machines in the system (active objects) should be compiled to THUMB.

Copyright Quantum Leaps, LLC. All Rights Reserved.

22 of 32

QDK FreeRTOS.org www.state-machine.com/freertos

5 The Example QP Application


The QP port to FreeRTOS.org has been tested with the Dining Philosopher Problem (DPP) application described in the Application Note Dining Philosophers Application [QL AN-DPP 08]. The standard DPP application has been augmented to demonstrate an independent FreeRTOS.org task executing outside of the QP framework. The QP example is located in the directory <qp>\examples\arm\freertos\iar\dpp-str92-sk\.

5.1 The main() Function


The main() function of the DPP example for FreeRTOS.org is shown in Listing 9. The function has the very standard structure for any QP application, as described in Chapter 1 of [PSiCC2] and also in the online QP Tutorial [QP/C 08]. #include #include #include #include "qp_port.h" "dpp.h" "bsp.h" "freertos_task.h" /* the prototype of the FreeRTOS.h task function */

/* Local-scope objects -----------------------------------------------------*/ static QSubscrList l_subscrSto[MAX_PUB_SIG]; static union SmallEvent { void *min_size; TableEvt te; /* other event types to go into this pool */ } l_smlPoolSto[2*N_PHILO]; /* storage for the small event pool */ /*..........................................................................*/ __arm void main(void) { uint8_t n; Philo_ctor(); Table_ctor(); BSP_init(); QF_init(); /* instantiate all Philosopher active objects */ /* instantiate the Table active object */ /* initialize the Board Support Package */ /* initialize the framework and the underlying RT kernel */ /* object dictionaries... */ QS_OBJ_DICTIONARY(l_smlPoolSto); QF_psInit(l_subscrSto, Q_DIM(l_subscrSto)); /* init publish-subscribe */

/* initialize event pools... */ QF_poolInit(l_smlPoolSto, sizeof(l_smlPoolSto), sizeof(l_smlPoolSto[0])); for (n = 0; n < N_PHILO; ++n) { /* start the active objects... */ QActive_start(AO_Philo[n], (uint8_t)(n + 1), (QEvent const **)0, N_PHILO, (void *)0, (configMINIMAL_STACK_SIZE * sizeof(portSTACK_TYPE)), (QEvent *)0); } QActive_start(AO_Table, (uint8_t)(N_PHILO + 1), (QEvent const **)0, N_PHILO, (void *)0, (configMINIMAL_STACK_SIZE * sizeof(portSTACK_TYPE)), (QEvent *)0); /* create a raw FreeRTOS task, not managed by QP */ xTaskCreate(&vTaskFunction, (signed portCHAR *)"TASK", Copyright Quantum Leaps, LLC. All Rights Reserved. 23 of 32

QDK FreeRTOS.org www.state-machine.com/freertos configMINIMAL_STACK_SIZE, (void *)0, tskIDLE_PRIORITY + N_PHILO + 2, (xTaskHandle *)0); QF_run(); } Listing 9 The main() function of the DPP application with FreeRTOS.org task. The only significant differences from the main() function without FreeRTOS.org is creating the raw FreeRTOS.org task shown in bold in Listing 9. Also, you dont need to allocate storage for event queues and stacks of active object tasks, because FreeRTOS.org allocates this storage internally. /* run the QF application (never returns) */

5.2 ISRs
The ISRs in the DPP application for FreeRTOS.org are located in the Board Support Package (file bsp.c) and are structured as described in Section 3.1. /* ISRs --------------------------------------------------------------------*/ (1) __arm void TIM3_IRQHandler(void) { (2) portISR_ENTRY(); /* always inform FreeRTOS about entering an ISR */ (3) (4) TIM3->OC1R += BSP_TIM3_PERIOD - 1; TIM3->SR &= ~TIM_IT_OC1; /* set the output compare register */ /* clear interrupt source (Timer3) */

(5) #ifdef Q_SPY { uint16_t currTime16 = (uint16_t)TIM3->CNTR; l_currTime32 += (currTime16 - l_prevTime16) & 0xFFFF; l_prevTime16 = currTime16; } #endif (6) (7) (8) } vTaskIncrementTick(); QF_tick(); portISR_EXIT(); /* handle the FreeRTOS.org system clock tick */ /* handle the QF system clock tick */ /* always inform FreeRTOS about exiting an ISR */

Listing 10 System time tick interrupt (Timer 3). (1) In the FreeRTOS.org port, ISRs are regular C functions (no __irq functions), because ISRs are actually called from an assembler wrapper interrupt handler linked to the address 0x18. This particular BSP uses the Output Compare interrupt of Timer 3 as the source for the system clock tick ISR. (2) As described in Section 3.1, every ISR must start with calling the macro portISR_ENTRY(). (3) The Output Compare register must be incremented to ensure that the free-running timer will reach the next deadline in the desired time. (4) The interrupt source (Timer 3 output compare) is then cleared. (5) When the QS software tracing is active, the ISR updates the internal counters, which allow extending the 16-bit free-running Timer 3 to 32-bits to accurately time stamp the trace records. (6) The system clock tick ISR must invoke the FreeRTOS.org vTaskIncrementTick() function to manage timeouts and time delays. Copyright Quantum Leaps, LLC. All Rights Reserved. 24 of 32

QDK FreeRTOS.org www.state-machine.com/freertos (7) The system clock tick ISR must also invoke QF_tick() to manage all armed time events (timers) in the QP application. (8) As described in Section 3.1, every ISR must end with calling the macro portISR_EXIT().

5.3 Starting Interrupts in vStartInterrupts()


As described in Section 3.4, the augmented FreeRTOS.org port calls the function vStartInterrupts(), just before starting the idle task. The vStartInterrupts() function is designed to start the interrupts, including the system clock tick interrupt. In this BSP only the timer tick interrupt is started.. void vStartInterrupts(void) { TIM_InitTypeDef TIM_InitStruct; /* called with interrupts locked */

SCU_APBPeriphClockConfig(__TIM23, ENABLE); TIM_DeInit(TIM3); TIM_StructInit(&TIM_InitStruct); TIM_InitStruct.TIM_Mode TIM_InitStruct.TIM_OC1_Modes TIM_InitStruct.TIM_Clock_Source TIM_InitStruct.TIM_Clock_Edge TIM_InitStruct.TIM_Prescaler TIM_InitStruct.TIM_Pulse_Level_1 TIM_InitStruct.TIM_Pulse_Length_1 TIM_Init(TIM3, &TIM_InitStruct); = = = = = = = TIM_OCM_CHANNEL_1; TIM_TIMING; TIM_CLK_APB; TIM_CLK_EDGE_RISING; BSP_TIM3_PRESCALER - 1; TIM_HIGH; BSP_TIM3_PERIOD - 1;

/* configure the VIC for the TIM3 interrupt */ VIC_Config(TIM3_ITLine, VIC_IRQ, BSP_TICK_PRIO); VIC_ITCmd(TIM3_ITLine, ENABLE); TIM_ITConfig(TIM3, TIM_IT_OC1, ENABLE); TIM_CounterCmd(TIM3, TIM_CLEAR); TIM_CounterCmd(TIM3, TIM_START);

5.4 Idle Processing in vApplicationIdleHook()


FreeRTOS.org allows to add idle processing to the application through the hook (callback) function vApplicationIdleHook(). In the DPP application, the idle hook is used to output the software trace data to the host (see the next section). The callback can also be used to place the MCU in a lowpower sleep mode to conserve power. NOTE: The STR912F device used in the STR912-SK board supports the Idle and Stop lowpower modes. However, when the device is placed in one of these modes, the JTAG debugger stops working and its extremely difficult to get control of the device again. Therefore the transition low-power mode is commented out in the vApplicationIdleHook() callback. void vApplicationIdleHook(void) { (1) (2) (3) (4) portDISABLE_INTERRUPTS(); LED_ON(16); LED_OFF(16); portENABLE_INTERRUPTS(); 25 of 32

Copyright Quantum Leaps, LLC. All Rights Reserved.

QDK FreeRTOS.org www.state-machine.com/freertos (5) #ifdef Q_SPY /* use the idle cycles for QS transmission if ((UART0->FR & 0x80) != 0) { /* TX FIFO empty? uint16_t nBytes = BSP_UART_TX_FIFO; /* capacity of the TX FIFO uint8_t const *block; QF_INT_LOCK(dummy); block = QS_getBlock(&nBytes); /* get the data block to transfer QF_INT_UNLOCK(dummy); while (nBytes-- != 0) { UART0->DR = *block++; /* stick the byte to the TX FIFO } } #elif defined NDEBUG /* only if not debugging (Release configuraion) /* shut down unused peripherals to save power ...*/ (6) // SCU_EnterIdleMode(); /* Power-Management: disable the CPU clock // NOTE: idle or sleep mode hangs the J-TAG, it's difficult to // get control of the MCU again!!! #endif } Listing 11 vApplicationIdleHook() in the file bsp.c (1-4) In order to see the activity of the idle task, the idle hook turns LED 16 on and off. These operations occur inside a critical section so that the intensity of the LED accounts only for the frequency of the calls to the idle hook, but not to preemptions by ISRs and tasks. (5) The idle hook performs QS data ouptu to the host (see the next section). (6) The ST driver function SCU_EnterIdleMode() puts the MCU in the low-power idle mode. However, as described above, the idle mode interferes with the J-TAG debugger and thats why it is commented out. */ */ */ */ */ */ */

5.5 Assertion Handling Policy in Q_onAssert()


As described in Chapter 6 of [PSiCC2], all QP components use internally assertions to detect errors in the way application is using the QP services. You need to define how the application reacts in case of assertion failure by providing the callback function Q_onAssert(). Typically, you would put the system in fail-safe state and try to reset. It is also a good idea to log some information as to where the assertion failed. The following code fragment shows the Q_onAssert() callback in the bsp.c file. The function simply locks all interrupts and enters a for-ever loop. This policy is only adequate for testing, but probably is not adequate for the final production release. __arm void Q_onAssert(char const Q_ROM * const Q_ROM_VAR file, int line) { __disable_interrupt(); /* make sure that all interrupts are disabled */ LED_ON_ALL(); /* light up all LEDs */ for (;;) { /* hang here in the for-ever loop */ } } NOTE: You must carefully design the appropriate course of action in Q_onAssert() for your final production release. Generally, Q_onAssert() should try to put the device in a fail-safe state.

Copyright Quantum Leaps, LLC. All Rights Reserved.

26 of 32

QDK FreeRTOS.org www.state-machine.com/freertos

6 The Quantum Spy (QS) Instrumentation


This QDK demonstrates how to use the Quantum Spy (QS) to generate real-time trace of a running QP application. Normally, the QS instrumentation is inactive and does not add any overhead to your application, but you can turn the instrumentation on by defining the Q_SPY macro and recompiling the code. Quantum Spy (QS) is a software tracing facility built into all QP components and also available to the Application code. QS allows you to gain unprecedented visibility into your application by selectively logging almost all interesting events occurring within state machines, the framework, the kernel, and your application code. QS software tracing is minimally intrusive, offers precise timestamping, sophisticated runtime filtering of events, and good data compression (see Chapter 11 in PSiCC2 [PSiCC2]). QS can be configured to send the real-time data out of the serial port of the target device. On the STR912F MCU, QS uses the built-in USART0 to send the trace data out (see Figure 1), so the QSPY host application can conveniently receive the trace data on the host PC. The complete implementation of the QS software-tracing output consists of several steps, which are all summarized in Listing 12 (file bsp.c). (1) #ifdef Q_SPY (2) static uint32_t l_currTime32; (3) static uint16_t l_prevTime16; (4) enum AppRecords { PHILO_STAT = QS_USER }; #endif

/* application-specific trace records */

/*--------------------------------------------------------------------------*/ #ifdef Q_SPY (5) uint8_t QS_onStartup(void const *arg) { (6) static uint8_t qsBuf[BSP_QS_BUF_SIZE]; /* buffer for Quantum Spy */ GPIO_InitTypeDef GPIO_InitStruct; UART_InitTypeDef UART_InitStruct; (7) (8) (9) (10) (11) (12) QS_initBuf(qsBuf, sizeof(qsBuf)); /* configure the UART0 for QSPY output ... */ SCU_APBPeriphClockConfig(__UART0, ENABLE); /* enable clock for UART0 */ SCU_APBPeriphClockConfig(__GPIO3, ENABLE); /* enable clock for GPIO3 */ SCU_APBPeriphReset(__UART0, DISABLE); SCU_APBPeriphReset(__GPIO3, DISABLE); /* remove UART0 from reset */ /* remove GPIO3 from reset */

/* configure UART0_TX pin GPIO3.4 ... */ GPIO_DeInit(GPIO3); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; GPIO_InitStruct.GPIO_Direction = GPIO_PinOutput; GPIO_InitStruct.GPIO_Type = GPIO_Type_PushPull; GPIO_InitStruct.GPIO_IPConnected = GPIO_IPConnected_Disable; GPIO_InitStruct.GPIO_Alternate = GPIO_OutputAlt3; GPIO_Init(GPIO3, &GPIO_InitStruct); /* configure UART0... */ UART_DeInit(UART0); /* force UART0 registers to reset values */ UART_InitStruct.UART_WordLength = UART_WordLength_8D; UART_InitStruct.UART_StopBits = UART_StopBits_1; UART_InitStruct.UART_Parity = UART_Parity_No; UART_InitStruct.UART_BaudRate = BSP_QS_BAUD_RATE; UART_InitStruct.UART_HardwareFlowControl = UART_HardwareFlowControl_None; 27 of 32

(13)

Copyright Quantum Leaps, LLC. All Rights Reserved.

QDK FreeRTOS.org www.state-machine.com/freertos UART_InitStruct.UART_Mode = UART_Mode_Tx; UART_InitStruct.UART_FIFO = UART_FIFO_Enable; UART_InitStruct.UART_TxFIFOLevel = UART_FIFOLevel_1_8; UART_InitStruct.UART_RxFIFOLevel = UART_FIFOLevel_1_8; UART_Init(UART0, &UART_InitStruct); /* initialize UART0 */ UART_Cmd(UART0, ENABLE); /* enable UART0 */ (14) QS_FILTER_ON(QS_ALL_RECORDS); QS_FILTER_OFF(...); ... /* setup the QS filters... */

(15) (16)

(17) (18) (19) (20) (21) (22) (23) (24) (25)

return (uint8_t)1; /* indicate successfull QS initialization */ } /*..........................................................................*/ void QS_onCleanup(void) { } /*..........................................................................*/ /* NOTE: getTime is invoked within a critical section (inetrrupts disabled) */ uint32_t QS_onGetTime(void) { uint16_t currTime16 = (uint16_t)TIM3->CNTR; l_currTime32 += (currTime16 - l_prevTime16) & 0xFFFF; l_prevTime16 = currTime16; return l_currTime32; } /*..........................................................................*/ void QS_onFlush(void) { uint16_t nBytes = BSP_UART_TX_FIFO; /* the capacity of the UART TX FIFO */ uint8_t const *block; while ((block = QS_getBlock(&nBytes)) != (uint8_t *)0) { while ((UART0->FR & 0x80) == 0) { /* TX FIFO not empty? */ } /* keep waiting... */ while (nBytes-- != 0) { UART0->DR = *block++; /* stick the byte to the TX FIFO */ } nBytes = BSP_UART_TX_FIFO; /* for the next time around */ } } #endif /* Q_SPY */ /*--------------------------------------------------------------------------*/

Listing 12 QS implementation to send data out of the UART0 of the STR912 device. (1) The QS instrumentation is enabled only when the macro Q_SPY is defined (2) The static l_currTime32 variable is used to hold the 32-bit-wide timestamp. (3) The static l_prevTime16 variable is used to hold the last 16-bit-wide reading of the free-running 16-bit Timer 3 (the same used to generate the system clock tick interrupt). (4) This enumeration defines application-specific QS trace record(s), to demonstrate how to use them. (5) You need to define the QS_onStartup() callback to initialize the QS software tracing. (6) You should adjust the QS buffer size (in bytes) to your particular application (7) You always need to call QS_initBuf() from QS_onStartup() to initialize the trace buffer. (8-9) The clock to the UART0 peripheral is enabled. Also, the clock to the GPIO3 peripheral is enabled. GPIO3 controls the UART0 transmit and receive pins. (10-11) The UART0 and GPIO3 peripherals are removed from reset.

Copyright Quantum Leaps, LLC. All Rights Reserved.

28 of 32

QDK FreeRTOS.org www.state-machine.com/freertos (12) The transmit pin GPIO3.4 is configured as output, alternative function 3 (UART0 Tx) using the ST driver library interface. (13) The UART0 is not properly configured using the ST driver library interface. (14) The QS filters are setup (see Chapter 11 in [PSiCC2] as well as QP Reference Manual online). (15) The QS_onStartup() callback returns 1, meaning that the QS initialization was successful. (16) The QS_onCleanup() callback is empty for MSP430 (the application never exits). (17-21) The QS_onGetTime() callback provides a fine-granularity timestamp. The timestamp is discussed in the next section. (22) The QS_onFlush() callback flushes the QS trace buffer to the host. Typically, the function busywaits for the transfer to complete. It is only used in the initialization phase for sending the QS dictionary records to the host. (23) The implementation of QS for STR912 uses the block-oriented QS-buffer interface QS_getBlock(), which provides up to 16 bytes to fill the FIFO of the UART (see Chapter 11 in [PSiCC2]). (24) The QS_onFlush() callback busy-waits in-line until the transmit buffer is empty. (25) The data byte is inserted into the UART0 data register.

6.1 QS Time Stamp Callback QS_onGetTime()


The platform-specific QS port must provide function QS_onGetTime() (Listing 12(17-21)) that returns the current time stamp in 32-bit resolution. To provide such a fine-granularity time stamp, the BSP uses the free running Timer 3, which is the same timer already used for generation of the system clock-tick interrupt. NOTE: The QS_onGetTime() callback is always called with interrupts locked. Figure 6 shows how the Timer 3 Count Register (TIM3->CNTR) reading is extended to 32 bits. The drawing below shows a free running Timer 3 Count Register (TIM3->CNTR) that counts up from 0 to 0xFFFF and rolls over to 0. If the system tick rate is faster than the rollover rate then you could oversample this free-running timer by reading it in the clock tick ISR, as shown in Listing 10(5). The 32-bit variable l_currTime32 contains the sum of the 16-bit deltas from each readout of the free running Timer 3 Count Register. Because of unsigned 16-bit arithmetic used in Listing 12(19), even a small current value minus a large previous value still results in the proper delta. Note that QS_onGetTime() can actually be called at just about any time and thus, also needs to update l_currTime32 before it returns the current value.

Copyright Quantum Leaps, LLC. All Rights Reserved.

29 of 32

QDK FreeRTOS.org www.state-machine.com/freertos


count 32-bit time stamp returned from QS_onGetTime()

System clock tick period

TIM3->CNTR Register 0xFFFF

0x0000

System clock-tick

time

Figure 6 Using the Timer 3 Count Register to provide 32-bit QS time stamp.

6.2 Invoking the QSpy Host Application


The QSPY host application receives the QS trace data, parses it and displays on the host workstation (currently Windows or Linux). For the configuration options chosen in this port, you invoke the QSPY host application as follows (please refer to the QSPY section in the QP Reference Manual): qspy c COM1 b 115200

Copyright Quantum Leaps, LLC. All Rights Reserved.

30 of 32

QDK FreeRTOS.org www.state-machine.com/freertos

7 Related Documents and References


Document [Samek 08] Practical UML Statecharts in C/C++, Second Edition: Event Driven Programming for Embedded Systems, Miro Samek, Newnes, 2008 [QP/C 08] QP/C Reference Manual, Quantum Leaps, LLC, 2008 [FeeRTOS.org 08] FreeRTOS online documentation. [QP/C++ 08] QP/C++ Reference Manual, Quantum Leaps, LLC, 2008 [QL AN-Directory 07] Application Note: QP Directory Structure, Quantum Leaps, LLC, 2007 [QL AN-DPP 08] Application Note: Dining Philosophers Application, Quantum Leaps, LLC, 2008 STR91xFA ARM9-based microcontroller family, ST Microelectronics, April 2008 ARM IAR C/C++ Guide, IAR Systems Compiler: Reference Location Available from most online book retailers, such as amazon.com. See also: http://www.quantumleaps.com/writings/psicc2.htm http://www.quantum-leaps.com/doxygen/qpc/ http://www.freertos.org/ http://www.quantum-leaps.com/doxygen/qpcpp/ http://www.quantumleaps.com/doc/AN_QP_Directory_Structure.pdf http://www.quantum-leaps.com/doc/AN_DPP.pdf

www.st.com/stonline/products/literature/rm/13742.pdf The PDF version of this document is included in the IAR Embedded Workbench for ARM.

Copyright Quantum Leaps, LLC. All Rights Reserved.

31 of 32

QDK FreeRTOS.org www.state-machine.com/freertos

8 Contact Information
Quantum Leaps, LLC 103 Cobble Ridge Drive Chapel Hill, NC 27516 USA +1 866 450 LEAP (toll free, USA only) +1 919 869-2998 (FAX) e-mail: info@quantum-leaps.com WEB : http://www.quantum-leaps.com http://www.state-machine.com Practical UML Statecharts in C/C++, Second Edition: Event Driven Programming for Embedded Systems, by Miro Samek, Newnes, 2008

FreeRTOS.org WEB : www.FreeRTOS.org

ARM Ltd. 110 Fulbourn Road Cambridge CB1 9NJ England Tel: (44) 01223 400400 Fax: (44) 01223 400410 WEB : www.ARM.com

Copyright Quantum Leaps, LLC. All Rights Reserved.

32 of 32

You might also like