Sunteți pe pagina 1din 29

QP state machine frameworks for AT91SAM7

QDK™
Atmel AT91SAM7S-EK with
IAR Toolset

Document Revision H
April 2009

Copyright © Quantum Leaps, LLC

www.quantum-leaps.com
www.state-machine.com
1 Introduction.................................................................................................... 1
1.1 What’s Included in the QDK-AT91SAM7S-EK? ....................................................... 2
1.2 Licensing QDK-AT91SAM7S-EK ........................................................................... 2
2 Getting Started ............................................................................................... 3
2.1 Directories and Files .......................................................................................... 3
2.2 Building the QP Libraries .................................................................................... 4
2.3 Building the Examples ....................................................................................... 4
2.4 Running the Examples ....................................................................................... 5
3 Board Support Package................................................................................... 7
3.1 Startup Code in Assembly .................................................................................. 7
3.1.1 Exception Vectors ....................................................................................... 7
3.1.2 Reset and MC Remapping ............................................................................ 8
3.2 Linker Command File....................................................................................... 11
3.3 Controlling Placement of the Code in Memory and ARM/THUMB Compilation ............ 12
3.4 BSP Functions in C .......................................................................................... 13
3.4.1 The Low-Level Initialization ........................................................................ 13
3.4.2 The Board Initialization .............................................................................. 14
3.4.3 The ISRs ................................................................................................. 15
3.4.3.1 ISRs in the Vanilla Port ..........................................................................15
3.4.3.2 ISRs in the QK Port, Mixed ARM/THUMB Mode...........................................17
3.4.4 QS Instrumentation................................................................................... 18
3.4.5 Idle Loop Customization............................................................................. 20
3.4.5.1 Idle Loop in the Vanilla Port....................................................................20
3.4.5.2 Idle Loop in the QK Port.........................................................................22
3.5 Loading the Code to Flash ................................................................................ 23
3.6 Manual Testing of Interrupt Preemptions Scenario ............................................... 24
4 References .................................................................................................... 26
5 Contact Information...................................................................................... 27

Copyright © Quantum Leaps, LLC. All Rights Reserved. i


1 Introduction
This QP Development Kit (QDK) describes how to use QP version 4.0 or later with the AT91SAM7S-
EK development board from Atmel and the IAR EWARM toolset. This QDK is based on the Applica-
tion Note “QP and ARM7/ARM with IAR Toolset” [QL 08a]. The actual hardware/software used in
this QDK is described below (see also Figure 1):

J-Link
J-TAG pod

external
power

4 LEDs

QSPY output
(NULL-modem
cable to PC)

Atmel
AT91SAM7S64
device

Figure 1 AT91SAM7S-EK evaluation board from Atmel and the J-Link pod.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 1 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

1. AT91SAM7S-EK evaluation board from Atmel (the board is based around the AT91SAM7S64
MCU) NOTE: The board, the J-Link pod, and software are bundled into the IAR AT91SAM7 Kick-
Start™ Kit available from IAR Systems (www.iar.com).
2. The J-Link J-Tag pod from Segger (www.segger.com). NOTE: IAR Embedded Workbench sup-
ports also several other J-Tag pods.
3. IAR Embedded Workbench® for ARM version 5.30, the free KickStart edition (www.iar.com)
4. QP/C/C++ version 4.0 or later (QEP, QF, QK, and QS)

1.1 What’s Included in the QDK-AT91SAM7S-EK?


This QDK provides the Board Support Package (BSP) and two example applications that implement
the two implementation options described in the Application Note “QP and ARM7/ARM with IAR
Toolset” [QL 08a].
1. The cooperative “Vanilla” kernel available in the QF real-time framework; and
2. The preemptive run-to-completion QK kernel.

NOTE: This QDK covers both the C and C++ version of QP. The concrete code examples are
taken from the C version, but the C++ version is essentially identical except for some trivial
syntax differences.

1.2 Licensing QDK-AT91SAM7S-EK


The Generally Available (GA) distribution of the ARM QDK available for download from the
www.quantum-leaps.com/downloads website is offered with the following two licensing options:
• The GNU General Public License version 2 (GPL) as published by the Free
Software Foundation and appearing in the file GPL.TXT included in the packag-
ing of every Quantum Leaps software distribution. The GPL open source li-
cense 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 com-
plete source code for your application must be also available under the condi-
tions of the GPL (GPL Section 2[b]).
• One of several Quantum Leaps commercial licenses, which are designed for customers who
wish to retain the proprietary status of their code and therefore cannot use the GNU General
Public License. The customers who license Quantum Leaps software under the commercial li-
censes 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.quantum-
leaps.com/licensing.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 2 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

2 Getting Started
This section describes how to install, build, and use the QDK- AT91SAM7S-EK based on two ver-
sions of an example application.
This document describes the standard QDK distribution, which must be augmented with the generic
ARM code accompanying the Application Note “QP and ARM7/ARM with IAR Toolset” [QL 08a] and
the standard distributions of the QP components. You need to download the following archives and
unzip all of them into the same directory of your choice. This directory will be referred to as QP
root directory and denoted <qp>:
1. QP baseline code: qpc_x.y.zz.zip (QP/C) or qpcpp_x.y.zz (for QP/C++)
2. This QDK: qdkc_arm-at91sam7s-iar_x.y.zz.zip (QP/C) or qdkcpp_arm-at91sam7s-iar_x.y.zz
(QP/C++)

NOTE: Please refer to the document “QL Licensing and Support” or to the HTML page at
www.quantum-leaps.com/licensing for details about the terms of licensing and technical sup-
port.

2.1 Directories and Files


The code of the QDK is organized according to the Application Note: “QP_Directory_Structure”.
Specifically, for this port the files are placed in the following directories:

<qp>/ - QP-root directory for Quantum Platform (QP) v4.0.xx


|
+-include/ - QP public include files
| +-qassert.h – Quantum Assertions platform-independent public include
| +-qevent.h – QEvent declaration
| +-qep.h – QEP platform-independent public include
| +-qf.h – QF platform-independent public include
| +-qk.h – QK platform-independent public include
| +-qs.h – QS platform-independent public include
| +-qs_dummy.h – QS “dummy” public include
| +-qequeue.h – native QF event queue include
| +-qmpool.h – native QF memory pool include
| +-qpset.h – native QF priority set include
| +-qvanilla.h – native QF non-preemptive “vanilla” kernel include
|
+-ports/ - QP ports
| +-arm/ - ARM port
| | +-vanilla/ - “vanilla” ports
| | | +-iar/ - IAR ARM compiler
| | | | +-dbg/ - QP libraries for Debug configuration
| | | | +-rel/ - QP libraries for Release configuration
| | | | +-spy/ - QP libraries for Spy configuration
| | | | +-make_ARM7TDMI.bat - batch script for building ARM7TDMI core QP libraries
| | | | +-qep_port.h – QEP platform-dependent public include
| | | | +-qf_port.h – QF platform-dependent public include
| | | | +-qs_port.h – QS platform-dependent public include
| | | | +-qp_port.h – QP platform-dependent public include
| | |
| | +-qk/ - QK ports
| | | +-iar/ - IAR ARM compiler
| | | | +-dbg/ - QP libraries for Debug configuration
| | | | +-rel/ - QP libraries for Release configuration
| | | | +-spy/ - QP libraries for Spy configuration

