QDK™ Atmel AVR32UC with Atmel Studioold.state-machine.com/avr/QDK_AVR32UC-GNU.pdf · QP state...

31
QP state machine frameworks for AVR QDK™ Atmel AVR32UC with Atmel Studio Document Revision B October 2012 Copyright © Quantum Leaps, LLC www.quantum-leaps.com www.state-machine.com

Transcript of QDK™ Atmel AVR32UC with Atmel Studioold.state-machine.com/avr/QDK_AVR32UC-GNU.pdf · QP state...

QP state machine frameworks for AVR

QDK™ Atmel AVR32UC with Atmel Studio

Document Revision BOctober 2012

Copyright © Quantum Leaps, LLC

www.quantum-leaps.com www.state-machine.com

Table of Contents

1 Introduction ..................................................................................................................................................... 1 1.1 About QP™ .................................................................................................................................................... 2 1.2 About QM™ ................................................................................................................................................... 3 1.3 About this QDK .............................................................................................................................................. 3 1.4 Licensing QP™ .............................................................................................................................................. 4 1.5 Licensing QM™ .............................................................................................................................................. 4

2 Getting Started ................................................................................................................................................ 5 2.1 Installation ...................................................................................................................................................... 5 2.2 Building the QP Libraries ............................................................................................................................... 7 2.3 Building the Examples .................................................................................................................................... 8 2.4 Running the Examples ................................................................................................................................... 9

3 The Vanilla QP Port ......................................................................................................................................... 11 3.1 The qep_port.h Header File ........................................................................................................................... 11 3.2 The qf_port.h Header File .............................................................................................................................. 11 3.3 The AVR32UC Exceptions and the qf_port.asm File ..................................................................................... 12 3.4 BSP for AVR32 .............................................................................................................................................. 16 3.5 QP Idle Loop Customization in QF_onIdle() ................................................................................................... 17 3.6 Assertion Handling Policy in Q_onAssert() .................................................................................................... 18

4 The QK Port ..................................................................................................................................................... 19 4.1 Single-Stack, Preemptive Multitasking on AVR32UC ..................................................................................... 19 4.2 The qk_port.h Header File ............................................................................................................................. 19 4.3 The Low-Level Interrupt Handlers for QK (file qk_port.asm) .......................................................................... 20 4.4 Idle Loop Customization in the QK_onIdle() .................................................................................................. 25

5 The QS Software Tracing Instrumentation ................................................................................................... 26

6 Related Documents and References ............................................................................................................. 28

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

Copyright © Quantum Leaps, LLC. All Rights Reserved.

1 IntroductionThis QP™ Development Kit (QDK) describes how to use the QP/C™ state machine framework with the Atmel AVR32 UC and the Atmel Studio 6 and the GNU AVR32 compiler. The actual hardware/software used to test this QDK as shown in Figure 1 and described below:

Figure 1 Atmel UC3-A3-Xplained board with the AT32UC3A3256 device and JTAGICE-mkII.

1 of 29

LED0

UC3-A3-Xplainedboard

JTAGICEmkII

JTAGconnector

TTL-RS232transceiver

RS-232to PC

Powerfrom PCvia USB

LED1

LED2

LED3

J4

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

The actual hardware/software used to test this QDK is described below:

1. Atmel UC3-A3-Xplained board with the AT32UC3A3256 device

2. JTAGICE mkII debugger

3. Atmel Studio 6.0

4. AVR32-GCC for windows (bundled with Atmel Studio 6.0)

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

As shown in Figure 1, the UC3-A3-Xplained board is powered via a USB cable and is connected to the JTAG-mkII emulator via the JTAG ribbon cable. This QDK has been tested on the AT32UC3A3256 device with 64KB of RAM and 256KB of on-board flash. However, the described port should be applicable to most microcontrollers based on the AVR32 UC CPU.

1.1 About QP™

QP™ is a family of very lightweight, open source, state machine-based frameworks for developing event-driven applications. QP enables building well-structured embedded applications as a set of concurrently executing hierarchical state machines (UML statecharts) directly in C or C++. QP is described in great detail in the book “Practical UML Statecharts in C/C++, Second Edition: Event-Driven Programming for Embedded Systems” [PSiCC2] (Newnes, 2008).

As shown in Figure 2, QP consists of a universal UML-compliant event processor (QEP), a portable real-time framework (QF), a tiny run-to-completion kernel (QK), and software tracing instrumentation (QS). Current versions of QP include: QP/C™ and QP/C++™, which require about 4KB of code and a few hundred bytes of RAM, and the ultra-lightweight QP-nano, which requires only 1-2KB of code and just several bytes of RAM. The Linux port described in this Application Note pertains to QP/C and QP/C++.

Figure 2 QP components and their relationship with the target hardware, board support package (BSP), and the application comprised of state machines

2 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

QP can work with or without a traditional RTOS or OS. In the simplest configuration, QP can completely replace a traditional RTOS. QP can manage up to 63 concurrently executing tasks structured as state machines (called active objects in UML).

1.2 About QM™

QM™ (QP™ Modeler) is a free, cross-platform, graphical UML modeling tool for designing and implementing real-time embedded applications based on the QP™ state machine frameworks. QM™ is available for Windows, Linux, and Mac OS X. QM™ provides intuitive diagramming environment for creating good looking hierarchical state machine diagrams and hierarchical outline of your entire application. QM™ eliminates coding errors by automatic generation of compact C or C++ code that is 100% traceable from your design. Please visit state-machine.com/qm for more information about QM™.

1.3 About this QDK

This QDK provides working examples of code running under both the cooperative Vanilla kernel and the preemptive QK kernel. The example code is based on the Dining Philosopher Problem (DPP) sample application described in Chapter 7 of [PSiCC2] as well as in the Application Note “Dining Philosopher Problem” [QL AN-DPP 08] (included in the example code distribution).

The entire source code included with this QDK can be edited manually in a traditional code editor. However, significant parts of the code have been generated automatically by the QM™ modeling tool from the dpp.qm model file included in the QDK. The preferred way of developing QP™ applications is to make all the changes in the model and generate the code automatically.

Figure 3: The example model opened in the QM™ modeling tool

3 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

The QDK-AVR32 example code includes the following components:

Board support package (BSP) which provides interrupt service routines (ISRs), all QP callbacks, and an interface to the board's LEDs, push buttons, system clock tick timer, and serial port.

QP port to AVR32UC for the Vanilla cooperative kernel described in Chapter 7 of [PSiCC2]

QP port to AVR32UC for the preemptive QK kernel described in Chapter 10 of [PSiCC2]

The DPP example for both the cooperative Vanilla kernel and the preemptive QK kernel.

The QM™ model of the Dinging Philosophers Problem (see Figure 3)

NOTE: The significant parts of the source code (files dpp.h, philo.c, and table.c) have been generated by the QM™ modeling tool from the dpp.qm model, which is the same for the Vanilla and QK versions of the DPP application. These files can be edited by hand (after unchecking the read-only property), but the changes made at the code level won't be incorporated back into the model.

