05.11.2014 Views

QDK AVR32 UC-GNU - Quantum Leaps

QDK AVR32 UC-GNU - Quantum Leaps

QDK AVR32 UC-GNU - Quantum Leaps

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

QP state machine frameworks for AVR<br />

<strong>QDK</strong><br />

Atmel <strong>AVR32</strong><strong>UC</strong><br />

with Atmel Studio<br />

Document Revision B<br />

October 2012<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC<br />

www.quantum-leaps.com<br />

www.state-machine.com


Table of Contents<br />

1 Introduction ..................................................................................................................................................... 1<br />

1.1 About QP .................................................................................................................................................... 2<br />

1.2 About QM ................................................................................................................................................... 3<br />

1.3 About this <strong>QDK</strong> .............................................................................................................................................. 3<br />

1.4 Licensing QP .............................................................................................................................................. 4<br />

1.5 Licensing QM .............................................................................................................................................. 4<br />

2 Getting Started ................................................................................................................................................ 5<br />

2.1 Installation ...................................................................................................................................................... 5<br />

2.2 Building the QP Libraries ............................................................................................................................... 7<br />

2.3 Building the Examples .................................................................................................................................... 8<br />

2.4 Running the Examples ................................................................................................................................... 9<br />

3 The Vanilla QP Port ......................................................................................................................................... 11<br />

3.1 The qep_port.h Header File ........................................................................................................................... 11<br />

3.2 The qf_port.h Header File .............................................................................................................................. 11<br />

3.3 The <strong>AVR32</strong><strong>UC</strong> Exceptions and the qf_port.asm File ..................................................................................... 12<br />

3.4 BSP for <strong>AVR32</strong> .............................................................................................................................................. 16<br />

3.5 QP Idle Loop Customization in QF_onIdle() ................................................................................................... 17<br />

3.6 Assertion Handling Policy in Q_onAssert() .................................................................................................... 18<br />

4 The QK Port ..................................................................................................................................................... 19<br />

4.1 Single-Stack, Preemptive Multitasking on <strong>AVR32</strong><strong>UC</strong> ..................................................................................... 19<br />

4.2 The qk_port.h Header File ............................................................................................................................. 19<br />

4.3 The Low-Level Interrupt Handlers for QK (file qk_port.asm) .......................................................................... 20<br />

4.4 Idle Loop Customization in the QK_onIdle() .................................................................................................. 25<br />

5 The QS Software Tracing Instrumentation ................................................................................................... 26<br />

6 Related Documents and References ............................................................................................................. 28<br />

7 Contact Information ........................................................................................................................................ 29


1 Introduction<br />

This QP Development Kit (<strong>QDK</strong>) describes how to use the QP/C state machine framework with the<br />

Atmel <strong>AVR32</strong> <strong>UC</strong> and the Atmel Studio 6 and the <strong>GNU</strong> <strong>AVR32</strong> compiler. The actual hardware/software<br />

used to test this <strong>QDK</strong> as shown in Figure 1 and described below:<br />

Figure 1 Atmel <strong>UC</strong>3-A3-Xplained board with the AT32<strong>UC</strong>3A3256 device and JTAGICE-mkII.<br />

JTAGICE<br />

mkII<br />

JTAG<br />

connector<br />

Power<br />

from PC<br />

via USB<br />

<strong>UC</strong>3-A3-Xplained<br />

board<br />

LED0<br />

LED2<br />

LED1<br />

LED3<br />

J4<br />

RS-232<br />

to PC<br />

TTL-RS232<br />

transceiver<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

1 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

The actual hardware/software used to test this <strong>QDK</strong> is described below:<br />

1. Atmel <strong>UC</strong>3-A3-Xplained board with the AT32<strong>UC</strong>3A3256 device<br />

2. JTAGICE mkII debugger<br />

3. Atmel Studio 6.0<br />

4. <strong>AVR32</strong>-GCC for windows (bundled with Atmel Studio 6.0)<br />

5. QP/C/C++ 4.5.02 or higher and QM v 2.2.03.<br />

As shown in Figure 1, the <strong>UC</strong>3-A3-Xplained board is powered via a USB cable and is connected to the<br />

JTAG-mkII emulator via the JTAG ribbon cable. This <strong>QDK</strong> has been tested on the AT32<strong>UC</strong>3A3256 device<br />

with 64KB of RAM and 256KB of on-board flash. However, the described port should be applicable to<br />

most microcontrollers based on the <strong>AVR32</strong> <strong>UC</strong> CPU.<br />

1.1 About QP<br />

QP is a family of very lightweight, open source, state machinebased<br />

frameworks for developing event-driven applications. QP<br />

enables building well-structured embedded applications as a set<br />

of concurrently executing hierarchical state machines (UML<br />

statecharts) directly in C or C++. QP is described in great detail in<br />

the book “Practical UML Statecharts in C/C++, Second Edition:<br />

Event-Driven Programming for Embedded Systems” [PSiCC2]<br />

(Newnes, 2008).<br />

As shown in Figure 2, QP consists of a universal UML-compliant<br />

event processor (QEP), a portable real-time framework (QF), a<br />

tiny run-to-completion kernel (QK), and software tracing<br />

instrumentation (QS). Current versions of QP include: QP/C<br />

and QP/C++, which require about 4KB of code and a few hundred bytes of RAM, and the ultralightweight<br />

QP-nano, which requires only 1-2KB of code and just several bytes of RAM. The Linux port<br />

described in this Application Note pertains to QP/C and QP/C++.<br />

Figure 2 QP components and their relationship with the target hardware, board support package<br />

(BSP), and the application comprised of state machines<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

2 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

QP can work with or without a traditional RTOS or OS. In the simplest configuration, QP can completely<br />

replace a traditional RTOS. QP can manage up to 63 concurrently executing tasks structured as state<br />

machines (called active objects in UML).<br />

1.2 About QM<br />

QM (QP Modeler) is a free, cross-platform, graphical UML modeling tool for<br />

designing and implementing real-time embedded applications based on the<br />

QP state machine frameworks. QM is available for Windows, Linux, and<br />

Mac OS X. QM provides intuitive diagramming environment for creating good<br />

looking hierarchical state machine diagrams and hierarchical outline of your<br />

entire application. QM eliminates coding errors by automatic generation of<br />

compact C or C++ code that is 100% traceable from your design. Please visit<br />

state-machine.com/qm for more information about QM.<br />

1.3 About this <strong>QDK</strong><br />

This <strong>QDK</strong> provides working examples of code running under both the cooperative Vanilla kernel and the<br />

preemptive QK kernel. The example code is based on the Dining Philosopher Problem (DPP) sample<br />

application described in Chapter 7 of [PSiCC2] as well as in the Application Note “Dining Philosopher<br />

Problem” [QL AN-DPP 08] (included in the example code distribution).<br />

The entire source code included with this <strong>QDK</strong> can be edited manually in a traditional code editor.<br />

However, significant parts of the code have been generated automatically by the QM modeling tool<br />

from the dpp.qm model file included in the <strong>QDK</strong>. The preferred way of developing QP applications is to<br />

make all the changes in the model and generate the code automatically.<br />

Figure 3: The example model opened in the QM modeling tool<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

3 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

The <strong>QDK</strong>-<strong>AVR32</strong> example code includes the following components:<br />

<br />

<br />

<br />

<br />

Board support package (BSP) which provides interrupt service routines (ISRs), all QP callbacks, and<br />

an interface to the board's LEDs, push buttons, system clock tick timer, and serial port.<br />

QP port to <strong>AVR32</strong><strong>UC</strong> for the Vanilla cooperative kernel described in Chapter 7 of [PSiCC2]<br />

QP port to <strong>AVR32</strong><strong>UC</strong> for the preemptive QK kernel described in Chapter 10 of [PSiCC2]<br />

The DPP example for both the cooperative Vanilla kernel and the preemptive QK kernel.<br />

The QM model of the Dinging Philosophers Problem (see Figure 3)<br />

NOTE: The significant parts of the source code (files dpp.h, philo.c, and table.c) have been<br />

generated by the QM modeling tool from the dpp.qm model, which is the same for the Vanilla and<br />

QK versions of the DPP application. These files can be edited by hand (after unchecking the readonly<br />

property), but the changes made at the code level won't be incorporated back into the model.<br />

1.4 Licensing QP<br />

The Generally Available (GA) distribution of QP available for download from the www.statemachine.com/downloads<br />

website is offered with the following two licensing options:<br />