Copyright © Quantum Leaps, LLC. All Rights Reserved. 3 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm
| | | | +-qep_port.h – QEP platform-dependent public include
| | | | +-qf_port.h – QF platform-dependent public include
| | | | +-qk_port.h – QK platform-dependent public include
| | | | +-qs_port.h – QS platform-dependent public include
| | | | +-qp_port.h – QP platform-dependent public include
|
+-examples/ - QP examples
| +-arm/ - ARM CPU
| | +-vanilla/ - “Vanilla” port
| | | +-iar/ - IAR ARM compiler
| | | | +-dpp-at91sam7s-ek – DPP example for the AT91SAM7S-EK evaluation board
| | | | | +-dbg/ – Debug build (runs from RAM)
| | | | | | +-dpp.out – executable image
| | | | | +-rel/ – Release build (runs from Flash)
| | | | | | +-dpp.out – executable image
| | | | | +-spy/ – Spy build (runs from RAM)
| | | | | | +-dpp.out – executable image (instrumented with QSpy)
| | | | | +-at91mc_cstartup.s – AT91 startup code in assembly
| | | | | +-at91SAM7S64.icf – IAR ARM linker command file
| | | | | +-bsp.h - Board Support Package include file
| | | | | +-bsp.c - Board Support Package implementation
| | | | | +-dpp.h
| | | | | +-main.c
| | | | | +-philo.c
| | | | | +-table.c
| | | | | +-dpp.ewp – IAR project for the DPP application example
| | | | | +-dpp.eww – IAR workspace for the DPP application example
| | | |
| | +-qk/ - QK (Quantum Kernel) port
| | | +-iar/ - IAR ARM compiler
| | | | +-dpp-qk-at91sam7s-ek – DPP example for the AT91SAM7S-EK board with QK
| | | | | +-. . . – the same files as in vanilla/iar/dpp-at91sam7s
| . . .
Listing 1 Directories and files of QP. Directory and File names in bold indicate the
elements included in this QDK-AT91SAM7S-EK.

2.2 Building the QP Libraries


All QP components are deployed as static libraries that you link to your application. The pre-built
libraries for QEP, QF, QS, and QK are provided in the Application Note “QP and ARM7/ARM” [QL
08a], which also describes the process of building the QP libraries.

2.3 Building the Examples


The examples included in this QDK are based on the standard Dining Philosopher Problem imple-
mented with active objects (see Chapter 9 in [PSiCC2]).
The example directory contains the IAR Embedded Workbench workspace file dpp.eww that you can
load into the IAR EW IDE (see Figure 2). The workspace contains three build configurations (De-
bug, Release, and Spy) that you can select with the drop-down list, as shown in Figure 2.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 4 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

Select build
configuration

Figure 2 Building the DPP application in the IAR EWARM IDE.

2.4 Running the Examples


You need to use the IAR EWARM IDE to download the code to the target and debug it with the IAR
C-Spy debugger integrated into the IAR EWARM IDE. Before starting the debug session, you should
make sure that your J-tag pod (such as J-Link) is installed and connected to the target. The
AT91SAM7S-EK board should be powered up and connected to the J-Link with the 20-pin ribbon
cable (see Figure 1). The status LED on the J-Link pod should not flash.
To download the code click on Project | Debug menu (or the toolbar shortcut). This should load the
code and break at main(). To continue running, click Debug/Go, or F5, or select the toolbar short-
cut.
As the application is running, the status LEDs at the top of the board (see Figure 1) should blink
indicating the changing status of the Dining Philosophers. If you connect the serial NULL-cable to
the DBGU DB9 connector and your PC, you could launch the QSPY host utility to observe the output
in the human-readable format. You launch the QSPY utility on a Windows PC as follows. (1) Change
the directory to the QSPY host utility <qp>\tools\qspy\win32\vc2005\Release and execute
qspy –c COM1 –b 115200

Copyright © Quantum Leaps, LLC. All Rights Reserved. 5 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

This will start the qspy utility to listen on COM1 serial port with baud rate 115200. (Please use –c
COM2, or higher if you connected the NULL-cable to a different COM port on your PC.)
The following screen shot shows the QSPY output from the DPP run:

Figure 3 Screen shot from the QSPY output.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 6 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

3 Board Support Package


The Board Support Package (BSP) for the AT91SAM7S-EK evaluation board is co-located with the
DPP example applications and consists of the following files:
• at91mc_cstartup.s — startup code in assembly
• at91SAM7S64.icf — linker command file for executing the code out of Flash
• bsp.c — BSP functions and ISRs in C
• bsp.h — BSP header file

The BSP does not include drivers for all AT91SAM7 peripherals. However, it should be fairly com-
plete in that it supports debugging in RAM, code downloading to Flash, software tracing with Quan-
tum Spy (QS), fine-tuning of the release version, and more.

3.1 Startup Code in Assembly


The customized startup sequence for the AT91SAM7 is implemented in the assembly file
at91mc_cstartup.s co-located with the DPP example application. This file is based on the IAR
startup assembly module cstartup.s. You need to customize this code for the AT91SAM7 to provide
the Memory Controller (MC) re-mapping step, among other things. The “System Startup and Ter-
mination” Section in the “ARM® IAR C/C++ Compiler Reference Guide” describes how to customize
the cstarupt.s module.
The customized at91mc_cstartup.s module is designed to be generic for all AT91SAM7 devices with
the MC, not just to the AT91SAM7S64 and the AT91SAM7S-EK board. Typically, you should not
need to modify this file to work with other members of the AT91SAM7 family. All CPU and board
specifics should be handled in C, typically in the file bsp.c. The following sections describe the
structure of the at91mc_cstartup.s module.

3.1.1 Exception Vectors