1.4 Licensing QP™

The Generally Available (GA) distribution of QP™ available for download from the www.state-machine.com/ downloads website is offered with the following two licensing options:

The GNU General Public License (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 version 2 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.state-machine.com/licensing.

1.5 Licensing QM™

The QM™ graphical modeling tool available for download from the www.state-machine.com/ downloads website is free to use, but is not open source. During the installation you will need to accept a basic End-User License Agreement (EULA), which legally protects Quantum Leaps from any warranty claims, prohibits removing any copyright notices from QM, selling it, and creating similar competitive products.

4 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

2 Getting StartedThis section describes how to install, build, and use QDK-AVR32UC-GNU based two examples. This information is intentionally included early in this document, so that you could start using the QDK as soon as possible. The main focus of this section is to walk you quickly through the main points without slowing you down with full-blown detail.

NOTE: This QDK assumes that the standard QP distribution consisting of QEP, QF, and QK has been installed, before installing this QDK. It is also strongly recommended that you read the QP tutorial before you start experimenting with this QDK.

2.1 Installation

The QDK code is distributed in a ZIP archive (qdkc_avr32uc-gnu.zip. You can unzip the archive into the same directory into which you’ve 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-AVR32UC-GNU distribution. (Please note that the QP directory structure is described in detail in a separate Application Note: “QP Directory Structure”):

Listing 1 Selected QP directories and files after installing QDK-AVR32UC-GNU. The highlighted elements are included in the standard QDK-AVR32UC-GNU distribution.

qpc\ - QP installation directory +-doc\ | +-AN_DPP.pdf - Application Note “Dining Philosopher Problem Example” | +-QDK_AVR-GNU-STK600.pdf – This QDK Manual “QDK AVR32UC with GNU Compiler” | +-include/ - QP public include files | +-examples/ - subdirectory containing the examples | +-avr32uc/ - examples for AVR32UC | | +-qk/ - QK examples | | | +-gnu/ - GNU AVR compiler | | | | +-dpp-qk_uc3a3xplained/ - DPP example for UC3A3Xplained board | | | | | +-Debug/ - directory containing the Debug build | | | | | +-Release/ - directory containing the Release build | | | | | +-Spy/ - directory containing the Spy build | | | | | +-src/ - source directory | | | | | | +-asf/ - Atmel Software Framework (ASF) directory (generated) | | | | | | | +-... - ASF sub-directories (generated) | | | | | | +-dpp.h - the DPP header file | | | | | | +-dpp.qm - QM model for the DPP application | | | | | | +-bsp.c - Board Support Package for AVR | | | | | | +-bsp.h - BSP header file | | | | | | +-main.c - the main function | | | | | | +-philo.c - the Philosopher active object | | | | | | +-table.c - the Table active object | | | | | +-dpp-qk_uc3a3xplained.atsln – Atmel Studio 6 solution | | | | | +-dpp-qk_uc3a3xplained.cproj – Atmel Studio 6 project | | | | | +-vanilla/ - Vanilla kernel examples | | | +-gnu/ - GNU AVR compiler | | | | +-dpp_uc3a3xplained/ - DPP example for UC3A3Xplained board | | | | | +-Debug/ - directory containing the Debug build

5 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

| | | | | +-Release/ - directory containing the Release build | | | | | +-Spy/ - directory containing the Spy build | | | | | +-src/ - source directory | | | | | | +-asf/ - Atmel Software Framework (ASF) directory (generated) | | | | | | | +-... - ASF sub-directories (generated) | | | | | | +-dpp.h - the DPP header file | | | | | | +-dpp.qm - QM model for the DPP application | | | | | | +-bsp.c - Board Support Package for AVR | | | | | | +-bsp.h - BSP header file | | | | | | +-main.c - the main function | | | | | | +-philo.c - the Philosopher active object | | | | | | +-table.c - the Table active object | | | | | +-dpp_uc3a3xplained.atsln – Atmel Studio 6 solution | | | | | +-dpp_uc3a3xplained.cproj – Atmel Studio 6 project | +-ports/ - QP ports | +-avr32uc/ - AVR32UC port | | +-qk/ - QK (preemptive) ports | | | +-gnu/ - GNU compiler | | | | +-dbg/ - QP library – Debug configuration | | | | | +-libqp_uc3a3256.a - QP library for UC3A3256 device | | | | +-rel/ - QP library – Release configuration | | | | +-spy/ - QP library – Spy configuration | | | | | | | | | +-make_uc3a3256.bat - make script for building the QP libraries | | | | +-qep_port.h - QEP port | | | | +-qf_port.h - QF port | | | | +-qk_port.h - QK port | | | | +-qk_port.asm - QK port implementation | | | | +-qs_port.h - QS port | | | | | +-vanilla/ - “vanilla” (cooperative) ports | | | +-gnu/ - GNU compiler | | | | +-dbg/ - QP library – Debug configuration | | | | +-dbg/ - QP library – Release configuration | | | | +-spy/ - QP library – Spy configuration | | | | | +-libqp_uc3a3256.a - QP library for UC3A3256 device | | | | | | | | | +- make_uc3a3256.bat - make script for building the QP libraries | | | | +-qep_port.h - QEP port | | | | +-qf_port.h - QF port | | | | +-qf_port.asm - QF port implementation | | | | +-qs_port.h - QS port | | | | +-qp_port.h - QP port

6 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

2.2 Building the QP Libraries

All QP components are deployed as libraries that you statically link to your application.-QP is deployed as a library that you statically link to your application. The pre-built QP libraries for various build configurations are provided inside the <qp>\ports\avr32uc\ 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 Atmel Studio 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 don’t need to rebuild them—at least not on the daily basis as you work on your application. This QDK uses the Atmel Studio 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_uc3a3256.bat for building all the libraries located in <qp>\ports\avr32uc\vanilla\gnu\ directory.

For example, to build the debug version of all the QP libraries for the AVR32, with the GNU AVR32 compiler, you open a console window on a Windows PC, change directory to <qp>\ports\-avr32uc\vanilla\gnu\, and invoke the batch by typing at the command prompt the following command:

make_uc3a3256.bat

The make process should produce the QP libraries in the location: <qp>\ports\avr32uc\vanilla\-gnu\dbg\. The make_uc3a3256.bat assumes that the GNU-AVR32 toolset has been installed in the directory C:\tools\Atmel\Studio_6.0\extensions\Atmel\AVRGCC\3.4.0.65\AVRToolchain.

NOTE: You need to adjust the symbol GNU_AVR at the top of the make_uc3a3256.bat file if you’ve installed the Atmel Studio in a different directory.Also, to build the QP libraries for a different AVR32 device, you need to change the symbol TARGET_MCU in the make_uc3a3256.bat file.

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_uc3a3256.bat utility with the “spy” target, like this:

make_uc3a3256.bat spy

The make process should produce the QP libraries in the directory: <qp>\ports\avr32uc\vanilla\-gnu\spy\.

NOTE: The QP libraries and QP applications can be built in the following three build configurations:Debug - this configuration is built with full debugging information and minimal optimization. When the QP framework finds no events to process, the framework busy-idles until there are new events to process.Release - this configuration is built with no debugging information and high optimization. Single-stepping and debugging is effectively impossible due to the lack of debugging information and optimized code, but the debugger can be used to download and start the executable. When the QP framework finds no events to process, the framework puts the CPU to sleep until there are new events to process.Spy - like the debug variant, this variant is built with full debugging information and minimal optimization. Additionally, it is build with the QP's Q-SPY trace functionality built in. The on-board serial port and the Q-Spy host application are used for sending and viewing trace data. Like the Debug configuration, the QP framework busy-idles until there are new events to process.

You choose the build configuration by providing a target to the make_uc3a3256.bat utility. The default target is “dbg”. Other targets are “rel”, and “spy” respectively. The following table summarizes the targets accepted by make_uc3a3256.bat .

7 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

2.3 Building the Examples

The QDK contains the Atmel Studio project files located in <qp>\examples\avr32uc\vanilla\gnu-\dpp_uc3a3xplained\dpp_uc3a3xplained.atsln for the “vanilla” version, and in <qp>\-examples\avr32uc\qk\gnu\dpp-qk_uc3a3xplained\dpp-qk_uc3a3xplained.atsln for the QK version, respectively.

NOTE: The particular directory structure in the example projects has been generated by the Atmel Studio project wizard and is based on the Atmel Software Framewrok (ASF). The projects have been subsequently modified for QP.

Figure 4 The DPP example project opened in Atmel Studio.The build configuration is selected by the drop-down box.

8 of 29

Select buildconfiguration

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

2.4 Running the Examples

To execute and debug the provided examples you need the Atmel UC3-A3-Xplained board and the JTAG pod, such as the JTAGICE mkII shown in Figure 1. You need to set up the Atmel Studio to use the JTAG pod “Tool” that you have.

After powering up both the board and the JTAG pod, you can click on the “Start Debugging” button in the Atmel Studio, at which point the DPP example code will be programmed to the flash memory of the microcontroller. The programming takes several seconds and the code should start executing and the LEDs of the UC3-A3-Xplained board should start blinking. The LEDs 1, 2, and 3 in the corners of the board (see Figure 1) represent philosophers 0-2.One of these LEDs turned on represents an “eating” philosopher. Extinguished LED represents philosopher “thinking” or “hungry”.

The LED0 in the top-left corner of the board is used to visualize the idle loop activity. The LED0 is rapidly toggled on and off from the idle callback, so its intensity is proportional to the frequency of idle loop.

2.4.1 Q-SPY Software TracingQS 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 time-stamping, sophisticated runtime filtering of events, and good data compression (see Chapter 11 in [PSiCC2]).

For the QS (Q-SPY) software tracing output, you need to connect a TTL to RS-232 transceiver to the UC3-A3-Xplained board, as shown in Figure 5. The figure shows the RS232 to TTL converter board 3.3V to 5V from NKC Electronics (http://www.nkcelectronics.com/rs232-to-ttl-converter-board-33v232335.html), but you can use any other equivalent board.

Figure 5 Connecting RS232-TTL transceiver to the J4 connector of the UC3-A3-Xplained board.

To see the QS software trace output, you also need to download the Spy build configuration to the target board. Next you need to launch the QSPY host utility to observe the output in the human-readable format.

9 of 29

J4[8] ↔ VCCJ4[7] ↔ GNDJ4[4] ↔ TX

TX J4[4]

UC3-A3-Xplainedboard

TTL-RS-232transceiver

board

Q-SPY tracedata to host

J4

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

NOTE: The QSPY host utility is now included in the Qtools collection, which is available for a separate download from www.state-machine.com/downlaods. The following discussion assumes that you have downloaded and installed Qtools, including adding the Qtools directory to the PATH variable on your system.

You launch the QSPY utility on a Windows PC as follows:

qspy –c COM1 –b 115200

This will start the QSPY host application to listen on COM1 serial port with baud rate 1152400. (Please use the actual (virtual) COM port number on your PC.) The following screen shot shows the QSPY output from the DPP run:

Figure 6 Screen shot from the QSPY output.

10 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

3 The Vanilla QP PortThe “vanilla” port shows how to use Quantum Platform on a “bare metal” AVR32-based system without any underlying multitasking kernel.

In the “vanilla” version of the QP, the only component requiring platform-specific porting is the QF. The other two components: QEP and QS require merely recompilation and will not be discussed here. Obviously, with the vanilla port you’re not using the QK component.

In case of AVR32, the “vanilla” QF port is very similar to the generic “vanilla” port described in Chapter 9 of [PSiCC2].

3.1 The qep_port.h Header File

The QEP header file for the RX port is located in <qpc>\ports\avr32uc\vanilla\gnu\qep_port.h. Listing 2 shows the qep_port.h header file for AVR32UC CPU.

Listing 2 The qep_port.h header file for the AVR32UC-GNU port

#ifndef qep_port_h #define qep_port_h

#include <stdint.h> /* C99-standard exact-width integers */ #include "qep.h" /* QEP platform-independent public interface */

#endif /* qep_port_h */

3.2 The qf_port.h Header File

The QF header file for the AVR32UC port with the GNU compiler is located in <qp>/ports/avr32uc/-vanilla/gnu/qf_port.h. This file specifies the configuration constants for QF (see Chapter 8 in [PsiCC2]) as well as the interrupt disabling/enabling and the critical section policy, which is the most important decision you make in the QF port. The AVR32UC family of MCUs allows using the simplest “unconditional interrupt unlocking” policy (see Section 7.3.2 of [PSiCC2]), because AVR32UC provides a built-in, prioritized interrupt controller (INTC).

Listing 3 The qf_port.h header file

#ifndef qf_port_h #define qf_port_h

/* The maximum number of active objects in the application, see NOTE01 */ (1) #define QF_MAX_ACTIVE 32

/* QF interrupt disable/enable */ (2) #define QF_INT_DISABLE() __builtin_ssrf(16) (3) #define QF_INT_ENABLE() __builtin_csrf(16)

/* QF critical section entry/exit */ (4) /* QF_CRIT_STAT_TYPE not defined: unconditional interrupt unlocking" policy */ (5) #define QF_CRIT_ENTRY(dummy) QF_INT_DISABLE() (6) #define QF_CRIT_EXIT(dummy) QF_INT_ENABLE()

11 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

#include "qep_port.h" /* QEP port */ (7) #include "qvanilla.h" /* "Vanilla" cooperative kernel */ #include "qf.h" /* QF platform-independent public interface */ #endif /* qf_port_h */

(1) The QF_MAX_ACTIVE macro specifies the maximum number of active object priorities in the application. You always need to provide this constant. Here, QF_MAX_ACTIVE is set to 32 to save RAM. You can increase it up to the maximum limit of 63 active object priorities in the system.

(2) The QF_INT_DISABLE() macro resolves to the single instruction "SSRF 16". This single instruction sets the GM mask in the SR register, thereby disabling all interrupts.

(3) The QF_INT_ENABLE() macro resolves to the single instruction "CSRF 16". This single instruction clears the GM mask in the SR register, thereby enabling all interrupts.

NOTE: The AVR32 SR register holds also 4 masks to disable individual interrupt priorities (IM0-IM3). These masks are independent from the GM mask (SR[16]).

(4) The QF_CRIT_STAT_TYPE macro is not defined, which means that the simple critical section policy of “unconditional interrupt locking and unlocking” is applied.

(5) The QF_CRIT_ENTRY() macro does not use its parameter in this case and simply unconditionally disables interrupts.

(6) The QF_CRIT_EXIT() macro does not use its parameter in this case and simply unconditionally re-enables interrupts.

NOTE: The simple and very efficient critical section policy does not allow nesting of critical sections. The AVR32US interrupt handlers don not disable interrupts upon entry, so the ISR itself is not a critical section with respect to the GM bit in SR.

(7) The “Vanilla” port includes the “qvanilla.h” header file.

3.3 The AVR32UC Exceptions and the qf_port.asm File

The standard Atmel Software Framework (ASF) projects for AVR32 generated by the project wizard in the Atmel Studio contain the file exception.S (in the src\asf\avr32\drivers\intc\ sub-directory), which defines all exception and interrupt handlers. This standard implementation is minimalist and designed for software development rather than deployment. For example, all exception handlers end up in an endless loop, which ties up the CPU completely and causes the application to “freeze”. While this is adequate for debugging, this “denial of service” after an exception is absolutely not acceptable for production release.

Also, the low-level interrupt handlers defined in exception.S provide a software-based “vectoring” feature, which calls user-defined Interrupt Service Routines (ISRs) in C. However, in the standard implementation, the ISRs in C still need to return via the 'rete' instruction, so in the GNU compiler they need to be defined as __attribute__((__interrupt__)) functions. This aspect is simplified in the QP implementation, because the existing low-level wrapper already performs function call to the regular C function to perform the vectoring, so the call to the user-defined ISR could just as well be a regular C function without any special return sequence generated by the compiler.

NOTE: The file exception.S (in the src\asf\avr32\drivers\intc\ sub-directory) generated by the Atmel Studio project wizard must be removed from the project, so that the QP-specific implementation can be linked in from the QP library.

12 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

The following Listing 4 shows the exception and interrupt handlers in the qf_port.asm file.

Listing 4 Exception and interrupt handling in qf_port.asm.

#include <avr32/io.h>

.section .exception, "ax", @progbits

////////////////////////////////////////////////////////////////////////////// // Start of Exception Vector Table // // EVBA must be aligned with a power of two strictly greater than the // EVBA-relative offset of the last vector. // .balign 0x200

// Export symbol .global _evba .type _evba, @function (1) _evba:

(2) .org 0x000 // Unrecoverable Exception (3) bral _handle_Unrecoverable_Exception

.org 0x004 // TLB Multiple Hit bral _handle_TLB_Multiple_Hit

.org 0x008 // Bus Error Data Fetch bral _handle_Bus_Error_Data_Fetch

. . .

.balign 4

(4) _handle_Unrecoverable_Exception: (5) mov R11, 0x000 (6) bral call_onAssert

_handle_TLB_Multiple_Hit: mov R11, 0x004 bral call_onAssert

_handle_Bus_Error_Data_Fetch: mov R11, 0x008 bral call_onAssert

. . .

.extern Q_onAssert // QP assertion handler

call_onAssert: (7) lddpc R12, exc_ptr // pointer to the "EXCEPTION\0" string (8) bral Q_onAssert // jump to the QP assertion handler

exc_ptr:

13 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

.word exc_str exc_str: .ascii "EXCEPTION\0" . . .

.balign 4 (9) .global _int0 .global _int1 .global _int2 .global _int3

.type _int0, @function .type _int1, @function .type _int2, @function .type _int3, @function

_int0:(10) mov R12, 0 // the paramter for _get_interrupt_handler(11) bral call_get_interrupt_handler

_int1: mov R12, 1 // the paramter for _get_interrupt_handler bral call_get_interrupt_handler

_int2: mov R12, 2 // the paramter for _get_interrupt_handler bral call_get_interrupt_handler

_int3: mov R12, 3 // the paramter for _get_interrupt_handler

call_get_interrupt_handler:(12) rcall _get_interrupt_handler // return the pointer to the ISR in R12(13) breq int_done // branch if return value (R12) == 0

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

int_done:(15) rete

(1) All exception handlers in AVR32 are relative to the Exception Vector Base Address (EVBA) system register.

(2) For example, the “Unrecoverable Exception” is placed at offset 0 from the EBA (see the exception addressed in the AVR32 data sheet).

(3) The address assignment leaves no room to handle the exception directly, so only a branch instruction to the handler fits in the allocated space.

(4) The exception is actually handled at this label.

(5) The address of the exception is moved to R11, which will be the second parameter for the Q_onAssert() function.

(6) Once the address of the exception is stored, another branch is taken to call the Q_onAssert() function.

14 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

(7) The pointer to the zero-terminated string “EXCEPTION” is moved to R12, which will be the first parameter for the Q_onAssert() function.

(8) The Q_onAssert() function is “called” with a branch instruction (instead of rcall) in order to avoid clobbering the LR register. The return address is unnecessary for Q_onAssert(), because the function is not supposed to return.

NOTE: The system handling of a hardware exception, such as bus error or privilege violation, must be very carefully designed before releasing the software into the field, just as the course of action to take after hitting an assertion. In fact, a system exception is a hardware-assisted assertion. Therefore, the exception handlers in the QP port call the QP assertion handler Q_onAssert(), which needs to be carefully designed to handle system failure in the most appropriate way.

(9) The following code defines four low-level AVR32 interrupt handlers (_int0, _int1, _int2, and _int3). All these handlers are called after the AVR32UC core saves R8-R12, LR, PC, and SR onto the system stack. This means that any of these saved registers can be used safely in the interrupt handler. The handlers can also safely call C functions, which can clobber R8-R12, LR, PC, and SR.

(10-11) Every low-level handler starts with saving the interrupt priority into R12 and branching to the part of the code common for all the handlers.

(12) This common part starts with the call to the _get_interrupt_handler function, which is a regular C function defined in the module intc.c. Note that the priority level saved in R12 is passed to this function as the first (and only) parameter.

(13) The _get_interrupt_handler function performs the “vectoring” of the interrupt request and returns the pointer to the user-defined ISR in R12. If the returned pointer is NULL, the return instruction automatically sets the Z flag in the SR, so the conditional branch (breq) can be taken if the returned vector is NULL.

NOTE: The _get_interrupt_handler function returns NULL for so called “spurious” interrupts, which have no explicitly assigned ISRs.

(14) The user-defined ISR returned in R12 is called as a regular C function (so the LR is set to return to the low-level interrupt handler).

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

NOTE: The user-defined ISR is a regular C function, not any special compiler-generated interrupt function.

15 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

3.4 BSP for AVR32

As mentioned before, the application examples provided in this Application Note are based on the ASF (Atmel Software Framework), which has been generated by the project wizard in the Atmel Studio. Therefore, most of the traditional Board Support Package (BSP) for AVR32 is already available, although spread out over many ASF directories and files. However, there are some QP-specific details that you need to pay attention to, and this section addresses these issues.

3.4.1 Starting and Prioritizing Interrupts in QF_onStartup()QP invokes the QF_onStartup() callback just before starting the event loop inside QF_run(). The QF_onStartup() function must configure and start the interrupts.

Listing 5 The QF_onStartup() callback

void QF_onStartup(void) { uint32_t count;

(1) INTC_init_interrupts(); /* initialize interrupt vectors */ /* set the tickISR IRQ number and priority */ (2) INTC_register_interrupt(&tickISR, AVR32_CORE_COMPARE_IRQ, AVR32_INTC_INT0);

/* setup the COUNT/COMPARE registers to generate system clock tick */ (3) __builtin_mtsr(SYSREG_COUNT, 0U); (4) __builtin_mtsr(SYSREG_COMPARE, BSP_TICK_PERIOD); }

(1) The AVR32 interrupt controller is initialized.

(2) Each interrupt in the system is registered. The interrupt is assigned the user-defined ISR function (tickISR in this case), the interrupt number, and the priority in the 0-3 range.

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

(4) The COMPARE system register is loaded with the value to generate interrupt in the desired number of clocks into the future. BSP_TICK_PERIOD is defined as (sysclk_get_pba_hz() / BSP_TICKS_PER_SEC).

3.4.2 The System Clock Tick ISRAs shown in Listing 5(3-4), the periodic system clock tick interrupt is implemented with the AVR32-specific cycle counter timer (the COUNT system register). This timer is left to run completely free and the interrupt is generated by re-loading the COMPARE moving the value in the COMPARE system register by the desired tick period into the future.

3.4.3 User-defined ISRsAs described before, the user-defined ISRs in this QP port to AVR32UC are regular C functions. The following Listing 6 shows the system clock tick ISR:

NOTE: The ISRs run with the global interrupt mask (GM) cleared, so they are not a critical section with respect to the QF_CRIT_ENTRY()/QF_CRIT_EXIT() macros.

16 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

Listing 6 The user-defined system clock tick ISR.

(1) static void tickISR(void) { /* see NOTE00 */ /* write to COMPARE to clear the interrupt request */ (2) __builtin_mtsr(SYSREG_COMPARE, BSP_TICK_PERIOD);

#ifdef Q_SPY (3) l_tickCount += BSP_TICK_PERIOD; #endif

(4) QF_TICK(&l_tickISR); }

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

(2) The write operation to the COMPARE system register clears the interrupt source.

(3) In the Q_SPY build configuration, the additional tick counter variable is incremented to extend the clock counter to 32 bits.

(4) The time-tick ISR must invoke QF_TICK(), and can also perform other actions, if necessary. The function QF_TICK() cannot be reentered, that is, it necessarily must run to completion and return before it can be called again. This requirement is automatically fulfilled, because here interrupts are locked throughout the interrupt processing.

3.5 QP Idle Loop Customization in QF_onIdle()

This QF port uses the standard QF_run() “vanilla” implementation described in Chapter 7 in the [PSiCC2] book. The standard QF_run() can very easily detect the situation when no events are available, in which case QF_run() calls the QF_onIdle() callback. You can use QF_onIdle() to suspended the CPU to save power, if your CPU supports such a power-saving mode. Please note that QF_onIdle() is called repetitively from the event loop whenever the event loop has no more events to process, in which case only an interrupt can provide new events. The QF_onIdle() callback is called with interrupts disabled, because the determination of the idle condition might change by any interrupt posting an event.

AVR supports several power-saving levels (consult the AVR data sheet for details). The following piece of code shows the QF_onIdle() callback that puts AVR into the idle power-saving mode. Please note that AVR architecture allows for very atomic setting the low-power mode and enabling interrupts at the same time.

Listing 7 QF_onIdle() for the “vanilla” AVR32UC port

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

(2) LED_On (LED0); /* toggle the LED0 on and then off, see NOTE02 */ (3) LED_Off(LED0);

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

QF_INT_ENABLE(); if ((QS_USART->csr & AVR32_USART_CSR_TXRDY_MASK) != 0U) { /* ready? */ uint16_t b;

QF_INT_DISABLE(); b = QS_getByte(); QF_INT_ENABLE();

17 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

if (b != QS_EOD) { QS_USART->thr = (b << AVR32_USART_THR_TXCHR_OFFSET) & AVR32_USART_THR_TXCHR_MASK; } }

#elif defined NDEBUG /* go to sleep and re-enable interrupts at the same time, see NOTE03 */ (5) __asm__ __volatile__ ("sleep 128");

#else (6) QF_INT_ENABLE(); #endif }

(1) The function QF_onIdle() is always called with interrupts disabled.

(2-3) The LED0 of the UC3-A3-Xplained board is turned on and off, so that the LED0 blinks for a few microseconds. This is done to visualize the idle loop activity, because the intensity of the LED0 is proportional to the frequency of invoking the QF_onIdle() callback.

(4) This part of the code is only used in the QSPY build configuration. In this case the idle callback is used to transmit the trace data using the USART of the AVR32 device.

(5) If the release configuration, the sleep mode is activated with the SLEEP 128 instruction.

NOTE: The SLEEP 128 instruction puts the CPU to sleep and clears the SR[GM] flag the same time. This re-enables interrupts atomically as the CPU enters the sleep mode.

(6) In the debug configuration, the interrupts are re-enabled.

3.6 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 for AVR32. The function simply locks all interrupts and enters a for-ever loop.

NOTE: This policy is only adequate for testing, but is not adequate for production release.

void Q_onAssert(char_t const Q_ROM * const Q_ROM_VAR file, int_t line) { QF_INT_DISABLE(); LED_On(LED0 | LED1 | LED2 | LED3); /* all LEDs on */ for (;;) { /* hang here in the for-ever loop */ } }

18 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

4 The QK PortThis section describes how to use QP on AVR32UC CPU with the preemptive QK real-time kernel described in Chapter 10 of [PSiCC2]. The benefit is very fast, fully deterministic task-level response and that execution timing of the high-priority tasks (active objects) will be virtually insensitive to any changes in the lower-priority tasks. The downside is bigger RAM requirement for the stack. Additionally, as with any preemptive kernel, you must be very careful to avoid any sharing of resources among concurrently executing active objects, or if you do need to share resources, you need to protect them with the QK priority-ceiling mutex (again see Chapter 10 of [PSiCC2]).

NOTE: The preemptive configuration with QK uses more stack than the non-preemptive “Vanilla” configuration. You need to adjust the size of this stack to be large enough for your application.

4.1 Single-Stack, Preemptive Multitasking on AVR32UC

The AVR32UC architecture is designed primarily for the traditional real-time kernels that use multiple per-task stacks. This hardware design requires some quite expensive CPU mode switches, which are strictly speaking superfluous for the simplistic, run-to-completion, single-stack kernel, such as QK, because they don't alter the stack. This section explains how the single-stack preemptive QK kernel works on AVR32UC.

NOTE: Even though AVR32UC is not an ideal match for a run-to-completion, single-stack kernel, the kernel of this type still saves about 50% of the stack space and CPU cycles compared to any traditional preemptive kernel.

1. The AVR32CPU processor executes all tasks and the QK idle loop in the Supervisor mode, which is exactly the mode entered out of reset.

2. The processor uses only the System Stack. No per-task stacks are necessarily (QK is a single stack kernel).

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

4. The QK-specific interrupt entry and exit is provided in the low-level interrupt handlers in assembly, which subsequently call the user-defined ISRs. Consequently, the user-defined ISRs do not call the macros QK_ISR_ENTRY()/QK_ISR_EXIT(). These macros are not provided in the QK port.

5. The user-defined ISRs must be registered with the INTC_register_interrupt() call, in which each ISR is assigned one of the four interrupt priorities.

6. The user-defined ISRs execute outside of the critical section (defined by the GM mask in the SR register) and can preempt each other based on their interrupt priority.

NOTE: If you don’t wish the ISRs to preempt each other, you can always set the same interrupt priority to them.

4.2 The qk_port.h Header File

You configure and customize QK through the header file qk_port.h, which is located in the QP ports directory <qp>\ports\avr32uc\qk\gnu\. The qk_port.h for the AVR32UC CPU contains only the platform-independent qk.h header file and does not contain the macros QK_ISR_ENTRY/QK_ISR_EXIT.

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

19 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

/***************************************************************************** * NOTE: The macros QK_ISR_ENTRY/QK_ISR_EXIT are NOT used in the AVR32 port, * because this functionality is implemented in the low-level interrupt * handlers define in assembly in "qk_port.asm". */

4.3 The Low-Level Interrupt Handlers for QK (file qk_port.asm)

The QK-specific exception and interrupt handling is performed in the assembly module qk_port.asm, which to a large degree is similar to the qf_port.asm file for the “vanilla” kernel. In particular, the AVR32 exception handling for QK is identical as for the Vanilla kernel, as described in Section 3.3.

However, the interrupt handling for the preemptive QK kernel is obviously different than for the cooperative kernel. The following Listing 8 shows the exception and interrupt handlers for QK, implemented in the qk_port.asm file.

NOTE: The file exception.S (in the src\asf\avr32\drivers\intc\ sub-directory) generated by the Atmel Studio project wizard must be removed from the project, so that the QK-specific implementation can be linked in from the QP library.

Listing 8 Exception and interrupt handling in qk_port.asm..

#include <avr32/io.h>

.section .exception, "ax", @progbits . . . (1) _evba: .org 0x000 // Unrecoverable Exception bral _handle_Unrecoverable_Exception . . .

///////////////////////////////////////////////////////////////////////////// .balign 4 .extern QK_intNest_ .extern QK_schedPrio_ .extern QK_sched_

.global _int0 .global _int1 .global _int2 .global _int3

.type _int0, @function .type _int1, @function .type _int2, @function .type _int3, @function

(2) _int0: (3) mov R12, 0 // parameter for _get_interrupt_handler (4) bral call_get_interrupt_handler

_int1: mov R12, 1 // tparameter for _get_interrupt_handler

20 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

bral call_get_interrupt_handler

_int2: mov R12, 2 // parameter for _get_interrupt_handler bral call_get_interrupt_handler

_int3: mov R12, 3 // parameter for _get_interrupt_handler

call_get_interrupt_handler: (5) rcall _get_interrupt_handler // return the pointer to the ISR in R12 (6) breq int_ret // branch if return value (R12) == 0

// ---------------------------- QK_ISR_ENTRY() --------------------------- (7) ssrf 16 // disable interrupts (8) mov R8, LO(QK_intNest_) // load address of QK_intNest_ into R8 orh R8, HI(QK_intNest_) // ... (9) ld.ub R9, R8[0] // load value of QK_intNest_ into R9(10) sub R9, -1 // increment R9 by 1(11) st.b R8[0], R9 // store R9 in R8(12) csrf 16 // enable interrupts // ---------------------------- QK_ISR_ENTRY() ---------------------------

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

// ---------------------------- QK_ISR_EXIT() ----------------------------(14) ssrf 16 // disable interrupts(15) mov R8, LO(QK_intNest_) // load address of QK_intNest_ into R8 orh R8, HI(QK_intNest_) // ...(16) ld.ub R9, R8[0] // load value of QK_intNest_ into R9(17) sub R9, 1 // decrement R9 by 1(18) castu.b R9(19) st.b R8[0], R9(20) brne int_ret // QK_inNest_ != 0, return

(21) ld.w R8, SP[0*4] // read the stacked SR(22) bfextu R8, R8, 22, 3 // extract the mode bits to R8(23) cp.w R8, 1 // compare with supervisor mode (b'001)(24) brne int_ret // branch if not supervisor

(25) rcall QK_schedPrio_ // find the highest priority task(26) breq int_ret // branch if return is zero (no task) // ---------------------------- QK_ISR_EXIT() ----------------------------

(27) sub SP, 4*4 // fake pushing R8-R11(28) mov R8, R12 // future R12 - arg for QK_sched_(29) mov R9, LO(sched_ret) // future LR - sched_ret(30) orh R9, HI(sched_ret) // ...(31) mov R10, LO(QK_sched_) // future PC - QK_sched_(32) orh R10, HI(QK_sched_) // ...(33) movh R11, 0x0041 // future SR - Supervisor mode + GM(34) pushm R8-R9, R10, R11 // push R12, LR, PC, SR(35) rete // context-switch to the scheduler

sched_ret:(36) sub R12, SP, -6*4 // setup R12 as the Supervisor call stack

21 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

(37) ldm R12, R8-R9 // load saved R8, R9(38) popm R10, R11 // pop saved SR into R11 and PC into R10(39) stm R12, R10, R11 // make the Supervisor call stack frame(40) popm R10, R11, R12, LR // pop the rest of the context(41) rets // context switch to the interrupted task

int_ret: rete

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

(2) The following code defines four low-level AVR32 interrupt handlers (_int0, _int1, _int2, and _int3). All these handlers are called after the AVR32UC core saves R8-R12, LR, PC, and SR onto the system stack. This means that any of these saved registers can be used safely in the interrupt handler. The handlers can also safely call C functions, which can clobber R8-R12, LR, PC, and SR.

(3-4) Every low-level handler starts with saving the interrupt priority into R12 and branching to the part of the code common for all the handlers.

(5) This common part starts with the call to the _get_interrupt_handler function, which is a regular C function defined in the module intc.c. Note that the priority level saved in R12 is passed to this function as the first (and only) parameter.

(6) The _get_interrupt_handler function performs the “vectoring” of the interrupt request and returns the pointer to the user-defined ISR in R12. If the returned pointer is NULL, the function-return automatically sets the Z flag in the SR, so the conditional branch (breq) can be taken if the returned vector is NULL.

NOTE: The _get_interrupt_handler function returns NULL for so called “spurious” interrupts, which have no explicitly assigned ISRs.

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

(8) The address of the QK_isrNest_ variable is loaded to R8.

(9) The value of the QK_isrNest_ variable is loaded to R9.

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

(11) The incremented value is stored in QK_isrNest_.

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

NOTE: Incrementing the QK_isrNest_ up-down counter is necessary to establish interrupt context for QK, so that the event posts made inside the user-defined ISRs don't inadvertently perform the synchronous preemptions.

(13) The user-defined ISR returned in R12 by _get_interrupt_handler is called as a regular C function (so the LR is set to return to the low-level interrupt handler).

NOTE: The user-defined ISR is a regular C function, not any special compiler-generated interrupt function.

(14) After the user-defined ISR returns, the QK-specific interrupt exit starts with disabling all interrupts by setting the GM mask in SR.

(15) The address of the QK_isrNest_ variable is loaded to R8.

22 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

(16) The value of the QK_isrNest_ variable is loaded to R9.

(17) The value in R9 is decremented by 1.

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

(19) The decremented value is stored in QK_isrNest_.

(20) If the value is stored in QK_isrNest_ is not zero we have interrupt nesting, so the branch is taken to return from this interrupt level.

NOTE: Finding out if this interrupt nests on top of another interrupt is critical for calling the QK scheduler. The scheduler should not be called if an interrupt that nests on top of another interrupt, because this would lead to priority inversion of executing a task before a (preempted) interrupt.

Testing of the QK_isrNest_ up-down counter is not sufficient to determine that the current interrupt does not nest on top of another interrupt. This is because with the AVR32 CPU it is always possible that the interrupt preemption happens before the QK_isrNest_ counter is incremented, no matter how early in the interrupt handler the QK_isrNest_ counter is incremented.

Therefore, to detect for sure that this interrupt does not nest on top of another interrupt the value of the SR register saved on the stack is examined in the lines (21-24).

(21) The value of the SR before preemption saved on the stack by the AVR32 CPU is loaded into R8. The interrupt stack frame saved automatically by the AVR32UC hardware is shown below. As you can see the saved SR is available right at the top of stack (at SR[0]).

Hi memory . . . R8 R9 R10 R11 R12 LR PC (interrupt return address) SP --> SR (saved SR)Low memory

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

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

(24) Branch is taken if the mode of the saved SR is not Supervisor

(25) If branch has not been taken, the QK_schedPrio_ function is called to find out the highest-priority task ready to run. The non-zero priority of this task is returned (in R12), otherwise zero is returned.

(26) Branch to interrupt return is taken if the returned value is zero, which means that no higher-priority task (than the currently executing) exists.

At this point, we are certain that a higher-priority task needs to preempt the current task. However, the AVR32UC CPU is still in the Interrupt mode and w need to be in the Supervisor mode to run this new task. The only way to switch the mode is to return from the interrupt (via the rete instruction), but this instruction will pop R8-R12, LR, PC, and SR off the stack, which we don't want, because this stack frame belongs to the already preempted lower-priority task. The only way out is to establish a “fake” interrupt stack frame for the rete instruction which will cause to “return” to the QK scheduler in Supervisor mode. The following code perform this tricky operation by building the following stack frame:

23 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

Hi memory . . . R8 R9 R10 R11 R12 LR PC (interrupt return address)old SP --> SR (saved SR) R8 - don't care R9 - don't care R10 – don't care R11 – don't care R12 – the task priority returned from QK_schedPrio_ LR - label sched_ret for the QK_sched_ to return to PC - QK scheduler function QK_sched_new SP --> SR - 0x0041000 (Supervisor mode, GM set, INT0-INt3 cleared)Low memory

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

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

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

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

(33) The desired value of the SR register is (Supervisor) is synthesized in R11

(34) All the values prepared in the registers are pushed on the stack to finish the “fake” interrupt stack frame.

(35) The rete instruction removes this “fake” stack frame to jump into the QK_sched_ function in Supervisor mode, GM set (interrupts disabled), and INT0-IN3 cleared.

As mentioned before, the LR register of the “fake” interrupt frame has been set up such that the QK scheduler QK_sched_ returns to the label sched_ret. At this point, we have another context switch problem. The QK_sched_ runs and returns in the Supervisor mode of the AVR32UC processor, but we need to return to the originally preempted task using an exception stack frame established by the interrupt entry (see the stack frame at label (21)). Please note that we cannot simply use the rete instruction, because the CPU mode is Supervisor, not Interrupt. The solution is to use the special Supervisor return instruction rets, which is capable of performing a mode switch. The challenge now is to convert the existing interrupt stack frame into a supervisor-call stack frame shown below. As you can see, the new Supervisor stack frame overlaps with the old Interrupt stack frame, so care must be taken not to lose any register values without clobbering the “lower” registers (R0-R7), which are not saved.

Hi memory . . . Old PC (interrupt return address)new SP --> Old SR (saved SR) R10 R11 R12 LR PC (interrupt return address)old SP --> SR (saved SR)Low memory

24 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

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

(37) The previous values of registers R8-R9 are popped from the Supervisor stack frame to make room for PC, SR

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

(39) The old PC, SR are stored into the Supervisor stack frame

(40) The Interrupt stack frame is destroyed by popping the registers R10, R11, R12, and LR. At this point the Supervisor stack frame is on top of the stack and all registers are restored from the original Interrupt stack frame.

(41) The rets instruction returns to the original task restoring the original SR.

4.4 Idle Loop Customization in the QK_onIdle()

The idle task is handled differently In the QK preemptive kernel than in the “vanilla” port. The difference is that the idle callback function QK_onIdle() is invoked with interrupts enabled (in contrast to the QF_onIdle(), which is called with interrupts disabled), because a preemptive kernel does not return to the idle loop as long as events are available.

void QK_onIdle(void) {

QF_INT_DISABLE(); LED_On (LED0); /* toggle the LED0 on and then off, see NOTE01 */ LED_Off(LED0); QF_INT_ENABLE();

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

if ((QS_USART->csr & AVR32_USART_CSR_TXRDY_MASK) != 0U) { /* ready? */ uint16_t b;

QF_INT_DISABLE(); b = QS_getByte(); QF_INT_ENABLE();

if (b != QS_EOD) { QS_USART->thr = (b << AVR32_USART_THR_TXCHR_OFFSET) & AVR32_USART_THR_TXCHR_MASK; } }

#elif defined NDEBUG /* go to sleep and re-enable interrupts at the same time, see NOTE02 */ __asm__ __volatile__ ("sleep 128");

#endif }

25 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

5 The QS Software Tracing InstrumentationThis QDK demonstrates how to use the QS software tracing instrumentation 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.

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 time-stamping, sophisticated runtime filtering of events, and good data compression (see Chapter 11 in PSiCC2 [PSiCC2]).

QS can be configured to send the trace data out of the serial port of the target device. On the AVR32, QS uses the built-in USART to send the trace data to the host. The UC3-A3-Xplained board exposes the USART pins, but needs an external level-shifter (see Figure 1). The QS platform-dependent implementation is located in the file bsp.c and looks as follows:

Listing 9 QSpy implementation to send data out of the USART serial port of the AVR32.

(1) #ifdef Q_SPY #include "usart.h"

(2) #define QS_USART (&AVR32_USART1) #define QS_USART_RX_PIN AVR32_USART1_RXD_0_0_PIN #define QS_USART_RX_FUNCTION AVR32_USART1_RXD_0_0_FUNCTION #define QS_USART_TX_PIN AVR32_USART1_TXD_0_0_PIN #define QS_USART_TX_FUNCTION AVR32_USART1_TXD_0_0_FUNCTION (3) #define QS_BUF_SIZE 512U (4) #define QS_BAUD_RATE 115200U

(5) static uint32_t l_tickCount = 0U; . . .

(6) uint8_t QS_onStartup(void const *arg) { static uint8_t qsBuf[QS_BUF_SIZE]; /* buffer for Quantum Spy */ static gpio_map_t const usart_gpio_map = { { QS_USART_RX_PIN, QS_USART_RX_FUNCTION }, { QS_USART_TX_PIN, QS_USART_TX_FUNCTION } }; usart_options_t const usart_options = { .baudrate = QS_BAUD_RATE, .charlength = 8, .paritytype = USART_NO_PARITY, .stopbits = USART_1_STOPBIT, .channelmode = USART_NORMAL_CHMODE };

(7) QS_initBuf(qsBuf, sizeof(qsBuf));

sysclk_enable_peripheral_clock(QS_USART);

/* Setup GPIO for the QS USART */ gpio_enable_module(usart_gpio_map, Q_DIM(usart_gpio_map));

26 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

/* Initialize the QS USART in RS232 mode */ usart_init_rs232(QS_USART, &usart_options, sysclk_get_pba_hz());

. . . /* setup the QS filters ... */

return (uint8_t)1; /* indicate successful QS initialization */ } /*..........................................................................*/ (8) void QS_onCleanup(void) { } /*..........................................................................*/ (9) void QS_onFlush(void) { uint16_t b; while ((b = QS_getByte()) != QS_EOD) { /* next QS trace byte available? */ while ((QS_USART->csr & AVR32_USART_CSR_TXRDY_MASK) == 0U) { /*busy?*/ } QS_USART->thr = (b << AVR32_USART_THR_TXCHR_OFFSET) & AVR32_USART_THR_TXCHR_MASK; } } /*..........................................................................*/ /* NOTE: getTime is invoked within a critical section (interrupts disabled) */(10) QSTimeCtr QS_onGetTime(void) { return (QSTimeCtr)(__builtin_mfsr(SYSREG_COUNT) + l_tickCount); } #endif /* Q_SPY */

(1) The QS instrumentation is enabled only when the macro Q_SPY is defined

(2) Here the USART1 is used for QS, but you can adjust this macro to use other USARTs of your AVR32 MCU.

NOTE: Don't forget to adjust also the RX/TX pins when you change the USART.

(3) You should adjust the QS buffer size (in bytes) to your particular application

(4) You might want to adjust the USART baud rate to your particular system

(5) This l_tickClock variable is used to extend the COUNT timer to 32-bits.

(6) The QS_onStartup() callback performs the initialization of QS

(7) You always need to call QS_initBuf() from QS_onStartup() to initialize the trace buffer. This particular QS port initializes USART for data transfer at the given baud rate.

(8) The QS_onCleanup() callback performs the cleanup of QS. Here nothing needs to be done.

(9) The QS_onFlush() callback flushes the QS trace buffer to the host. Typically, the function busy-waits for the transfer to complete. It is only used in the initialization phase for sending the QS dictionary records to the host (see Chapter 11 in [PSiCC2])

(10) The QS_getTime() callback provides the time-stamp to the QS trace records. The QS time-stamping implementation uses the same COUNT timer that is also providing the time tick interrupt. The idea is simple: count the number of the overflows in the time-tick interrupt and add on the number of hardware clock ticks from the COUNT register.

27 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

6 Related Documents and References

Document Location[PSiCC2] “Practical UML Statecharts in C/C++, Second Edition”, Miro Samek, Newnes, 2008

Available from most online book retailers, such as amazon.com. See also: http://www.state-machine.com/psicc2.htm

[QP 08] “QP Reference Manual”, Quantum Leaps, LLC, 2008

http://www.state-machine.com/doxygen/qpn/

[QL AN-Directory 07] “Application Note: QP Directory Structure”, Quantum Leaps, LLC, 2007

http://www.state-machine.com/doc/AN_QP_Directory_Structure.pdf

[QL AN-DPP 08] “Application Note: Dining Philosopher Problem Application”, Quantum Leaps, LLC, 2008

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

[AVR32] “AVR32 “AVR32 Architecture Document”, Atmel

Document doc32000.pdf available from www.atmel.com/literature

[AVR32UC] “AVR32UC Technical Reference Manual”, Atmel

Document doc32002.pdf available from www.atmel.com/literature

[AVR32UC3A3/A4] “32-bit AVR Microcontroller AT32UC3A3256S, AT32UC3A3256, AT32UC3A3128S, AT32UC3A3128, ...”, Atmel

Document 32072s.pdf available from www.atmel.com/literature

[Samek 07a] “Using Low-Power Modes in Foreground/Background Systems”, Miro Samek, Embedded System Design, October 2007

http://www.embedded.com/design/202103425

28 of 29

Copyright © Quantum Leaps, LLC. All Rights Reserved.

QDK™AVR32UC with Atmel Studio

www.state-machine.com/avr

7 Contact Information

Quantum Leaps, LLC103 Cobble Ridge DriveChapel Hill, NC 27516USA

+1 866 450 LEAP (toll free, USA only)+1 919 869-2998 (FAX)

e-mail: [email protected] 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

29 of 29