<br />

<br />

The <strong>GNU</strong> General Public License (GPL) as published by the Free Software<br />

Foundation and appearing in the file GPL.TXT included in the packaging of every<br />

<strong>Quantum</strong> <strong>Leaps</strong> software distribution. The GPL open source license allows you to<br />

use the software at no charge under the condition that if you redistribute the original<br />

software or applications derived from it, the complete source code for your<br />

application must be also available under the conditions of the GPL (GPL version 2<br />

Section 2[b]).<br />

One of several <strong>Quantum</strong> <strong>Leaps</strong> commercial licenses, which are designed for<br />

customers who wish to retain the proprietary status of their code and therefore cannot<br />

use the <strong>GNU</strong> General Public License. The customers who license <strong>Quantum</strong> <strong>Leaps</strong><br />

software under the commercial licenses do not use the software under the GPL and<br />

therefore are not subject to any of its terms.<br />

For more information, please visit the licensing section of our website at: www.statemachine.com/licensing.<br />

1.5 Licensing QM<br />

The QM graphical modeling tool available for download from the www.statemachine.com/downloads<br />

website is free to use, but is not open source. During the<br />

installation you will need to accept a basic End-User License Agreement (EULA),<br />

which legally protects <strong>Quantum</strong> <strong>Leaps</strong> from any warranty claims, prohibits removing<br />

any copyright notices from QM, selling it, and creating similar competitive products.<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

4 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

2 Getting Started<br />

This section describes how to install, build, and use <strong>QDK</strong>-<strong>AVR32</strong><strong>UC</strong>-<strong>GNU</strong> based two examples. This<br />

information is intentionally included early in this document, so that you could start using the <strong>QDK</strong> as soon<br />

as possible. The main focus of this section is to walk you quickly through the main points without slowing<br />

you down with full-blown detail.<br />

NOTE: This <strong>QDK</strong> assumes that the standard QP distribution consisting of QEP, QF, and QK has<br />

been installed, before installing this <strong>QDK</strong>. It is also strongly recommended that you read the QP<br />

tutorial before you start experimenting with this <strong>QDK</strong>.<br />

2.1 Installation<br />