;-----------------------------------------------------------------------------
; Reset and other vectors
;
(1) SECTION .intvec:CODE:NOROOT(2)
PUBLIC __vector
PUBLIC __iar_program_start
; Execution starts here.
; After a reset, the mode is ARM, Supervisor, interrupts disabled.
(2) CODE32 ; Always ARM mode after reset
(3) __vector:
(4) LDR pc,[pc,#24] ; load the secondary vector
LDR pc,[pc,#24] ; load the secondary vector
LDR pc,[pc,#24] ; load the secondary vector
LDR pc,[pc,#24] ; load the secondary vector
LDR pc,[pc,#24] ; load the secondary vector
LDR pc,[pc,#24] ; load the secondary vector
LDR pc,[pc,#24] ; load the secondary vector
LDR pc,[pc,#24] ; load the secondary vector
; The secondary jump talbe starts below. It contains the
; addresses for the PC-relative loads from the primary vector table.
; The secondary vectors are to be overwritten by the application to hook

Copyright © Quantum Leaps, LLC. All Rights Reserved. 7 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm
; up exception handlers at runtime. The default implementation provided
; below causes endless loops around the selected addresses.
; For example, a prefetch abort exception forces the PC to 0x0C and
; the address loaded from the secondary vector table will be again 0x0C.
;
(5) DC32 __iar_program_start ; Reset
DC32 0x04 ; Undefined Instruction
DC32 0x08 ; Software Interrupt
DC32 0x0C ; Prefetch Abort
DC32 0x10 ; Data Abort
DC32 0x14 ; Reserved
DC32 0x18 ; IRQ
DC32 0x1C ; FIQ
Listing 2 Reset and exception vectors defined in the at91mc_cstartup.s.

(1) This module defines interrupt vectors and is placed in the .intvec section.
(2) The ARM core always starts in ARM state, Supervisor mode, all interrupts disabled.
(3) The symbol __vector denotes the beginning the primary vector table.
(4) The primary vector table is pre-filled with jumps to the secondary jump table located immedi-
ately after the primary vector table at address 0x20. The secondary vector table is used for
maximum flexibility. Such jump table makes it much easier to hook any exception vector at real
time, by simply writing a pointer to one of the locations 0x20-0x3C, rather than having to syn-
thesize a branch instruction at the primary vector table. Also, the LDR instruction can access any
code within the full 32-bit address range, while the PC-relative branch instruction is limited to
0x02000000 from the current PC.

NOTE: Please note that the ARM core starts execution at address 0x0. Out of reset, the Flash
memory is mapped at this address. However, immediately after executing the LDR pc,[pc,#24]
instruction, the code starts executing from the address range above 0x00100000, in which al-
ways Flash is mapped, even after the MC remapping.

(5) The secondary jump table is initialized in such a way that any exception (except reset) causes
an endless loop to itself. For example, a Prefetch Abort exception located at address 0x0C
causes a jump also to 0x0C, so the CPU hangs in an endless loop around address 0x0C. Of
course this is only the initial setting, after which you application code should initialize the sec-
ondary vector table to handle exceptions any way you want.

NOTE: The simple exception vectors are only for initial setting, after which you application code
should initialize the secondary vector table to handle exceptions any way you want. In particu-
lar, you will need to adjust the interrupt exceptions (IRQ and FIQ).

3.1.2 Reset and MC Remapping


Normally, when the AT91SAM7 boots from Flash, the boot sequence performs the MC remap to re-
place slow Flash ROM with fast RAM at the address 0x0. However, in order to guarantee that the
ARM core is provided with valid vectors at all times, including the boot sequence itself, the vector
table must be initialized in RAM before the RAM is remapped down to address 0x0.

SECTION FIQ_STACK:DATA:NOROOT(3)
SECTION IRQ_STACK:DATA:NOROOT(3)
SECTION SVC_STACK:DATA:NOROOT(3)

Copyright © Quantum Leaps, LLC. All Rights Reserved. 8 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm
SECTION ABT_STACK:DATA:NOROOT(3)
SECTION UND_STACK:DATA:NOROOT(3)
SECTION CSTACK:DATA:NOROOT(3)
(1) SECTION .text:CODE:NOROOT(2)
REQUIRE __vector
EXTERN ?main
PUBLIC __iar_program_start
; Embed a copyright notice prominently at the begining of
; the Flash image.
;
(2) DC8 'Copyright (c) 2008, Quantum Leaps, LLC. All Rights Reserved.'
ALIGNROM 2 ; re-align after the string at 2^2 boundary
ARM ; reset always executes in ARM
(3) __iar_program_start:
; Copy the exception vectors from ROM to RAM
;
; NOTE: the exception vectors must be in RAM *before* the remap
; in order to guarantee that the ARM core is provided with valid vectors
; during the remap operation.
;
(4) LDR r8,=__vector ; Source
LDR r9,=AT91SAM7S_RAM ; Destination
(5) MOV r0,#0
(6) STR r0,[r9,#0] ; write zero at the start of RAM
(7) LDR r0,[r0,#0] ; read the location zero
(8) TEQ r0,#0 ; is the result equal to zero?

(9) LDMIA r8!,{r0-r7} ; Load Vectors


(10) STMIA r9!,{r0-r7} ; Store Vectors
(11) LDMIA r8!,{r0-r7} ; Load secondary vector table
(12) STMIA r9!,{r0-r7} ; Store secondary vector table
(13) LDR r0,=AT91SAM7S_MC
(14) MOV r1,#1
(15) STRNE r1,[r0,#0] ; Remap Memory, if not remapped already

; Initialize the stack pointers...


(16) MSR cpsr_c,#(IRQ_MODE | I_BIT | F_BIT) ; Change to IRQ mode
LDR sp,=SFE(IRQ_STACK) ; End of IRQ_STACK
(17) MSR cpsr_c,#(FIQ_MODE | I_BIT | F_BIT) ; Change to FIQ mode
LDR sp,=SFE(FIQ_STACK) ; End of FIQ_STACK
(18) MSR cpsr_c,#(SVC_MODE | I_BIT | F_BIT) ; Change to SVC mode
LDR sp,=SFE(SVC_STACK) ; End of SVC_STACK
(19) MSR cpsr_c,#(ABT_MODE | I_BIT | F_BIT) ; Change to ABT mode
LDR sp,=SFE(ABT_STACK) ; End of ABT_STACK
(20) MSR cpsr_c,#(UND_MODE | I_BIT | F_BIT) ; Change to UND mode
LDR sp,=SFE(UND_STACK) ; End of UND_STACK
(21) MSR cpsr_c,#(SYS_MODE | I_BIT | F_BIT) ; Change to SYSTEM mode
LDR sp,=SFE(CSTACK) ; End of CSTACK
; Add more initialization here...
; Continue to ?main for more IAR specific system startup
;
(22) LDR r12,=?main

Copyright © Quantum Leaps, LLC. All Rights Reserved. 9 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm
BX r12
; The code should never return from ?main, but just in case, put
; an endless loop here to hang the CPU.
; Alternatively, you might try a reset...
;
(23) B .
Listing 3 Reset and Memory Controller remapping

(1) The code is assembled to the regular .text segment


(2) It’s always a good idea to embed an ASCII copyright notice directly into the binary image. Such
a prominent ASCII text early in the binary image informs anybody attempting to reverse-
engineer the code about the origin and rights to the code. You should replace this copyright no-
tice with your company’s name.
(3) The symbol __iar_program_start is the standard entry point for the IAR startup code.
(4) The source and destination addresses for copying vectors from ROM to RAM are prepared in
registers
(5) Register r0 is loaded with zero.
(6) Zero is written at the beginning of the permanent RAM location.

NOTE: Unlike the earlier AT91X40 MCUs, the AT91SAM family keeps the RAM permanently
mapped to the address range starting at 0x00200000, and the MC remapping operation only
creates the RAM alias at the address 0x0.

(7) The memory at address zero is loaded to the register.


(8) The loaded value is tested against zero, which is the value written before at this location. If the
loaded value is indeed zero, this means that RAM is already mapped to zero and the remap
should not be done.

NOTE: In the AT91SAM the Memory Controller remap is a toggle, so doing a remap twice would
revert the remap, which is not what you want.
Also, please note that the value zero cannot be located at zero address of the ROM before the
remap. This location is the ARM reset vector and must contain a valid ARM instruction.
Finally, please note that the testing for remap is very handy when resetting the MCU from a
debugger, which resets only the ARM core, but does not reset the Memory Controller (including
the remap operation).

(9-10) The primary vector table copied to the RAM. This vector table is identical to the ROM table
in Listing 2. Please note that the ADDR pseudo-instruction is PC-relative, so the code is poison-
independent.
(11-12) The secondary jump table copied to the RAM. This jump table is also identical to the ROM
table in Listing 2.
(13-15) The actual Memory Controller remap is performed only if the ZERO flag hasn’t been set
earlier in the TEQ instruction (i.e., the memory remap has not occurred yet).
(16-21) All stacks are initialized to the end of the stack sections, because the stack grows towards
lower memory addresses (descending stack)

Copyright © Quantum Leaps, LLC. All Rights Reserved. 10 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

NOTE: This startup code is generic, so it allows configuring all the available stacks in the ARM
core. However, the QP ports (both the vanilla and the QK versions) use only the SYSTEM/USER
stack.

(22) The code branches to the low-level initialization ?main provided by the IAR standard library.
The IAR code initializes all the RAM sections from the ROM sections and finally invokes your
main() function in C. The “System Startup and Termination” Section in the “ARM® IAR C/C++
Compiler Reference Guide” describes in more detail what happens from that point on and how
you can customize further the initialization of the various sections.
(23) The control should never return back to the startup code, but just in case this branch will hang
the CPU in a tight loop.

3.2 Linker Command File


A linker command file controls where the linker will locate the code and data in memory. The BSP
for the AT91SAM7S-EK board comes with the file at91SAM7S64.icf to place the complete application
image in the Flash ROM. This file is not intended for manual editing, but rather only via the IAR
Embedded Workbench IDE, as shown in Figure 4.

Browse for the


linker file
Select
Linker
Edit the linker
configuration file

Figure 4 Editing the linker control script in the IAR Embedded Workbench IDE.
Copyright © Quantum Leaps, LLC. All Rights Reserved. 11 of 27
QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

Typically, you don’t need to adjust the memory addresses for the ARM device (in the Memory Re-
gions tab in Figure 4), because they come pre-configured when you select the specific device in the
General Options section. However, you should adjust the Stack and Heap Sizes on the third tab of
the “Linker configuration file editor” shown in Figure 4. Again, note that QP uses only the
USER/SYSTEM stack and does not use any other stacks. If you don’t use the heap, which is highly
recommended in any embedded application, you should also set the size of the heap to zero.

3.3 Controlling Placement of the Code in Memory and


ARM/THUMB Compilation
A very important and often overlooked aspect for optimal system performance is controlling both
the placement of the code in memory and the instruction set chosen to compile individual modules.
The placement of the code in memory is most important. For example, on a typical AT91 family
MCU, the code executing from the fast 32-bit wide on-chip SRAM can be three to four times faster
than the same code executing from the 16-bit wide Flash. This is 300 to 400% difference!
The instruction set can contribute to additional difference of 20 to 40% in the execution speed,
ARM being faster than THUMB when executed from 32-bit wide memory, and slower, when exe-
cuted from 16-bit wide memory.
Therefore, this QDK puts a lot attention on giving you fine-granularity of control over the place-
ment of the code in memory and instruction set compilation. Clearly, it’s advantageous to expend
some of the fast on-chip RAM to dramatically improve the performance.
In the IAR toolset, you can instruct the compiler to place the code in RAM by assigning it to the
.textrw section (see “ARM® IAR C/C++ Compiler Reference Guide”). You can achieve this by the
compiler option --section .text=.textrw. Similarly, you can instruct the compiler to produce either
THUMB or ARM code by the compiler option --cpu_mode thumb or --cpu_mode arm, respectively.
To enable fine-tuning of the code, the Makefile for each QP component allows you to specify the
code segment placement and instruction set for each individual fine-granularity module in the li-
brary. For example, the following fragment of the Makefile for building the QF library shows the
choices made for several QF components:
. . .
%CC% --cpu_mode thumb %CCFLAGS% %CCINC% -o%BINDIR% %SRCDIR%\qa_sub.c
%CC% --cpu_mode arm --section .text=.textrw %CCFLAGS% -o%BINDIR% %SRCDIR%\qvanilla.c
. . .

The module qa_sub.c, for instance, which contains subscribe/unsubscribe functions for active ob-
jects, is compiled to THUMB and placed in the default location, which is ROM (Flash). This is be-
cause the functionality must be merely correct, but not necessarily fast. On the other hand, the
module qvanilla.c is clearly a “hot-spot”, because it contains the cooperative “vanilla” klernel run-
ning the whole application (see Chapter 7 in [PSiCC2]) and therefore it is compiled to ARM and
placed in the fast RAM. Of course, you can fine-tune the code placement any way you like for your
particular project.
You could also apply similar strategy to your application code. Additionally, you could use the IAR
extended keyword __ramfunc to place selected functions in RAM. This option is used in the ISR code
discussed in Section 0.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 12 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

3.4 BSP Functions in C


The file bsp.c located in the directory <qp>\examples\arm\vanilla\iar\dpp-at91sam7s-ek contains
the ISRs, the initialization, and the QS port to the AT91SAM7S-EK board. The file bsp.c is mostly
about accessing the hardware. It indirectly includes (through the bsp.h header file) the IAR header
file ioat91sam7s64.h, which contains symbolic names for all registers defined inside the
AT91SAM7S64 MCU.

3.4.1 The Low-Level Initialization


The standard IAR initialization sequence that starts from ?main (see [2]), calls the function
__low_level_init().The function gives the application a chance to perform early initializations of
the hardware even before the segments are copied to RAM. This function cannot use any static
variables, because these have not yet been initialized in RAM. (See also “System Startup and Ter-
mination” Section in the “ARM® IAR C/C++ Compiler Reference Guide”.)
In the AT91SAM7 BSP, the __low_level_init() function is used to setup the PLL to speed up the
rest of the startup sequence.

(1) int __low_level_init(void) {


AT91PS_PMC pPMC = AT91C_BASE_PMC;
/* Set flash wait sate FWS and FMCN */
(2) AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN) & ((MCK + 500000)/1000000 << 16))
| AT91C_MC_FWS_1FWS;
(3) AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS; /* Disable the watchdog */

/* Enable the Main Oscillator: set OSCOUNT to 6, which gives


* Start up time = 8 * 6 / SCK = 1.4ms (SCK = 32768Hz)
*/
(3) pPMC->PMC_MOR = ((6 << 8) & AT91C_CKGR_OSCOUNT) | AT91C_CKGR_MOSCEN;
while ((pPMC->PMC_SR & AT91C_PMC_MOSCS) == 0) {/* Wait the startup time */
}
/* Set the PLL and Divider:
* - div by 5 Fin = 3,6864 =(18,432 / 5)
* - Mul 25+1: Fout = 95,8464 =(3,6864 *26)
* PLLCOUNT pll startup time estimate at : 0.844 ms
* PLLCOUNT 28 = 0.000844 / (1/32768)
*/
pPMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x05)
| (AT91C_CKGR_PLLCOUNT & (28 << 8))
| (AT91C_CKGR_MUL & (25 << 16)));
while ((pPMC->PMC_SR & AT91C_PMC_LOCK) == 0) { /* Wait the startup time */
}
while ((pPMC->PMC_SR & AT91C_PMC_MCKRDY) == 0) {
}

/* Select Master Clock and CPU Clock select the PLL clock / 2 */
pPMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
while ((pPMC->PMC_SR & AT91C_PMC_MCKRDY) == 0) {
}
pPMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK;
while ((pPMC->PMC_SR & AT91C_PMC_MCKRDY) == 0) {
}

(4) return 1; /* proceed with the segment initialization */


}
Listing 4 Low-level initialization in the BSP

Copyright © Quantum Leaps, LLC. All Rights Reserved. 13 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

(1) __low_level_init() is called from the IAR startup code before copying the DATA section and be-
fore zeroing the BSS section. (And also before calling the static constructors in C++).
(2) The number of Flash wait states FWS is set to 1 and the number FMCN (number of MCK cycles
in a microsecond) is set to the programmed MCK.
(3) The PLL is programmed
(4) The value returned by __low_level_init() determines whether or not data segments should be
initialized by __seqment_init(). If __low_level_init() returns 0, the data segments will NOT be
initialized. For more information see the "IAR ARM C/C++ Compiler Reference Guide".

3.4.2 The Board Initialization


The board initialization is performed in the BSP_init() function called from main().

void BSP_init(void) {
uint32_t i;
(1) for (i = 0; i < Q_DIM(l_led); ++i) { /* initialize the LEDs... */
AT91C_BASE_PIOA->PIO_PER = l_led[i]; /* enable pin */
AT91C_BASE_PIOA->PIO_OER = l_led[i]; /* configure as output pin */
LED_OFF(i); /* extinguish the LED */
}
/* configure Advanced Interrupt Controller (AIC) of AT91... */
(2) AT91C_BASE_AIC->AIC_IDCR = ~0; /* disable all interrupts */
AT91C_BASE_AIC->AIC_ICCR = ~0; /* clear all interrupts */
for (i = 0; i < 8; ++i) {
AT91C_BASE_AIC->AIC_EOICR = 0; /* write AIC_EOICR 8 times */
}
/* set the desired ticking rate for the PIT... */
i = (MCK / 16 / BSP_TICKS_PER_SEC) - 1;
(3) AT91C_BASE_PITC->PITC_PIMR = (AT91C_PITC_PITEN | AT91C_PITC_PITIEN | i);

(4) if (QS_INIT((void *)0) == 0) { /* initialize the QS software tracing */


Q_ERROR();
}
}
Listing 5 BSP initialization

(1) Configure the 4 LEDs of the AT91SAM7S-EK board


(2) All interrupts must be disabled at the interrupt controller level (AIC in this case). This is criti-
cal, because due to the simple policy of interrupt locking, later in the QF initialization phase the
interrupts will be unlocked at the ARM core level before the system is ready to receive them.
(3) Configure the Programmable Interval Timer (PIT) to deliver the QF time tick.

NOTE: The PIT has been specially designed to deliver the operating system time tick.

(4) Initialize the QS software tracing (this code is active only when the macro Q_SPY is defined).

Copyright © Quantum Leaps, LLC. All Rights Reserved. 14 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

3.4.3 The ISRs


The Interrupt Service Routines and the initialization of interrupts is the only part of the BSP de-
pendent on the QF port type. The following subsections discuss the ISRs for the three QF ports in-
cluded in this QDK.

3.4.3.1 ISRs in the Vanilla Port

(1) typedef void (*IntVector)(void); /* IntVector pointer-to-function */


/*..........................................................................*/
(2) __arm __ramfunc void BSP_irq(void) {
(3) IntVector vect = (IntVector)AT91C_BASE_AIC->AIC_IVR; /* read the IVR */
(4) QF_INT_UNLOCK_ARM(); /* allow nesting interrupts */
(5) (*vect)(); /* call the IRQ ISR via the pointer to function */
(6) QF_INT_LOCK_ARM(); /* lock interrupts for the exit sequence */
(7) AT91C_BASE_AIC->AIC_EOICR = 0; /* write AIC_EOICR to clear interrupt */
}
/*..........................................................................*/
(8) __arm __ramfunc void BSP_fiq(void) {
/* TBD: implement the FIQ handler directly right here, see NOTE02 */
/* NOTE: Do NOT enable interrupts throughout the whole FIQ processing. */
/* NOTE: Do NOT write EOI to the AIC */
}
/* ISRs --------------------------------------------------------------------*/
(9) static __arm __ramfunc void ISR_tick(void) {
(10) uint32_t tmp = AT91C_BASE_PITC->PITC_PIVR; /* clear interrupt source */
(11) QF_tick();
}
/*..........................................................................*/
(12) static __arm __ramfunc void ISR_spur(void) {
}
/*..........................................................................*/
(13) __arm void QF_onStartup(void) {
(14) QF_INT_LOCK_ARM(); /* make sure that all interrupts are disabled */
/* hook the exception handlers from the QF port */
(15) *(uint32_t volatile *)0x24 = (uint32_t)&QF_undef;
(16) *(uint32_t volatile *)0x28 = (uint32_t)&QF_swi;
(17) *(uint32_t volatile *)0x2C = (uint32_t)&QF_pAbort;
(18) *(uint32_t volatile *)0x30 = (uint32_t)&QF_dAbort;
(19) *(uint32_t volatile *)0x34 = (uint32_t)&QF_reserved;
(20) *(uint32_t volatile *)0x38 = (uint32_t)&QF_irq;
(21) *(uint32_t volatile *)0x3C = (uint32_t)&QF_fiq;
(22) AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SYS] = (uint32_t)&IRQ_tick;
(23) AT91C_BASE_AIC->AIC_SPU = (uint32_t)&ISR_spur; /* spurious ISR */
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SYS] =
(AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | AT91C_AIC_PRIOR_LOWEST);
AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_SYS);
AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_SYS);
(24) QF_INT_UNLOCK_ARM(); /* unlock interrupts to run the application */
}
Listing 6 The ISR definitions and initialization for the Vanilla port (<qp>\examples\arm\-
vanilla\iar\dpp-at91sam7s-ek\bsp.c).

(1) This typedef defines the pointer-to-function type for calling the interrupt handlers.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 15 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

(2) As described in Application Note “QP and ARM7/ARM with IAR Toolset” [QL 08a], the low-level
IRQ interrupt “wrapper” in assembly calls function BSP_irq(). This function is a regular C func-
tion (not an __irq function!) and can be compiled to THUMB or ARM, as you like. Here, the
function BSP_irq() is defined as an ARM function (via the __arm keyword) to be able to use the
very efficient, unconditional interrupt locking and unlocking macros QF_INT_UNLOCK_ARM()/
QF_INT_LOCK_ARM(). The __ramfunc extended keyword makes the function to execute from the
RAM, which is only done for better performance.
(3) The current interrupt vector is loaded from the AIC IVR register into a temporary variable.
(4) Interrupts are enabled unconditionally at the ARM core level by means of the macro
QF_INT_UNLOCK_ARM(). Please note that the QF_INT_UNLOCK() macro is not used, because it
unlocks interrupts conditionally depending on the interrupt lock key parameter.

NOTE: Enabling all IRQs and FIQs is safe, because the AIC performs interrupt prioritization in
hardware.

(5) The interrupt handler is invoked via the pointer-to-function (vector address) extracted from the
AIC. Please note that the vectoring capability of the AIC is actually used, even though this is
not the traditional auto-vectoring. For the vectoring to work, the AIC SVR registers must be ini-
tialized with the addresses of interrupt handlers, such as the time tick ISR tickIRQ().
(6) After ISR function returns, the interrupts are disabled unconditionally at the ARM core level by
means of the macro QF_INT_UNLOCK_ARM().
(7) The EOI command is written to the AIC, which informs the interrupt controller that the interrupt
processing has ended.
(8) As described in Application Note “QP and ARM7/ARM with IAR Toolset” [QL 08a], the low-level
FIQ interrupt “wrapper” in assembly calls function BSP_fiq(). This function is a regular C func-
tion (not an __fiq function!) and can be compiled to THUMB or ARM, as you like. Here, the
function BSP_fiq() is defined as __ramfunc to execute from the RAM, which is only done for bet-
ter performance. Because the AIC does not provide priority controller for the FIQ (see the
“AT91SAM Datasheet”) there is really not any value added by indirecting via the AIC_FVR regis-
ter. The body of the interrupt might as well be directly implemented in BSP_fiq().

NOTE: Because the AIC does not protect the FIQ line with the priority controller, the whole
work of FIQ should be performed with interrupts permanently locked at the ARM core level. In
particular, the IRQ interrupt should never be unlocked during FIQ processing.

(9) As described at Listing 6(5), the interrupt handler is a regular C function. Declaring this func-
tion as __ramunc is just an optimization.
(10) The interrupt source (Timer/Counter 1 in this case) must be cleared.

NOTE: Please note that the interrupt handler executes with interrupt unlocked at the ARM core
level. However, the prioritization performed in AIC prevents the same (or any other lower-
priority) interrupt from preempting the currently serviced interrupt.

(11) The work of the interrupt is performed, which consists of the system clock tick processing
QF_tick() in this case.
Listing 5(12) The spurious interrupt handler is empty.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 16 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

(13) The QF callback QF_onStartup() is called just before entering the background loop of the “va-
nilla” QF port (see Chapter 7 in [PSiCC2]). This purpose of the QF_onStartup() function is to
configure and enable the interrupts.
(14) All interrupts (both IRQ and FIQ) are locked unconditionally with the macro
QF_INT_LOCK_ARM().
(15-21) The secondary jump table at address 0x20 is initialized with the addresses of the “wrap-
per” functions in assembly. Among others, the table entry at 0x38 is initialized with the address
of BSP_irq() and the entry at 0x3C with the address of BSP_fiq().
(22,23) The AIC is initialized with the addresses of all used interrupt handlers.
(24) All interrupts (both IRQ and FIQ) are unlocked unconditionally with the macro
QF_INT_UNLOCK_ARM().

3.4.3.2 ISRs in the QK Port, Mixed ARM/THUMB Mode


The ISRs in the QK port are defined and initialization identically as in the “vanilla” port. The only
difference is that you use the QK “wrapper” functions for interrupts and other exceptions instead of
QF functions. The following subsections discuss the ISRs for the QK port included in this QDK.

__arm void QF_onStartup(void) {


uint32_t dummy;
QF_INT_LOCK_ARM(); /* make sure that all interrupts are disabled */
/* hook the exception handlers from the QF port */
*(uint32_t volatile *)0x24 = (uint32_t)&QF_undef;
*(uint32_t volatile *)0x28 = (uint32_t)&QF_swi;
*(uint32_t volatile *)0x2C = (uint32_t)&QF_pAbort;
*(uint32_t volatile *)0x30 = (uint32_t)&QF_dAbort;
*(uint32_t volatile *)0x34 = (uint32_t)&QF_reserved;
(1) *(uint32_t volatile *)0x38 = (uint32_t)&QK_irq;
(2) *(uint32_t volatile *)0x3C = (uint32_t)&QK_fiq;
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SYS] = (uint32_t)&ISR_tick;
AT91C_BASE_AIC->AIC_SPU = (uint32_t)&ISR_spur; /* spurious IRQ */
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SYS] =
(AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | AT91C_AIC_PRIOR_LOWEST);
AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_SYS);
AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_SYS);
/* TESTING ONLY: configure Timer1 interrupt as FIQ */
(3) AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); /* enable clock of TC1 */
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; /* disable clock & interrupts */
AT91C_BASE_TC1->TC_IDR = ~0U;
dummy = AT91C_BASE_TC1->TC_SR; /* clear status bit */
(void)dummy; /* suppress warning "dummy" was set but never used */
AT91C_BASE_TC1->TC_CMR = (AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO);
AT91C_BASE_AIC->AIC_IDCR = (1 << AT91C_ID_TC1);
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC1] =
(AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 0); /* ignore priority for FIQ */
AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_TC1);
AT91C_BASE_TC1->TC_IER = AT91C_TC_CPCS; /* enable CPC */
AT91C_BASE_AIC->AIC_FFER = (1 << AT91C_ID_TC1); /* Fast Forcing (FIQ) */
AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_TC1);
AT91C_BASE_TC1->TC_RC = 1; /* Timer1 reset compare C (just one tick) */
QF_INT_UNLOCK_ARM(); /* unlock interrupts to run the application */
}
Copyright © Quantum Leaps, LLC. All Rights Reserved. 17 of 27
QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm
/*..........................................................................*/
__ramfunc void BSP_fiq(void) {
/* TBD: implement the FIQ handler directly right here, see NOTE02 */
/* NOTE: Do NOT enable interrupts throughout the whole FIQ processing. */
/* NOTE: Do NOT write EOI to the AIC */
uint32_t dummy = AT91C_BASE_TC1->TC_SR; /* clear interrupt source */
static QEvent test = { MAX_SIG, 0 };
(4) QActive_postFIFO(AO_Table, &test); /* make Table ready to run */
(void)dummy; /* suppress warning "dummy" was set but never used */
}
Listing 7 The ISR definitions and initialization for the QK port (<qp>\examples\arm\qk\-
iar\dpp-at91sam7s-ek\bsp.c).

(1-2) The IRQ and FIQ interrupt handlers are set to QK_irq and QK_fiq, respectively (see Applica-
tion Note “QP and ARM7/ARM with IAR Toolset” [QL 08a]).
(3) The Timer-Counter 1 (TC1) is configured to deliver the FIQ interrupt for testing of various pre-
emption scenarios in the QK port (see also Section 3.6).
(4) As described in Application Note “QP and ARM7/ARM with IAR Toolset” [QL 08a], the low-level
FIQ interrupt “wrapper” in assembly calls function BSP_irq(). This function is a regular C func-
tion (not an __fiq function!) and can be compiled to THUMB or ARM, as you like. Here, the
function BSP_fiq() is defined as __ramfunc to execute from the RAM, which is only done for bet-
ter performance. The BSP_fiq() function is setup to generate an event for the highest-priority
active object Table in the DPP application. This allows testing of various asynchronous preemp-
tion scenarios in the QK port (see Section 3.6)

3.4.4 QS Instrumentation
This QDK demonstrates how to use the Quantum Spy (QS) to obtain real-time trace of a running
QP application.
Quantum Spy (QS) is a software tracing facility built into all Quantum Platform components and
also available to the Application code. QS allows you to gain unprecedented visibility into your ap-
plication 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]).
QS can be configured to send the real-time data out of the serial port of the target device. On the
AT91SAM7S-EK board, the QS has been configured to send data out of the debug serial port (De-
bug UART, see Figure 1). The QS platform-dependent implementation is located in the file bsp.c
and looks as follows:

(1) #ifdef Q_SPY


(2) uint32_t l_timeOverflow;
#define QS_BUF_SIZE (2*1024)
#define BAUD_RATE 115200
(3) uint8_t QS_onStartup(void const *arg) {
(4) static uint8_t qsBuf[QS_BUF_SIZE]; /* buffer for Quantum Spy */
AT91PS_DBGU pDBGU = AT91C_BASE_DBGU;
AT91PS_TC pTC0 = AT91C_BASE_TC0;/* TC0 used for timestamp generation */
uint32_t tmp;
(5) QS_initBuf(qsBuf, sizeof(qsBuf));
Copyright © Quantum Leaps, LLC. All Rights Reserved. 18 of 27
QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

/* configure the Debug UART for QSPY output ... */


(6) AT91C_BASE_PIOA->PIO_PDR = AT91C_PA10_DTXD; /* configure pin as DTXD */
pDBGU->DBGU_CR = AT91C_US_TXEN; /* enable only transmitter */
pDBGU->DBGU_IDR = ~0; /* disable all DBGU interrupts */
pDBGU->DBGU_MR = AT91C_US_PAR_NONE; /* no parity bit */
pDBGU->DBGU_BRGR = ((MCK/BAUD_RATE + 8) >> 4); /* baud rate generator */
pDBGU->DBGU_PTCR = AT91C_PDC_TXTEN; /* enable PDC transfer from DBGU */
/* configure Timer/Counter 0 for time measurements ... */
(7) AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); /* enable clock to TC0 */
(8) pTC0->TC_CCR = AT91C_TC_CLKDIS; /* TC_CCR: disable Clock Counter */
pTC0->TC_IDR = ~0; /* TC_IDR: disable all timer interrupts */
tmp = pTC0->TC_SR; /* TC_SR: read */
/* CPCTRG, MCK/32 clock */
pTC0->TC_CMR = (AT91C_TC_CPCTRG | AT91C_TC_CLKS_TIMER_DIV3_CLOCK);
pTC0->TC_CCR = AT91C_TC_CLKEN; /* TC_CCR: enable Clock Counter */
pTC0->TC_CCR = AT91C_TC_SWTRG; /* TC_CCR: start counting */
return (uint8_t)1; /* indicate successfull QS initialization */
}
/*..........................................................................*/
(8) void QS_onCleanup(void) {
}
/*..........................................................................*/
(9) void QS_onFlush(void) {
uint16_t nBytes = QS_BUF_SIZE;
uint8_t const *block;
(10) while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXBUFE) == 0) { /* busy? */
}
(11) if ((block = QS_getBlock(&nBytes)) != (uint8_t *)0) {
(12) AT91C_BASE_DBGU->DBGU_TPR = (uint32_t)block;
(13) AT91C_BASE_DBGU->DBGU_TCR = (uint32_t)nBytes;
(14) nBytes = QS_BUF_SIZE;
(15) if ((block = QS_getBlock(&nBytes)) != (uint8_t *)0) {
(16) AT91C_BASE_DBGU->DBGU_TNPR = (uint32_t)block;
(17) AT91C_BASE_DBGU->DBGU_TNCR = (uint32_t)nBytes;
}
}
}
/*..........................................................................*/
/* NOTE: invoked within a critical section (inetrrupts disabled) */
(18) __ramfunc uint32_t QS_onGetTime(void) {
AT91PS_TC pTC0 = AT91C_BASE_TC0; /* TC0 used for timestamp generation */
uint32_t now = pTC0->TC_CV; /* get the counter value */
/* did the timer overflow 0xFFFF? */
(19) if ((pTC0->TC_SR & AT91C_TC_COVFS) != 0) {
l_timeOverflow += (uint32_t)0x10000; /* account for the overflow */
}
return l_timeOverflow + now;
}
#endif /* Q_SPY */
Listing 8 QS implementation to send data out of the UART1 serial port at 115200 baud
rate.