The <strong>QDK</strong> code is distributed in a ZIP archive (qdkc_avr32uc-gnu.zip. You can unzip the archive into<br />

the same directory into which you’ve installed all the standard QP components. The installation directory<br />

you choose will be referred henceforth as QP Root Directory . The following Listing 1 shows the<br />

directory structure and selected files included in the <strong>QDK</strong>-<strong>AVR32</strong><strong>UC</strong>-<strong>GNU</strong> distribution. (Please note that<br />

the QP directory structure is described in detail in a separate Application Note: “QP Directory Structure”):<br />

Listing 1 Selected QP directories and files after installing <strong>QDK</strong>-<strong>AVR32</strong><strong>UC</strong>-<strong>GNU</strong>. The highlighted<br />

elements are included in the standard <strong>QDK</strong>-<strong>AVR32</strong><strong>UC</strong>-<strong>GNU</strong> distribution.<br />

qpc\<br />

- QP installation directory<br />

+-doc\<br />

| +-AN_DPP.pdf - Application Note “Dining Philosopher Problem Example”<br />

| +-<strong>QDK</strong>_AVR-<strong>GNU</strong>-STK600.pdf – This <strong>QDK</strong> Manual “<strong>QDK</strong> <strong>AVR32</strong><strong>UC</strong> with <strong>GNU</strong> Compiler”<br />

|<br />

+-include/<br />

- QP public include files<br />

|<br />

+-examples/<br />

- subdirectory containing the examples<br />

| +-avr32uc/ - examples for <strong>AVR32</strong><strong>UC</strong><br />

| | +-qk/ - QK examples<br />

| | | +-gnu/ - <strong>GNU</strong> AVR compiler<br />

| | | | +-dpp-qk_uc3a3xplained/ - DPP example for <strong>UC</strong>3A3Xplained board<br />

| | | | | +-Debug/ - directory containing the Debug build<br />

| | | | | +-Release/ - directory containing the Release build<br />

| | | | | +-Spy/ - directory containing the Spy build<br />

| | | | | +-src/ - source directory<br />

| | | | | | +-asf/ - Atmel Software Framework (ASF) directory (generated)<br />

| | | | | | | +-... - ASF sub-directories (generated)<br />

| | | | | | +-dpp.h - the DPP header file<br />

| | | | | | +-dpp.qm - QM model for the DPP application<br />

| | | | | | +-bsp.c - Board Support Package for AVR<br />

| | | | | | +-bsp.h - BSP header file<br />

| | | | | | +-main.c - the main function<br />

| | | | | | +-philo.c - the Philosopher active object<br />

| | | | | | +-table.c - the Table active object<br />

| | | | | +-dpp-qk_uc3a3xplained.atsln – Atmel Studio 6 solution<br />

| | | | | +-dpp-qk_uc3a3xplained.cproj – Atmel Studio 6 project<br />

| | |<br />

| | +-vanilla/ - Vanilla kernel examples<br />

| | | +-gnu/ - <strong>GNU</strong> AVR compiler<br />

| | | | +-dpp_uc3a3xplained/ - DPP example for <strong>UC</strong>3A3Xplained board<br />

| | | | | +-Debug/ - directory containing the Debug build<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

5 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

| | | | | +-Release/ - directory containing the Release build<br />

| | | | | +-Spy/ - directory containing the Spy build<br />

| | | | | +-src/ - source directory<br />

| | | | | | +-asf/ - Atmel Software Framework (ASF) directory (generated)<br />

| | | | | | | +-... - ASF sub-directories (generated)<br />

| | | | | | +-dpp.h - the DPP header file<br />

| | | | | | +-dpp.qm - QM model for the DPP application<br />

| | | | | | +-bsp.c - Board Support Package for AVR<br />

| | | | | | +-bsp.h - BSP header file<br />

| | | | | | +-main.c - the main function<br />

| | | | | | +-philo.c - the Philosopher active object<br />

| | | | | | +-table.c - the Table active object<br />

| | | | | +-dpp_uc3a3xplained.atsln – Atmel Studio 6 solution<br />

| | | | | +-dpp_uc3a3xplained.cproj – Atmel Studio 6 project<br />

|<br />

+-ports/<br />

- QP ports<br />

| +-avr32uc/ - <strong>AVR32</strong><strong>UC</strong> port<br />

| | +-qk/ - QK (preemptive) ports<br />

| | | +-gnu/ - <strong>GNU</strong> compiler<br />

| | | | +-dbg/ - QP library – Debug configuration<br />

| | | | | +-libqp_uc3a3256.a - QP library for <strong>UC</strong>3A3256 device<br />

| | | | +-rel/ - QP library – Release configuration<br />

| | | | +-spy/ - QP library – Spy configuration<br />

| | | | |<br />

| | | | +-make_uc3a3256.bat - make script for building the QP libraries<br />

| | | | +-qep_port.h - QEP port<br />

| | | | +-qf_port.h - QF port<br />

| | | | +-qk_port.h - QK port<br />

| | | | +-qk_port.asm - QK port implementation<br />

| | | | +-qs_port.h - QS port<br />

| | |<br />

| | +-vanilla/ - “vanilla” (cooperative) ports<br />

| | | +-gnu/ - <strong>GNU</strong> compiler<br />

| | | | +-dbg/ - QP library – Debug configuration<br />

| | | | +-dbg/ - QP library – Release configuration<br />

| | | | +-spy/ - QP library – Spy configuration<br />

| | | | | +-libqp_uc3a3256.a - QP library for <strong>UC</strong>3A3256 device<br />

| | | | |<br />

| | | | +- make_uc3a3256.bat - make script for building the QP libraries<br />

| | | | +-qep_port.h - QEP port<br />

| | | | +-qf_port.h - QF port<br />

| | | | +-qf_port.asm - QF port implementation<br />

| | | | +-qs_port.h - QS port<br />

| | | | +-qp_port.h - QP port<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

6 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

2.2 Building the QP Libraries<br />

All QP components are deployed as libraries that you statically link to your application.-QP is deployed as<br />

a library that you statically link to your application. The pre-built QP libraries for various build<br />

configurations are provided inside the \ports\avr32uc\ directory (see Listing 1). This section<br />

describes steps you need to take to rebuild the libraries yourself.<br />

NOTE: To streamline and simplify the QP-library build process, <strong>Quantum</strong> <strong>Leaps</strong> software does not<br />

use the vendor-specific IDEs, such as the Atmel Studio IDE, for building the QP libraries. Instead, this<br />

<strong>QDK</strong> provides command-line build process based on simple batch scripts. The build process for your<br />

application is largely independent on the QP-library builds. In fact, once you have the QP libraries,<br />

you typically don’t need to rebuild them—at least not on the daily basis as you work on your<br />

application. This <strong>QDK</strong> uses the Atmel Studio IDE to build the example applications, but you are free<br />

to use any other build strategy.<br />

The code distribution contains all the batch file make_uc3a3256.bat for building all the libraries located in<br />

\ports\avr32uc\vanilla\gnu\ directory.<br />

For example, to build the debug version of all the QP libraries for the <strong>AVR32</strong>, with the <strong>GNU</strong> <strong>AVR32</strong><br />

compiler, you open a console window on a Windows PC, change directory to \ports\-<br />

avr32uc\vanilla\gnu\, and invoke the batch by typing at the command prompt the following command:<br />

make_uc3a3256.bat<br />

The make process should produce the QP libraries in the location: \ports\avr32uc\vanilla\-<br />

gnu\dbg\. The make_uc3a3256.bat assumes that the <strong>GNU</strong>-<strong>AVR32</strong> toolset has been installed in the<br />

directory C:\tools\Atmel\Studio_6.0\extensions\Atmel\AVRGCC\3.4.0.65\AVRToolchain.<br />

NOTE: You need to adjust the symbol <strong>GNU</strong>_AVR at the top of the make_uc3a3256.bat file if<br />

you’ve installed the Atmel Studio in a different directory.<br />

Also, to build the QP libraries for a different <strong>AVR32</strong> device, you need to change the symbol<br />

TARGET_MCU in the make_uc3a3256.bat file.<br />

In order to take advantage of the Q-SPY instrumentation, you need to build the Spy version of the QP<br />

libraries. You achieve this by invoking the make_uc3a3256.bat utility with the “spy” target, like this:<br />

make_uc3a3256.bat spy<br />

The make process should produce the QP libraries in the directory: \ports\avr32uc\vanilla\-<br />

gnu\spy\.<br />

NOTE: The QP libraries and QP applications can be built in the following three build configurations:<br />

Debug - this configuration is built with full debugging information and minimal optimization. When the<br />

QP framework finds no events to process, the framework busy-idles until there are new events to<br />

process.<br />

Release - this configuration is built with no debugging information and high optimization. Singlestepping<br />

and debugging is effectively impossible due to the lack of debugging information and<br />

optimized code, but the debugger can be used to download and start the executable. When the QP<br />

framework finds no events to process, the framework puts the CPU to sleep until there are new<br />

events to process.<br />

Spy - like the debug variant, this variant is built with full debugging information and minimal<br />

optimization. Additionally, it is build with the QP's Q-SPY trace functionality built in. The on-board<br />

serial port and the Q-Spy host application are used for sending and viewing trace data. Like the<br />

Debug configuration, the QP framework busy-idles until there are new events to process.<br />

You choose the build configuration by providing a target to the make_uc3a3256.bat utility. The default<br />

target is “dbg”. Other targets are “rel”, and “spy” respectively. The following table summarizes the<br />

targets accepted by make_uc3a3256.bat .<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

7 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

2.3 Building the Examples<br />

The <strong>QDK</strong> contains the Atmel Studio project files located in \examples\avr32uc\vanilla\gnu-<br />

\dpp_uc3a3xplained\dpp_uc3a3xplained.atsln for the “vanilla” version, and in \-<br />

examples\avr32uc\qk\gnu\dpp-qk_uc3a3xplained\dpp-qk_uc3a3xplained.atsln for the QK<br />

version, respectively.<br />

NOTE: The particular directory structure in the example projects has been generated by the Atmel<br />

Studio project wizard and is based on the Atmel Software Framewrok (ASF). The projects have been<br />

subsequently modified for QP.<br />

Figure 4 The DPP example project opened in Atmel Studio.<br />

The build configuration is selected by the drop-down box.<br />

Select build<br />

configuration<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

8 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

2.4 Running the Examples<br />

To execute and debug the provided examples you need the Atmel <strong>UC</strong>3-A3-Xplained board and the JTAG<br />

pod, such as the JTAGICE mkII shown in Figure 1. You need to set up the Atmel Studio to use the JTAG<br />

pod “Tool” that you have.<br />

After powering up both the board and the JTAG pod, you can click on the “Start Debugging” button in the<br />

Atmel Studio, at which point the DPP example code will be programmed to the flash memory of the<br />

microcontroller. The programming takes several seconds and the code should start executing and the<br />

LEDs of the <strong>UC</strong>3-A3-Xplained board should start blinking. The LEDs 1, 2, and 3 in the corners of the<br />

board (see Figure 1) represent philosophers 0-2.One of these LEDs turned on represents an “eating”<br />

philosopher. Extinguished LED represents philosopher “thinking” or “hungry”.<br />

The LED0 in the top-left corner of the board is used to visualize the idle loop activity. The LED0 is rapidly<br />

toggled on and off from the idle callback, so its intensity is proportional to the frequency of idle loop.<br />

2.4.1 Q-SPY Software Tracing<br />

QS is a software tracing facility built into all QP components and also available to the Application code.<br />

QS allows you to gain unprecedented visibility into your application by selectively logging almost all<br />

interesting events occurring within state machines, the framework, the kernel, and your application code.<br />

QS software tracing is minimally intrusive, offers precise time-stamping, sophisticated runtime filtering of<br />

events, and good data compression (see Chapter 11 in [PSiCC2]).<br />

For the QS (Q-SPY) software tracing output, you need to connect a TTL to RS-232 transceiver to the<br />

<strong>UC</strong>3-A3-Xplained board, as shown in Figure 5. The figure shows the RS232 to TTL converter board 3.3V<br />

to 5V from NKC Electronics (http://www.nkcelectronics.com/rs232-to-ttl-converter-board-33v232335.html),<br />

but you can use any other equivalent board.<br />

Figure 5 Connecting RS232-TTL transceiver to the J4 connector of the <strong>UC</strong>3-A3-Xplained board.<br />

<strong>UC</strong>3-A3-Xplained<br />

board<br />

TTL-RS-232<br />

transceiver<br />

board<br />

TX J4[4]<br />

J4<br />

J4[8] ↔ VCC<br />

J4[7] ↔ GND<br />

J4[4] ↔ TX<br />

Q-SPY trace<br />

data to host<br />

To see the QS software trace output, you also need to download the Spy build configuration to the<br />

target board. Next you need to launch the QSPY host utility to observe the output in the human-readable<br />

format.<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

9 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

NOTE: The QSPY host utility is now included in the Qtools collection, which is available for a<br />

separate download from www.state-machine.com/downlaods. The following discussion assumes that<br />

you have downloaded and installed Qtools, including adding the Qtools directory to the PATH<br />

variable on your system.<br />

You launch the QSPY utility on a Windows PC as follows:<br />

qspy –c COM1 –b 115200<br />

This will start the QSPY host application to listen on COM1 serial port with baud rate 1152400. (Please use<br />

the actual (virtual) COM port number on your PC.) The following screen shot shows the QSPY output<br />

from the DPP run:<br />

Figure 6 Screen shot from the QSPY output.<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

10 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

3 The Vanilla QP Port<br />

The “vanilla” port shows how to use <strong>Quantum</strong> Platform on a “bare metal” <strong>AVR32</strong>-based system without<br />

any underlying multitasking kernel.<br />

In the “vanilla” version of the QP, the only component requiring platform-specific porting is the QF. The<br />

other two components: QEP and QS require merely recompilation and will not be discussed here.<br />

Obviously, with the vanilla port you’re not using the QK component.<br />

In case of <strong>AVR32</strong>, the “vanilla” QF port is very similar to the generic “vanilla” port described in Chapter 9<br />

of [PSiCC2].<br />

3.1 The qep_port.h Header File<br />

The QEP header file for the RX port is located in \ports\avr32uc\vanilla\gnu\qep_port.h.<br />

Listing 2 shows the qep_port.h header file for <strong>AVR32</strong><strong>UC</strong> CPU.<br />

#ifndef qep_port_h<br />

#define qep_port_h<br />

Listing 2 The qep_port.h header file for the <strong>AVR32</strong><strong>UC</strong>-<strong>GNU</strong> port<br />

#include /* C99-standard exact-width integers */<br />

#include "qep.h" /* QEP platform-independent public interface */<br />

#endif /* qep_port_h */<br />

3.2 The qf_port.h Header File<br />

The QF header file for the <strong>AVR32</strong><strong>UC</strong> port with the <strong>GNU</strong> compiler is located in /ports/avr32uc/-<br />

vanilla/gnu/qf_port.h. This file specifies the configuration constants for QF (see Chapter 8 in<br />

[PsiCC2]) as well as the interrupt disabling/enabling and the critical section policy, which is the most<br />

important decision you make in the QF port. The <strong>AVR32</strong><strong>UC</strong> family of MCUs allows using the simplest<br />

“unconditional interrupt unlocking” policy (see Section 7.3.2 of [PSiCC2]), because <strong>AVR32</strong><strong>UC</strong> provides a<br />

built-in, prioritized interrupt controller (INTC).<br />

#ifndef qf_port_h<br />

#define qf_port_h<br />

Listing 3 The qf_port.h header file<br />

/* The maximum number of active objects in the application, see NOTE01 */<br />

(1) #define QF_MAX_ACTIVE 32<br />

/* QF interrupt disable/enable */<br />

(2) #define QF_INT_DISABLE() __builtin_ssrf(16)<br />

(3) #define QF_INT_ENABLE() __builtin_csrf(16)<br />

/* QF critical section entry/exit */<br />

(4) /* QF_CRIT_STAT_TYPE not defined: unconditional interrupt unlocking" policy */<br />

(5) #define QF_CRIT_ENTRY(dummy) QF_INT_DISABLE()<br />

(6) #define QF_CRIT_EXIT(dummy) QF_INT_ENABLE()<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

11 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

#include "qep_port.h" /* QEP port */<br />

(7) #include "qvanilla.h" /* "Vanilla" cooperative kernel */<br />

#include "qf.h" /* QF platform-independent public interface */<br />

#endif /* qf_port_h */<br />

(1) The QF_MAX_ACTIVE macro specifies the maximum number of active object priorities in the<br />

application. You always need to provide this constant. Here, QF_MAX_ACTIVE is set to 32 to save<br />

RAM. You can increase it up to the maximum limit of 63 active object priorities in the system.<br />

(2) The QF_INT_DISABLE() macro resolves to the single instruction "SSRF 16". This single instruction<br />

sets the GM mask in the SR register, thereby disabling all interrupts.<br />

(3) The QF_INT_ENABLE() macro resolves to the single instruction "CSRF 16". This single instruction<br />

clears the GM mask in the SR register, thereby enabling all interrupts.<br />

NOTE: The <strong>AVR32</strong> SR register holds also 4 masks to disable individual interrupt priorities (IM0-IM3).<br />

These masks are independent from the GM mask (SR[16]).<br />

(4) The QF_CRIT_STAT_TYPE macro is not defined, which means that the simple critical section policy<br />

of “unconditional interrupt locking and unlocking” is applied.<br />

(5) The QF_CRIT_ENTRY() macro does not use its parameter in this case and simply unconditionally<br />

disables interrupts.<br />

(6) The QF_CRIT_EXIT() macro does not use its parameter in this case and simply unconditionally reenables<br />

interrupts.<br />

NOTE: The simple and very efficient critical section policy does not allow nesting of critical sections.<br />

The <strong>AVR32</strong>US interrupt handlers don not disable interrupts upon entry, so the ISR itself is not a<br />

critical section with respect to the GM bit in SR.<br />

(7) The “Vanilla” port includes the “qvanilla.h” header file.<br />

3.3 The <strong>AVR32</strong><strong>UC</strong> Exceptions and the qf_port.asm File<br />

The standard Atmel Software Framework (ASF) projects for <strong>AVR32</strong> generated by the project wizard in the<br />

Atmel Studio contain the file exception.S (in the src\asf\avr32\drivers\intc\ sub-directory), which<br />

defines all exception and interrupt handlers. This standard implementation is minimalist and designed for<br />

software development rather than deployment. For example, all exception handlers end up in an endless<br />

loop, which ties up the CPU completely and causes the application to “freeze”. While this is adequate for<br />

debugging, this “denial of service” after an exception is absolutely not acceptable for production release.<br />

Also, the low-level interrupt handlers defined in exception.S provide a software-based “vectoring”<br />

feature, which calls user-defined Interrupt Service Routines (ISRs) in C. However, in the standard<br />

implementation, the ISRs in C still need to return via the 'rete' instruction, so in the <strong>GNU</strong> compiler they<br />

need to be defined as __attribute__((__interrupt__)) functions. This aspect is simplified in the QP<br />

implementation, because the existing low-level wrapper already performs function call to the regular C<br />

function to perform the vectoring, so the call to the user-defined ISR could just as well be a regular C<br />

function without any special return sequence generated by the compiler.<br />

NOTE: The file exception.S (in the src\asf\avr32\drivers\intc\ sub-directory) generated<br />

by the Atmel Studio project wizard must be removed from the project, so that the QP-specific<br />

implementation can be linked in from the QP library.<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

12 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

The following Listing 4 shows the exception and interrupt handlers in the qf_port.asm file.<br />

#include <br />

Listing 4 Exception and interrupt handling in qf_port.asm.<br />

.section .exception, "ax", @progbits<br />

//////////////////////////////////////////////////////////////////////////////<br />

// Start of Exception Vector Table<br />

//<br />

// EVBA must be aligned with a power of two strictly greater than the<br />

// EVBA-relative offset of the last vector.<br />

//<br />

.balign 0x200<br />

// Export symbol<br />

.global _evba<br />

.type _evba, @function<br />

(1) _evba:<br />

(2) .org 0x000 // Unrecoverable Exception<br />

(3) bral _handle_Unrecoverable_Exception<br />

.org 0x004 // TLB Multiple Hit<br />

bral _handle_TLB_Multiple_Hit<br />

.org 0x008 // Bus Error Data Fetch<br />

bral _handle_Bus_Error_Data_Fetch<br />

. . .<br />

.balign 4<br />

(4) _handle_Unrecoverable_Exception:<br />

(5) mov R11, 0x000<br />

(6) bral call_onAssert<br />

_handle_TLB_Multiple_Hit:<br />

mov R11, 0x004<br />

bral call_onAssert<br />

_handle_Bus_Error_Data_Fetch:<br />

mov R11, 0x008<br />

bral call_onAssert<br />

. . .<br />

.extern Q_onAssert<br />

// QP assertion handler<br />

call_onAssert:<br />

(7) lddpc R12, exc_ptr // pointer to the "EXCEPTION\0" string<br />

(8) bral Q_onAssert // jump to the QP assertion handler<br />

exc_ptr:<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

13 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

.word exc_str<br />

exc_str:<br />

.ascii "EXCEPTION\0"<br />

. . .<br />

.balign 4<br />

(9) .global _int0<br />

.global _int1<br />

.global _int2<br />

.global _int3<br />

.type<br />

.type<br />

.type<br />

.type<br />

_int0, @function<br />

_int1, @function<br />

_int2, @function<br />

_int3, @function<br />

_int0:<br />

(10) mov R12, 0 // the paramter for _get_interrupt_handler<br />

(11) bral call_get_interrupt_handler<br />

_int1:<br />

mov R12, 1 // the paramter for _get_interrupt_handler<br />

bral call_get_interrupt_handler<br />

_int2:<br />

mov R12, 2 // the paramter for _get_interrupt_handler<br />

bral call_get_interrupt_handler<br />

_int3:<br />

mov R12, 3 // the paramter for _get_interrupt_handler<br />

call_get_interrupt_handler:<br />

(12) rcall _get_interrupt_handler // return the pointer to the ISR in R12<br />

(13) breq int_done // branch if return value (R12) == 0<br />

(14) icall R12 // call the user ISR (normal C function!)<br />

int_done:<br />

(15) rete<br />

(1) All exception handlers in <strong>AVR32</strong> are relative to the Exception Vector Base Address (EVBA) system<br />

register.<br />

(2) For example, the “Unrecoverable Exception” is placed at offset 0 from the EBA (see the exception<br />

addressed in the <strong>AVR32</strong> data sheet).<br />

(3) The address assignment leaves no room to handle the exception directly, so only a branch<br />

instruction to the handler fits in the allocated space.<br />

(4) The exception is actually handled at this label.<br />

(5) The address of the exception is moved to R11, which will be the second parameter for the<br />

Q_onAssert() function.<br />

(6) Once the address of the exception is stored, another branch is taken to call the Q_onAssert()<br />

function.<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

14 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

(7) The pointer to the zero-terminated string “EXCEPTION” is moved to R12, which will be the first<br />

parameter for the Q_onAssert() function.<br />

(8) The Q_onAssert() function is “called” with a branch instruction (instead of rcall) in order to avoid<br />

clobbering the LR register. The return address is unnecessary for Q_onAssert(), because the<br />

function is not supposed to return.<br />

NOTE: The system handling of a hardware exception, such as bus error or privilege violation, must<br />

be very carefully designed before releasing the software into the field, just as the course of action to<br />

take after hitting an assertion. In fact, a system exception is a hardware-assisted assertion.<br />

Therefore, the exception handlers in the QP port call the QP assertion handler Q_onAssert(),<br />

which needs to be carefully designed to handle system failure in the most appropriate way.<br />

(9) The following code defines four low-level <strong>AVR32</strong> interrupt handlers (_int0, _int1, _int2, and<br />

_int3). All these handlers are called after the <strong>AVR32</strong><strong>UC</strong> core saves R8-R12, LR, PC, and SR onto<br />

the system stack. This means that any of these saved registers can be used safely in the interrupt<br />

handler. The handlers can also safely call C functions, which can clobber R8-R12, LR, PC, and SR.<br />

(10-11) Every low-level handler starts with saving the interrupt priority into R12 and branching to the part<br />

of the code common for all the handlers.<br />

(12) This common part starts with the call to the _get_interrupt_handler function, which is a regular<br />

C function defined in the module intc.c. Note that the priority level saved in R12 is passed to this<br />

function as the first (and only) parameter.<br />

(13) The _get_interrupt_handler function performs the “vectoring” of the interrupt request and<br />

returns the pointer to the user-defined ISR in R12. If the returned pointer is NULL, the return<br />

instruction automatically sets the Z flag in the SR, so the conditional branch (breq) can be taken if<br />

the returned vector is NULL.<br />

NOTE: The _get_interrupt_handler function returns NULL for so called “spurious” interrupts,<br />

which have no explicitly assigned ISRs.<br />

(14) The user-defined ISR returned in R12 is called as a regular C function (so the LR is set to return to<br />

the low-level interrupt handler).<br />

(15) After the user-defined ISR returns, the low-level interrupt handler returns with the 'rete' instruction.<br />

NOTE: The user-defined ISR is a regular C function, not any special compiler-generated interrupt<br />

function.<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

15 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

3.4 BSP for <strong>AVR32</strong><br />

As mentioned before, the application examples provided in this Application Note are based on the ASF<br />

(Atmel Software Framework), which has been generated by the project wizard in the Atmel Studio.<br />

Therefore, most of the traditional Board Support Package (BSP) for <strong>AVR32</strong> is already available, although<br />

spread out over many ASF directories and files. However, there are some QP-specific details that you<br />

need to pay attention to, and this section addresses these issues.<br />

3.4.1 Starting and Prioritizing Interrupts in QF_onStartup()<br />

QP invokes the QF_onStartup() callback just before starting the event loop inside QF_run(). The<br />

QF_onStartup() function must configure and start the interrupts.<br />

void QF_onStartup(void) {<br />

uint32_t count;<br />

Listing 5 The QF_onStartup() callback<br />

(1) INTC_init_interrupts(); /* initialize interrupt vectors */<br />

/* set the tickISR IRQ number and priority */<br />

(2) INTC_register_interrupt(&tickISR,<br />

<strong>AVR32</strong>_CORE_COMPARE_IRQ, <strong>AVR32</strong>_INTC_INT0);<br />

/* setup the COUNT/COMPARE registers to generate system clock tick */<br />

(3) __builtin_mtsr(SYSREG_COUNT, 0U);<br />

(4) __builtin_mtsr(SYSREG_COMPARE, BSP_TICK_PERIOD);<br />

}<br />

(1) The <strong>AVR32</strong> interrupt controller is initialized.<br />

(2) Each interrupt in the system is registered. The interrupt is assigned the user-defined ISR function<br />

(tickISR in this case), the interrupt number, and the priority in the 0-3 range.<br />

(3) The COUNT system register is reset to zero and immediately starts counting up.<br />

(4) The COMPARE system register is loaded with the value to generate interrupt in the desired number<br />

of clocks into the future. BSP_TICK_PERIOD is defined as (sysclk_get_pba_hz() /<br />

BSP_TICKS_PER_SEC).<br />

3.4.2 The System Clock Tick ISR<br />

As shown in Listing 5(3-4), the periodic system clock tick interrupt is implemented with the <strong>AVR32</strong>-specific<br />

cycle counter timer (the COUNT system register). This timer is left to run completely free and the interrupt<br />

is generated by re-loading the COMPARE moving the value in the COMPARE system register by the<br />

desired tick period into the future.<br />

3.4.3 User-defined ISRs<br />

As described before, the user-defined ISRs in this QP port to <strong>AVR32</strong><strong>UC</strong> are regular C functions. The<br />

following Listing 6 shows the system clock tick ISR:<br />

NOTE: The ISRs run with the global interrupt mask (GM) cleared, so they are not a critical section<br />

with respect to the QF_CRIT_ENTRY()/QF_CRIT_EXIT() macros.<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

16 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

Listing 6 The user-defined system clock tick ISR.<br />

(1) static void tickISR(void) { /* see NOTE00 */<br />

/* write to COMPARE to clear the interrupt request */<br />

(2) __builtin_mtsr(SYSREG_COMPARE, BSP_TICK_PERIOD);<br />

#ifdef Q_SPY<br />

(3) l_tickCount += BSP_TICK_PERIOD;<br />

#endif<br />

(4) QF_TICK(&l_tickISR);<br />

}<br />

(1) A user-defined ISR is a regular void (*)(void) C function.<br />

(2) The write operation to the COMPARE system register clears the interrupt source.<br />

(3) In the Q_SPY build configuration, the additional tick counter variable is incremented to extend the<br />

clock counter to 32 bits.<br />

(4) The time-tick ISR must invoke QF_TICK(), and can also perform other actions, if necessary. The<br />

function QF_TICK() cannot be reentered, that is, it necessarily must run to completion and return<br />

before it can be called again. This requirement is automatically fulfilled, because here interrupts are<br />

locked throughout the interrupt processing.<br />

3.5 QP Idle Loop Customization in QF_onIdle()<br />

This QF port uses the standard QF_run() “vanilla” implementation described in Chapter 7 in the [PSiCC2]<br />

book. The standard QF_run() can very easily detect the situation when no events are available, in which<br />

case QF_run() calls the QF_onIdle() callback. You can use QF_onIdle() to suspended the CPU to<br />

save power, if your CPU supports such a power-saving mode. Please note that QF_onIdle() is called<br />

repetitively from the event loop whenever the event loop has no more events to process, in which case<br />

only an interrupt can provide new events. The QF_onIdle() callback is called with interrupts disabled,<br />

because the determination of the idle condition might change by any interrupt posting an event.<br />

AVR supports several power-saving levels (consult the AVR data sheet for details). The following piece of<br />

code shows the QF_onIdle() callback that puts AVR into the idle power-saving mode. Please note that<br />

AVR architecture allows for very atomic setting the low-power mode and enabling interrupts at the same<br />

time.<br />

Listing 7 QF_onIdle() for the “vanilla” <strong>AVR32</strong><strong>UC</strong> port<br />

(1) void QF_onIdle() { /* called with interrupts DISABLED, see NOTE01 */<br />

(2) LED_On (LED0); /* toggle the LED0 on and then off, see NOTE02 */<br />

(3) LED_Off(LED0);<br />

(4) #ifdef Q_SPY /* use the idle cycles for QS transmission */<br />

QF_INT_ENABLE();<br />

if ((QS_USART->csr & <strong>AVR32</strong>_USART_CSR_TXRDY_MASK) != 0U) { /* ready? */<br />

uint16_t b;<br />

QF_INT_DISABLE();<br />

b = QS_getByte();<br />

QF_INT_ENABLE();<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

17 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

}<br />

if (b != QS_EOD) {<br />

QS_USART->thr = (b


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

4 The QK Port<br />

This section describes how to use QP on <strong>AVR32</strong><strong>UC</strong> CPU with the preemptive QK real-time kernel<br />

described in Chapter 10 of [PSiCC2]. The benefit is very fast, fully deterministic task-level response and<br />

that execution timing of the high-priority tasks (active objects) will be virtually insensitive to any changes<br />

in the lower-priority tasks. The downside is bigger RAM requirement for the stack. Additionally, as with<br />

any preemptive kernel, you must be very careful to avoid any sharing of resources among concurrently<br />

executing active objects, or if you do need to share resources, you need to protect them with the QK<br />

priority-ceiling mutex (again see Chapter 10 of [PSiCC2]).<br />

NOTE: The preemptive configuration with QK uses more stack than the non-preemptive “Vanilla”<br />

configuration. You need to adjust the size of this stack to be large enough for your application.<br />

4.1 Single-Stack, Preemptive Multitasking on <strong>AVR32</strong><strong>UC</strong><br />

The <strong>AVR32</strong><strong>UC</strong> architecture is designed primarily for the traditional real-time kernels that use multiple pertask<br />

stacks. This hardware design requires some quite expensive CPU mode switches, which are strictly<br />

speaking superfluous for the simplistic, run-to-completion, single-stack kernel, such as QK, because they<br />

don't alter the stack. This section explains how the single-stack preemptive QK kernel works on<br />

<strong>AVR32</strong><strong>UC</strong>.<br />

NOTE: Even though <strong>AVR32</strong><strong>UC</strong> is not an ideal match for a run-to-completion, single-stack kernel, the<br />

kernel of this type still saves about 50% of the stack space and CPU cycles compared to any<br />

traditional preemptive kernel.<br />

1. The <strong>AVR32</strong>CPU processor executes all tasks and the QK idle loop in the Supervisor mode, which is<br />

exactly the mode entered out of reset.<br />

2. The processor uses only the System Stack. No per-task stacks are necessarily (QK is a single stack<br />

kernel).<br />

3. The user-defined ISRs are regular C function (not any __interrupt__ function).<br />

4. The QK-specific interrupt entry and exit is provided in the low-level interrupt handlers in assembly,<br />

which subsequently call the user-defined ISRs. Consequently, the user-defined ISRs do not call the<br />

macros QK_ISR_ENTRY()/QK_ISR_EXIT(). These macros are not provided in the QK port.<br />

5. The user-defined ISRs must be registered with the INTC_register_interrupt() call, in which each<br />

ISR is assigned one of the four interrupt priorities.<br />

6. The user-defined ISRs execute outside of the critical section (defined by the GM mask in the SR<br />

register) and can preempt each other based on their interrupt priority.<br />

NOTE: If you don’t wish the ISRs to preempt each other, you can always set the same interrupt<br />

priority to them.<br />

4.2 The qk_port.h Header File<br />

You configure and customize QK through the header file qk_port.h, which is located in the QP ports<br />

directory \ports\avr32uc\qk\gnu\. The qk_port.h for the <strong>AVR32</strong><strong>UC</strong> CPU contains only the<br />

platform-independent qk.h header file and does not contain the macros QK_ISR_ENTRY/QK_ISR_EXIT.<br />

#include "qk.h" /* QK platform-independent public interface */<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

19 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

/*****************************************************************************<br />

* NOTE: The macros QK_ISR_ENTRY/QK_ISR_EXIT are NOT used in the <strong>AVR32</strong> port,<br />

* because this functionality is implemented in the low-level interrupt<br />

* handlers define in assembly in "qk_port.asm".<br />

*/<br />

4.3 The Low-Level Interrupt Handlers for QK (file qk_port.asm)<br />

The QK-specific exception and interrupt handling is performed in the assembly module qk_port.asm,<br />

which to a large degree is similar to the qf_port.asm file for the “vanilla” kernel. In particular, the <strong>AVR32</strong><br />

exception handling for QK is identical as for the Vanilla kernel, as described in Section 3.3.<br />

However, the interrupt handling for the preemptive QK kernel is obviously different than for the<br />

cooperative kernel. The following Listing 8 shows the exception and interrupt handlers for QK,<br />

implemented in the qk_port.asm file.<br />

NOTE: The file exception.S (in the src\asf\avr32\drivers\intc\ sub-directory) generated<br />

by the Atmel Studio project wizard must be removed from the project, so that the QK-specific<br />

implementation can be linked in from the QP library.<br />

#include <br />

Listing 8 Exception and interrupt handling in qk_port.asm..<br />

.section .exception, "ax", @progbits<br />

. . .<br />

(1) _evba:<br />

.org 0x000 // Unrecoverable Exception<br />

bral _handle_Unrecoverable_Exception<br />

. . .<br />

/////////////////////////////////////////////////////////////////////////////<br />

.balign 4<br />

.extern QK_intNest_<br />

.extern QK_schedPrio_<br />

.extern QK_sched_<br />

.global _int0<br />

.global _int1<br />

.global _int2<br />

.global _int3<br />

.type<br />

.type<br />

.type<br />

.type<br />

_int0, @function<br />

_int1, @function<br />

_int2, @function<br />

_int3, @function<br />

(2) _int0:<br />

(3) mov R12, 0 // parameter for _get_interrupt_handler<br />

(4) bral call_get_interrupt_handler<br />

_int1:<br />

mov R12, 1 // tparameter for _get_interrupt_handler<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

20 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

bral<br />

call_get_interrupt_handler<br />

_int2:<br />

mov R12, 2 // parameter for _get_interrupt_handler<br />

bral call_get_interrupt_handler<br />

_int3:<br />

mov R12, 3 // parameter for _get_interrupt_handler<br />

call_get_interrupt_handler:<br />

(5) rcall _get_interrupt_handler // return the pointer to the ISR in R12<br />

(6) breq int_ret // branch if return value (R12) == 0<br />

// ---------------------------- QK_ISR_ENTRY() ---------------------------<br />

(7) ssrf 16 // disable interrupts<br />

(8) mov R8, LO(QK_intNest_) // load address of QK_intNest_ into R8<br />

orh R8, HI(QK_intNest_) // ...<br />

(9) ld.ub R9, R8[0] // load value of QK_intNest_ into R9<br />

(10) sub R9, -1 // increment R9 by 1<br />

(11) st.b R8[0], R9 // store R9 in R8<br />

(12) csrf 16 // enable interrupts<br />

// ---------------------------- QK_ISR_ENTRY() ---------------------------<br />

(13) icall R12 // call the user ISR (normal C function!)<br />

// ---------------------------- QK_ISR_EXIT() ----------------------------<br />

(14) ssrf 16 // disable interrupts<br />

(15) mov R8, LO(QK_intNest_) // load address of QK_intNest_ into R8<br />

orh R8, HI(QK_intNest_) // ...<br />

(16) ld.ub R9, R8[0] // load value of QK_intNest_ into R9<br />

(17) sub R9, 1 // decrement R9 by 1<br />

(18) castu.b R9<br />

(19) st.b R8[0], R9<br />

(20) brne int_ret // QK_inNest_ != 0, return<br />

(21) ld.w R8, SP[0*4] // read the stacked SR<br />

(22) bfextu R8, R8, 22, 3 // extract the mode bits to R8<br />

(23) cp.w R8, 1 // compare with supervisor mode (b'001)<br />

(24) brne int_ret // branch if not supervisor<br />

(25) rcall QK_schedPrio_ // find the highest priority task<br />

(26) breq int_ret // branch if return is zero (no task)<br />

// ---------------------------- QK_ISR_EXIT() ----------------------------<br />

(27) sub SP, 4*4 // fake pushing R8-R11<br />

(28) mov R8, R12 // future R12 - arg for QK_sched_<br />

(29) mov R9, LO(sched_ret) // future LR - sched_ret<br />

(30) orh R9, HI(sched_ret) // ...<br />

(31) mov R10, LO(QK_sched_) // future PC - QK_sched_<br />

(32) orh R10, HI(QK_sched_) // ...<br />

(33) movh R11, 0x0041 // future SR - Supervisor mode + GM<br />

(34) pushm R8-R9, R10, R11 // push R12, LR, PC, SR<br />

(35) rete // context-switch to the scheduler<br />

sched_ret:<br />

(36) sub R12, SP, -6*4 // setup R12 as the Supervisor call stack<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

21 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

(37) ldm R12, R8-R9 // load saved R8, R9<br />

(38) popm R10, R11 // pop saved SR into R11 and PC into R10<br />

(39) stm R12, R10, R11 // make the Supervisor call stack frame<br />

(40) popm R10, R11, R12, LR // pop the rest of the context<br />

(41) rets // context switch to the interrupted task<br />

int_ret:<br />

rete<br />

(1) The omitted exception handling in the qk_port.asm file is identical as in qf_port.asm, see Section<br />

3.3.<br />

(2) The following code defines four low-level <strong>AVR32</strong> interrupt handlers (_int0, _int1, _int2, and<br />

_int3). All these handlers are called after the <strong>AVR32</strong><strong>UC</strong> core saves R8-R12, LR, PC, and SR onto<br />

the system stack. This means that any of these saved registers can be used safely in the interrupt<br />

handler. The handlers can also safely call C functions, which can clobber R8-R12, LR, PC, and SR.<br />

(3-4) Every low-level handler starts with saving the interrupt priority into R12 and branching to the part of<br />

the code common for all the handlers.<br />

(5) This common part starts with the call to the _get_interrupt_handler function, which is a regular<br />

C function defined in the module intc.c. Note that the priority level saved in R12 is passed to this<br />

function as the first (and only) parameter.<br />

(6) The _get_interrupt_handler function performs the “vectoring” of the interrupt request and<br />

returns the pointer to the user-defined ISR in R12. If the returned pointer is NULL, the functionreturn<br />

automatically sets the Z flag in the SR, so the conditional branch (breq) can be taken if the<br />

returned vector is NULL.<br />

NOTE: The _get_interrupt_handler function returns NULL for so called “spurious” interrupts,<br />

which have no explicitly assigned ISRs.<br />

(7) The QK-specific interrupt entry starts with disabling all interrupts by setting the GM mask in SR.<br />

(8) The address of the QK_isrNest_ variable is loaded to R8.<br />

(9) The value of the QK_isrNest_ variable is loaded to R9.<br />

(10) The value in R9 is decremented by -1 (i.e., incremented by +1).<br />

(11) The incremented value is stored in QK_isrNest_.<br />

(12) All interrupts are re-enabled by clearing the GM mask in SR.<br />

NOTE: Incrementing the QK_isrNest_ up-down counter is necessary to establish interrupt context<br />

for QK, so that the event posts made inside the user-defined ISRs don't inadvertently perform the<br />

synchronous preemptions.<br />

(13) The user-defined ISR returned in R12 by _get_interrupt_handler is called as a regular C<br />

function (so the LR is set to return to the low-level interrupt handler).<br />

NOTE: The user-defined ISR is a regular C function, not any special compiler-generated interrupt<br />

function.<br />

(14) After the user-defined ISR returns, the QK-specific interrupt exit starts with disabling all interrupts by<br />

setting the GM mask in SR.<br />

(15) The address of the QK_isrNest_ variable is loaded to R8.<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

22 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

(16) The value of the QK_isrNest_ variable is loaded to R9.<br />

(17) The value in R9 is decremented by 1.<br />

(18) The decremented value in R9 is tested and the Z flag in SR is set if it is zero.<br />

(19) The decremented value is stored in QK_isrNest_.<br />

(20) If the value is stored in QK_isrNest_ is not zero we have interrupt nesting, so the branch is taken to<br />

return from this interrupt level.<br />

NOTE: Finding out if this interrupt nests on top of another interrupt is critical for calling the QK<br />

scheduler. The scheduler should not be called if an interrupt that nests on top of another interrupt,<br />

because this would lead to priority inversion of executing a task before a (preempted) interrupt.<br />

Testing of the QK_isrNest_ up-down counter is not sufficient to determine that the current<br />

interrupt does not nest on top of another interrupt. This is because with the <strong>AVR32</strong> CPU it is always<br />

possible that the interrupt preemption happens before the QK_isrNest_ counter is incremented, no<br />

matter how early in the interrupt handler the QK_isrNest_ counter is incremented.<br />

Therefore, to detect for sure that this interrupt does not nest on top of another interrupt the value of<br />

the SR register saved on the stack is examined in the lines (21-24).<br />

(21) The value of the SR before preemption saved on the stack by the <strong>AVR32</strong> CPU is loaded into R8.<br />

The interrupt stack frame saved automatically by the <strong>AVR32</strong><strong>UC</strong> hardware is shown below. As you<br />

can see the saved SR is available right at the top of stack (at SR[0]).<br />

Hi memory<br />

. . .<br />

R8<br />

R9<br />

R10<br />

R11<br />

R12<br />

LR<br />

PC (interrupt return address)<br />

SP --> SR (saved SR)<br />

Low memory<br />

(22) This instruction isolates the three mode bits (M2, M1, M1) in the R8 register.<br />

(23) The mode bits are compared to the Supervisor mode (M2=0, M1=0, M0=1)<br />

(24) Branch is taken if the mode of the saved SR is not Supervisor<br />

(25) If branch has not been taken, the QK_schedPrio_ function is called to find out the highest-priority<br />

task ready to run. The non-zero priority of this task is returned (in R12), otherwise zero is returned.<br />

(26) Branch to interrupt return is taken if the returned value is zero, which means that no higher-priority<br />

task (than the currently executing) exists.<br />

At this point, we are certain that a higher-priority task needs to preempt the current task. However, the<br />

<strong>AVR32</strong><strong>UC</strong> CPU is still in the Interrupt mode and w need to be in the Supervisor mode to run this new<br />

task. The only way to switch the mode is to return from the interrupt (via the rete instruction), but this<br />

instruction will pop R8-R12, LR, PC, and SR off the stack, which we don't want, because this stack frame<br />

belongs to the already preempted lower-priority task. The only way out is to establish a “fake” interrupt<br />

stack frame for the rete instruction which will cause to “return” to the QK scheduler in Supervisor mode.<br />

The following code perform this tricky operation by building the following stack frame:<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

23 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

Hi memory<br />

. . .<br />

R8<br />

R9<br />

R10<br />

R11<br />

R12<br />

LR<br />

PC (interrupt return address)<br />

old SP --> SR (saved SR)<br />

R8 - don't care<br />

R9 - don't care<br />

R10 – don't care<br />

R11 – don't care<br />

R12 – the task priority returned from QK_schedPrio_<br />

LR - label sched_ret for the QK_sched_ to return to<br />

PC - QK scheduler function QK_sched_<br />

new SP --> SR - 0x0041000 (Supervisor mode, GM set, INT0-INt3 cleared)<br />

Low memory<br />

(27) The stack pointer is decremented by 4 registers (the don't care R8-R11)<br />

(28) The value of R12 (task priority) is moved to R8 to be pushed on the stack<br />

(29-30) The address of the sched_ret label is loaded into R9 to be pushed on the stack<br />

(31-32) The address of the QK_sched_ function is loaded into R10 to be pushed on the stack<br />

(33) The desired value of the SR register is (Supervisor) is synthesized in R11<br />

(34) All the values prepared in the registers are pushed on the stack to finish the “fake” interrupt stack<br />

frame.<br />

(35) The rete instruction removes this “fake” stack frame to jump into the QK_sched_ function in<br />

Supervisor mode, GM set (interrupts disabled), and INT0-IN3 cleared.<br />

As mentioned before, the LR register of the “fake” interrupt frame has been set up such that the QK<br />

scheduler QK_sched_ returns to the label sched_ret. At this point, we have another context switch<br />

problem. The QK_sched_ runs and returns in the Supervisor mode of the <strong>AVR32</strong><strong>UC</strong> processor, but we<br />

need to return to the originally preempted task using an exception stack frame established by the interrupt<br />

entry (see the stack frame at label (21)). Please note that we cannot simply use the rete instruction,<br />

because the CPU mode is Supervisor, not Interrupt. The solution is to use the special Supervisor return<br />

instruction rets, which is capable of performing a mode switch. The challenge now is to convert the<br />

existing interrupt stack frame into a supervisor-call stack frame shown below. As you can see, the new<br />

Supervisor stack frame overlaps with the old Interrupt stack frame, so care must be taken not to lose any<br />

register values without clobbering the “lower” registers (R0-R7), which are not saved.<br />

Hi memory<br />

. . .<br />

Old PC (interrupt return address)<br />

new SP --> Old SR (saved SR)<br />

R10<br />

R11<br />

R12<br />

LR<br />

PC (interrupt return address)<br />

old SP --> SR (saved SR)<br />

Low memory<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

24 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

(36) The stack pointer to the new Supervisor stack frame is temporarily established in R12<br />

(37) The previous values of registers R8-R9 are popped from the Supervisor stack frame to make room<br />

for PC, SR<br />

(38) The old PC, SR are popped from the Interrupt stack frame into R10, R11<br />

(39) The old PC, SR are stored into the Supervisor stack frame<br />

(40) The Interrupt stack frame is destroyed by popping the registers R10, R11, R12, and LR. At this point<br />

the Supervisor stack frame is on top of the stack and all registers are restored from the original<br />

Interrupt stack frame.<br />

(41) The rets instruction returns to the original task restoring the original SR.<br />

4.4 Idle Loop Customization in the QK_onIdle()<br />

The idle task is handled differently In the QK preemptive kernel than in the “vanilla” port. The difference is<br />

that the idle callback function QK_onIdle() is invoked with interrupts enabled (in contrast to the<br />

QF_onIdle(), which is called with interrupts disabled), because a preemptive kernel does not return to<br />

the idle loop as long as events are available.<br />

void QK_onIdle(void) {<br />

QF_INT_DISABLE();<br />

LED_On (LED0); /* toggle the LED0 on and then off, see NOTE01 */<br />

LED_Off(LED0);<br />

QF_INT_ENABLE();<br />

#ifdef Q_SPY /* use the idle cycles for QS transmission */<br />

if ((QS_USART->csr & <strong>AVR32</strong>_USART_CSR_TXRDY_MASK) != 0U) { /* ready? */<br />

uint16_t b;<br />

QF_INT_DISABLE();<br />

b = QS_getByte();<br />

QF_INT_ENABLE();<br />

}<br />

if (b != QS_EOD) {<br />

QS_USART->thr = (b


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

5 The QS Software Tracing Instrumentation<br />

This <strong>QDK</strong> demonstrates how to use the QS software tracing instrumentation to generate real-time trace of<br />

a running QP application. Normally, the QS instrumentation is inactive and does not add any overhead to<br />

your application, but you can turn the instrumentation on by defining the Q_SPY macro and recompiling the<br />

code.<br />

QS is a software tracing facility built into all QP components and also available to the Application code.<br />

QS allows you to gain unprecedented visibility into your application by selectively logging almost all<br />

interesting events occurring within state machines, the framework, the kernel, and your application code.<br />

QS software tracing is minimally intrusive, offers precise time-stamping, sophisticated runtime filtering of<br />

events, and good data compression (see Chapter 11 in PSiCC2 [PSiCC2]).<br />

QS can be configured to send the trace data out of the serial port of the target device. On the <strong>AVR32</strong>, QS<br />

uses the built-in USART to send the trace data to the host. The <strong>UC</strong>3-A3-Xplained board exposes the<br />

USART pins, but needs an external level-shifter (see Figure 1). The QS platform-dependent<br />

implementation is located in the file bsp.c and looks as follows:<br />

Listing 9 QSpy implementation to send data out of the USART serial port of the <strong>AVR32</strong>.<br />

(1) #ifdef Q_SPY<br />

#include "usart.h"<br />

(2) #define QS_USART (&<strong>AVR32</strong>_USART1)<br />

#define QS_USART_RX_PIN <strong>AVR32</strong>_USART1_RXD_0_0_PIN<br />

#define QS_USART_RX_FUNCTION <strong>AVR32</strong>_USART1_RXD_0_0_FUNCTION<br />

#define QS_USART_TX_PIN <strong>AVR32</strong>_USART1_TXD_0_0_PIN<br />

#define QS_USART_TX_FUNCTION <strong>AVR32</strong>_USART1_TXD_0_0_FUNCTION<br />

(3) #define QS_BUF_SIZE 512U<br />

(4) #define QS_BAUD_RATE 115200U<br />

(5) static uint32_t l_tickCount = 0U;<br />

. . .<br />

(6) uint8_t QS_onStartup(void const *arg) {<br />

static uint8_t qsBuf[QS_BUF_SIZE]; /* buffer for <strong>Quantum</strong> Spy */<br />

static gpio_map_t const usart_gpio_map = {<br />

{ QS_USART_RX_PIN, QS_USART_RX_FUNCTION },<br />

{ QS_USART_TX_PIN, QS_USART_TX_FUNCTION }<br />

};<br />

usart_options_t const usart_options = {<br />

.baudrate = QS_BAUD_RATE,<br />

.charlength = 8,<br />

.paritytype = USART_NO_PARITY,<br />

.stopbits = USART_1_STOPBIT,<br />

.channelmode = USART_NORMAL_CHMODE<br />

};<br />

(7) QS_initBuf(qsBuf, sizeof(qsBuf));<br />

sysclk_enable_peripheral_clock(QS_USART);<br />

/* Setup GPIO for the QS USART */<br />

gpio_enable_module(usart_gpio_map, Q_DIM(usart_gpio_map));<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

26 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

/* Initialize the QS USART in RS232 mode */<br />

usart_init_rs232(QS_USART, &usart_options, sysclk_get_pba_hz());<br />

. . . /* setup the QS filters ... */<br />

return (uint8_t)1; /* indicate successful QS initialization */<br />

}<br />

/*..........................................................................*/<br />

(8) void QS_onCleanup(void) {<br />

}<br />

/*..........................................................................*/<br />

(9) void QS_onFlush(void) {<br />

uint16_t b;<br />

while ((b = QS_getByte()) != QS_EOD) { /* next QS trace byte available? */<br />

while ((QS_USART->csr & <strong>AVR32</strong>_USART_CSR_TXRDY_MASK) == 0U) { /*busy?*/<br />

}<br />

QS_USART->thr = (b


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

6 Related Documents and References<br />

Document<br />

[PSiCC2] “Practical UML Statecharts in C/C++,<br />

Second Edition”, Miro Samek, Newnes, 2008<br />

[QP 08] “QP Reference Manual”, <strong>Quantum</strong><br />

<strong>Leaps</strong>, LLC, 2008<br />

[QL AN-Directory 07] “Application Note: QP<br />

Directory Structure”, <strong>Quantum</strong> <strong>Leaps</strong>, LLC, 2007<br />

[QL AN-DPP 08] “Application Note: Dining<br />

Philosopher Problem Application”, <strong>Quantum</strong><br />

<strong>Leaps</strong>, LLC, 2008<br />

[<strong>AVR32</strong>] “<strong>AVR32</strong> “<strong>AVR32</strong> Architecture<br />

Document”, Atmel<br />

[<strong>AVR32</strong><strong>UC</strong>] “<strong>AVR32</strong><strong>UC</strong> Technical Reference<br />

Manual”, Atmel<br />

[<strong>AVR32</strong><strong>UC</strong>3A3/A4] “32-bit AVR Microcontroller<br />

AT32<strong>UC</strong>3A3256S, AT32<strong>UC</strong>3A3256,<br />

AT32<strong>UC</strong>3A3128S, AT32<strong>UC</strong>3A3128, ...”, Atmel<br />

[Samek 07a] “Using Low-Power Modes in<br />

Foreground/Background Systems”, Miro Samek,<br />

Embedded System Design, October 2007<br />

http://www.state-machine.com/doxygen/qpn/<br />

Location<br />

Available from most online book retailers, such as<br />

amazon.com. See also: http://www.statemachine.com/psicc2.htm<br />

http://www.statemachine.com/doc/AN_QP_Directory_Structure.pdf<br />

http://www.state-machine.com/doc/AN_DPP.pdf<br />

Document doc32000.pdf available from<br />

www.atmel.com/literature<br />

Document doc32002.pdf available from<br />

www.atmel.com/literature<br />

Document 32072s.pdf available from<br />

www.atmel.com/literature<br />

http://www.embedded.com/design/202103425<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

28 of 29


<strong>QDK</strong><br />

<strong>AVR32</strong><strong>UC</strong> with Atmel Studio<br />

www.state-machine.com/avr<br />

7 Contact Information<br />

<strong>Quantum</strong> <strong>Leaps</strong>, LLC<br />

103 Cobble Ridge Drive<br />

Chapel Hill, NC 27516<br />

USA<br />

+1 866 450 LEAP (toll free, USA only)<br />

+1 919 869-2998 (FAX)<br />

e-mail: info@quantum-leaps.com<br />

WEB : http://www.quantum-leaps.com<br />

http://www.state-machine.com<br />

“Practical UML<br />

Statecharts in C/C++,<br />

Second Edition:<br />

Event Driven<br />

Programming for<br />

Embedded Systems”,<br />

by Miro Samek,<br />

Newnes, 2008<br />

Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />

29 of 29

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!