(1) The QS instrumentation is enabled only when the macro Q_SPY is defined
(2) This variable is used to extend the 16-bit timestamp counter to 32-bits
(3) The QS_onStartup() callback performs the initialization of QS
(4) You must allocate the QS trace buffer of adequate size

Copyright © Quantum Leaps, LLC. All Rights Reserved. 19 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

(5) You always need to call QS_initBuf() from QS_onStartup() to initialize the trace buffer
(6) This particular QS port initializes the DEBUG UNIT UART for polled DMA data transfer at the
given baud rate (BAUD_RATE = 115200 bits per second)
(7) This QS port uses Timer/Counter 0 for sub-microsecond time-stamping of the trace records.
The clock to this peripheral must be enabled before it can be used.
(8) Timer/Counter 0 is configured to tick at the rate of MCK/32.
(8) The QS_onCleanup() callback performs the cleanup of QS. Here nothing needs to be done.
Listing 8(9) The QS_onFlush() callback flushes the QS trace buffer to the host. It is only used in the
initialization phase for sending the QS dictionary records to the host (see Chapter 11 in
[PSiCC2])
(10) QS_onFlush() busy-waits for the DMA transfer to complete.
(11) The function QS_getBlock() returns a non-NULL pointer when the trace buffer has data.
(12-13) If a data block is available, it is used to setup the DMA pointer and the number of bytes for
the DMA counter.
(14) The number of bytes to accept is reset to the buffer size
(15) The function QS_getBlock() is called again, because the QS buffer is circular and could wrap
around.
(16-17) If a data block is still available, its used to setup the NEXT DMA pointer and the NEXT DMA
counter.

NOTE: This hardware structure of the AT91SAM7 DMA with two levels of pointers and chaining
the DMA transfers is exactly designed to flush circular buffers, like the QS trace buffer.

(18) The QS_onGetTime() callback provides the time-stamp to the QS trace records. The QS time-
stamping implementation uses the high-resolution Timer-Counter 0 of the AT91. The timer is
configured to use the MCK with the 1/32 prescaler, which on AT91SAM7S-EK works out to be
47923200Hz/32 = 1.4976MHz (0.667735 microsecond per count).The 16-bit counter is ex-
tended to 32-bits by looking at the overflow bit pTC0->TC_SR & AT91C_TC_COVS. The assumption
here is that the QS_onGetTime() callback will be called at least once per the 16-bit overflow time.

3.4.5 Idle Loop Customization

3.4.5.1 Idle Loop in the Vanilla Port


In the absence of events to process, the non-preemptive QF scheduler invokes the QF_onIdle()
callback function to give you an opportunity to perform some processing outside of the time-critical
parts of the code or to give you an opportunity to conserve power by putting the CPU in a power-
saving mode. The QF_onIdle() callback is called with interrupts locked, because the determination
of the idle condition might change by any interrupt posting an event.

(1) __ramfunc void QF_onIdle(QF_INT_KEY_TYPE key) { /* NOTE: interrupts LOCKED */


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

(3) QF_INT_UNLOCK(key);
(4) if ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXBUFE) != 0) { /* not busy? */
uint16_t nBytes = QS_BUF_SIZE;

Copyright © Quantum Leaps, LLC. All Rights Reserved. 20 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm
uint8_t const *block;
(5) QF_INT_LOCK(key);
(6) if ((block = QS_getBlock(&nBytes)) != (uint8_t *)0) {
(7) AT91C_BASE_DBGU->DBGU_TPR = (uint32_t)block;
(8) AT91C_BASE_DBGU->DBGU_TCR = (uint32_t)nBytes;
(9) nBytes = QS_BUF_SIZE;
(10) if ((block = QS_getBlock(&nBytes)) != (uint8_t *)0) {
(11) AT91C_BASE_DBGU->DBGU_TNPR = (uint32_t)block;
(12) AT91C_BASE_DBGU->DBGU_TNCR = (uint32_t)nBytes;
}
}
(13) QF_INT_UNLOCK(key);
}
#else /* no QS instrumentation */
#ifdef NDEBUG /* only if not debugging (power saving hinders debugging) */
(14) AT91C_BASE_PMC->PMC_SCDR = 1;/* Power-Management: disable the CPU clock */
/* NOTE: an interrupt re-starts the CPU clock*/
#endif /* NDEBUG */
(15) QF_INT_UNLOCK(key); /* unlock interrupts as soon as CPU starts */
#endif /* Q_SPY */
}
Listing 9 The QF_onIdle() callback in the QF “vanilla” port

(1) The function QF_onIdle() is placed in RAM (__ramfunc), because it is executed very often and
therefore is a clear “hot-spot”.

NOTE: The signature of the QF_onIdle() callback depends on the interrupt locking policy. In
case of the “save and restore interrupt status” policy, the function takes the interrupt lock key
as the parameter to be able to unlock the interrupts internally.

(2) If Q_SPY is enabled, QF_onIdle() performs QS trace data transfer using the DMA mode of
UART1.
(3) If Q_SPY is enabled, the interrupts are unlocked immediately (no power-saving is applied).
(4) The UART1 transmit counter is examined. If it’s zero the DMA is done with the transfer.
(6,10) The QS buffer access function QS_getBlock() is not protected internally with a critical sec-
tion. Here, in the background loop, such protection is needed.
(6) The function QS_getBlock() returns a non-NULL pointer when the trace buffer has data.
(7-8) If a data block is available, it is used to setup the DMA pointer and the number of bytes for
the DMA counter.
(9) The number of bytes to accept is reset to the buffer size
(10) The function QS_getBlock() is called again, because the QS buffer is circular and could wrap
around.
(11-12) If a data block is still available, its used to setup the NEXT DMA pointer and the NEXT DMA
counter.

NOTE: This hardware structure of the AT91SAM7 DMA with two levels of pointers and chaining
the DMA transfers is exactly designed to flush circular buffers, like the QS trace buffer.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 21 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

(14) If the Q_SPY is not configured, the QF_onIdle() function uses the power saving feature of the
AT91 to gate the clock to the CPU. An active interrupt first re-starts the CPU clock.

NOTE: The power-saving mode is applied with interrupts locked. Interrupts are unlocked only
later, after an interrupt restarts the CPU clock again.

(15) Immediately after the CPU clock re-starts the interrupts are unlocked to allow processing of
the interrupt.

3.4.5.2 Idle Loop in the QK Port


In the absence of events to process, the QK invokes the QK_onIdle() callback function to give you
an opportunity to perform some processing outside of the time-critical parts of the code or to give
you an opportunity to conserve power by putting the CPU in a power-saving mode.
In the AT91 BSP the QK_onIdle() callback is used to perform the QS trace data transmission to the
host. In the release code, where the QS tracing is “compiled-out”, you it’s used to save power.

(1) __ramfunc void QK_onIdle(void) { /* entered with interrupts unlocked */


(2) #ifdef Q_SPY /* use the idle cycles for QS transmission */
(3) if ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXBUFE) != 0) { /* not busy? */
uint16_t nBytes = QS_BUF_SIZE;
uint8_t const *block;
(4) QK_INT_LOCK(ignore);
(5) if ((block = QS_getBlock(&nBytes)) != (uint8_t *)0) {
(6) AT91C_BASE_DBGU->DBGU_TPR = (uint32_t)block;
(7) AT91C_BASE_DBGU->DBGU_TCR = (uint32_t)nBytes;
(8) nBytes = QS_BUF_SIZE;
(9) if ((block = QS_getBlock(&nBytes)) != (uint8_t *)0) {
(10) AT91C_BASE_DBGU->DBGU_TNPR = (uint32_t)block;
(11) AT91C_BASE_DBGU->DBGU_TNCR = (uint32_t)nBytes;
}
}
(12) QK_INT_UNLOCK(ignore);
}
#else /* no QS instrumentation */
#ifdef NDEBUG /* only if not debugging (power saving hinders debugging) */
(13) AT91C_BASE_PMC->PMC_SCDR = 1;/* Power-Management: disable the CPU clock */
#endif /* NDEBUG */
#endif /* Q_SPY */
}
Listing 10 The QK_onIdle() callback

(1) The function QK_onIdle() is placed in RAM (__ramfunc), because it is executed very often and
therefore is a clear “hot-spot”.
(2) If Q_SPY is enabled, QK_onIdle() performs QS trace data transfer using the DMA mode of the
DEBUG UNIT UART.
(3) The UART transmit buffer-empty bit is examined. If it’s set the DMA is done with the transfer.
(4,12) The QS buffer access function QS_getBlock() is not protected internally with a critical sec-
tion. Here, in the background loop, such protection is needed.
(5) The function QS_getBlock() returns a non-NULL pointer when the trace buffer has data.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 22 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

(6-7) If a data block is available, it is used to setup the DMA pointer and the number of bytes for
the DMA counter.
(8) The number of bytes to accept is reset to the buffer size
(9) The function QS_getBlock() is called again, because the QS buffer is circular and could wrap
around.
(10-11) If a data block is still available, its used to setup the NEXT DMA pointer and the NEXT DMA
counter.
(13) If the Q_SPY is not configured, the QK_onIdle() function uses the power saving feature of the
AT91SAM7 to gate the clock to the CPU. Only an interrupt can wake the CPU up.

NOTE: The power-saving mode can interfere with debugging. You’ll see that you can break into
a running code only at the IRQ vector at 0x18.

3.5 Loading the Code to Flash


As mentioned in the earlier Section 2.4, you use the IAR C-Spy debugger through the IAR Embed-
ded Workbench for ARM IDE (EWARM). The example application DPP contains the following build
configurations:

Workspace file Purpose


Debug EWARM workspace for debugging the DPP application in Flash. Uses the
dbg\dpp.out image.
Release EWARM workspace for downloading the DPP application into Flash. Uses the
rel\dpp.out and rel\dpp.sim images.
Spy EWARM workspace for downloading the DPP application in Flash with QS out-
put via DEBUG UART. Uses the spy\dpp.out and spy\dpp.sim images.

Table 1 Build configurations provided in the QDK

Loading the application image into the Flash memory of the AT91SAM7 microcontroller is very
easy, because the whole functionality is already provided in the IAR toolset. The IAR Flash Loader
utility is described in the IAR document “IAR Embedded Workbench Flash Loader Developer Guide”,
which is included in PDF in the IAR KickStart™ development toolset for ARM. The process of config-
uring the C-Spy debugger for the flash loader is described in Section “Using Flash Loaders” in the
“ARM® IAR Embedded Workbench® IDE User Guide” [IAR 05b].
Once the C-Spy is configured for the device you’re using, you need to configure the Debugger sec-
tion of the “Options for Node” dialog box.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 23 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

Figure 5 Configuring the Download tab of the “Options” dialog box, and editing the
Flash Loader parameters.

Figure 5 shows how to setup the Debugger options to “Use flash loaders” and how to configure the
flash loader. In particular, the Atmel AT91SAM7S64 flash loader requires relocating the Base ad-
dress to 0x00100000, if the image is linked to RAM after the Memory Controller remapping, which
is typically the case.

NOTE: All IAR examples for the AT91SAM7 show only how to load the image to Flash without
the MC remapping. The code provided in these examples will not load correctly if you try to link
the image to ROM at 0x00100000 (i.e., after the MC remap), even if you select the “Relocate”
checkbox and specify the address 0x00100000, as shown in Figure 5.

3.6 Manual Testing of Interrupt Preemptions Scenario


The DPP application does not test the FIQ preemption of IRQs. This section describes a comple-
mentary technique for manual testing of various interrupt scenarios, so that you can easily trigger
an interrupt at any machine instruction and observe the preemptions it causes.
The DPP example application includes special instrumentation for manual testing of interrupts. As
shown in Listing 6, the Timer-Counter 1 (TC1) is setup to generate the FIQ interrupt. TC1 is con-
figured with just one count in the RC-compare register, and the software trigger is NOT applied.
With this setup, you can manually trigger the timers from the debugger by writing 0x05 (SWTRG +
CLKEN) to the timer’s Control Register (TCx_CR). The TC0_CR is located at the addresses
0xFFFA0000, and the TC1_CR is located at 0xFFFA0040 [1]. Because of just one count in the RC-
comapre register, the timer expires immediately and triggers the desired interrupt before the next
machine instruction gets executed.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 24 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

The general testing strategy is to break into the application at an interesting point for preemption,
set breakpoints to verify which path through the code is taken, and trigger the desired timer. Next,
you need to free-run the code (don’t use single stepping) so that the interrupt controller can per-
form prioritization. You observe the order in which the breakpoints are hit. This procedure will be-
come clearer after some examples.
The first interesting test is verifying the prioritization of IRQ interrupts by the AIC. To test this sce-
nario, you place a breakpoint at the beginning of QK_irq assembler “wrapper” function in the
qk_port.s file. When the breakpoint is hit, you move the original breakpoint to the beginning of
QK_fiq assembler “wrapper” function. Next you trigger the Timer1 interrupt by writing 0x5 to the
address 0xFFFA0040. You hit the Run button.
After the breakpoint in QK_fiq is hit, you need to disable Timer1 from expiring again, by writing 0x2
(CLKDIS) to the address 0xFFFA0040. You then step through the QK_fiq assembler “wrapper”. In
particular, you can verify that the QK scheduler QK_schedule_() is not executed, because the FIQ
nests on the IRQ, even though the QK_intNest_ variable has not been incremented yet inside the
QK_irq handler.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 25 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

4 References
Document Location

[PSiCC2] “Practical UML Statecharts in Available from most online book retailers, such as
C/C++, Second Edition”, Miro Samek, New- amazon.com. See also: http://www.state-
nes, 2008 machine.com/psicc2.htm

[QP-ARM 08] “QP and ARM7/ARM9”, Quan- http://www.state-


tum Leaps, 2008 machine.com/doc/AN_QP_and_ARM.pdf

[QL AN-DPP 08] “Application Note: Dining http://www.state-machine.com/doc/AN_DPP.pdf


Philosophers Application”, Quantum Leaps, (included in this QDK)
LLC, 2008

[QP/C 08] “QP/C Reference Manual”, Quan- http://www.state-machine.com/doxygen/qpc/


tum Leaps, LLC, 2008

[QP/C++ 08] “QP/C++ Reference Manual”, http://www.state-machine.com/doxygen/qpcpp/


Quantum Leaps, LLC, 2008

[QL AN-Directory 07] “Application Note: QP http://www.state-machine.com/doc/-


Directory Structure”, Quantum Leaps, LLC, AN_QP_Directory_Structure.pdf
2007

[IAR 08a] “ARM® IAR C/C++ Compiler Ref- Available in PDF as part of the ARM KickStart™ kit
erence Guide”, IAR 08 in the file EWARM_CompilerReference.pdf.

[IAR 08b] “IAR Linker and Library Tools Ref- Available in PDF as part of the ARM KickStart™ kit
erence Guide”, IAR 08

[IAR 08c] “ARM® Embedded Workbench® Available in PDF as part of the ARM KickStart™ kit
IDE User Guide”, IAR 08 in the file EWARM_UserGuide.pdf.

Copyright © Quantum Leaps, LLC. All Rights Reserved. 26 of 27


QDK™
QDK Atmel AT91SAM7S-EK with IAR Toolset
www.state-machine.com/arm

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

ARM Ltd. IAR Systems


110 Fulbourn Road Century Plaza
Cambridge 1065 E. Hillsdale Blvd
CB1 9NJ Foster City, CA 94404
England USA
+1 650 287 4250
Tel: (44) 01223 400400 +1 650 287 4253 (FAX)
Fax: (44) 01223 400410 e-mail: Info@IAR.com
WEB : www.ARM.com WEB : www.IAR.com

Copyright © Quantum Leaps, LLC. All Rights Reserved. 27 of 27

S-ar putea să vă placă și