This application note is aimed at helping the reader become familiar with the Atmel
®
ARM
Thumb®-based AT91SAM7SE microcontroller.
It describes in detail a simple project that uses several important features present on
AT91SAM7SE chips. This includes how to setup the microcontroller prior to executing
the application, as well as how to add the functionalities themselves. After going
through this guide, the reader should be able to successfully start a new project from
scratch.
This document also explains how to setup and use a GNU ARM toolchain in order to
compile and run a software project.
Note that the Getting Started example has been ported and is included in IAR
EWARM 4.41A; the reader should disregard the section “Building the Project” on page
17 when using this version.
To be able to use this document efficiently, the reader should be experienced in using
the ARM core. For more information about the ARM core architecture, please refer to
the appropriate documents available from http://www.arm.com.
AT91 ARM
Thumb
Microcontrollers
Application Note
®
2.Requirements
The software provided with this application notes requires several components:
• The AT91SAM7SE Evaluation Kit
• A computer running Microsoft
• An ARM cross-compiler toolchain (such as YAGARTO)
• AT91-ISP V1.8 or later
®
Windows® 2000/XP
6295A–ATARM–27-Mar-07
3.Getting Started with a Software Example
This section describes how to program a basic application that helps you to become familiar with
AT91SAM7SE microcontrollers. It is divided into two main sections: the first one covers the
specification of the example (what it does, what peripherals are used); the other details the programming aspect.
3.1Specification
3.1.1Features
The demonstration program makes two LEDs on the board blink at a fixed rate. This rate is generated by using a timer for the first LED; the second one uses a Wait function based on a 1 ms
tick. The blinking can be stopped using two buttons (one for each LED).
While this software may look simple, it uses several peripherals which make up the basis of an
operating system. As such, it makes a good starting point for someone wanting to become familiar with the AT91SAM microcontroller series.
3.1.2Peripherals
In order to perform the operations described in the previous section, the software example uses
the following set of peripherals:
• Parallel Input/Output (PIO) controller
• Timer Counter (TC)
• Periodic Interval Timer (PIT)
• Advanced Interrupt Controller (AIC)
• Debug Unit (DBGU)
LEDs and buttons on the board are connected to standard input/output pins of the chip; those
are managed by a PIO controller. In addition, it is possible to have the controller generate an
interrupt when the status of one of its pins changes; buttons are configured to have this
behavior.
3.1.3Evaluation Kit
3.1.3.1Booting
2
Application Note
The TC and PIT are used to generate two time bases, in order to obtain the LED blinking rates.
They are both used in interrupt mode: the TC triggers an interrupt at a fixed rate, each time toggling the LED state (on/off). The PIT triggers an interrupt every millisecond, incrementing a
variable by one tick; the Wait function monitors this variable to provide a precise delay for toggling the second LED state.
Using the AIC is required to manage interrupts. It allows the configuration of a separate vector
for each source; three different functions are used to handle PIO, TC and PIT interrupts.
Finally, an additional peripheral is used to output debug traces on a serial line: the DBGU. Having the firmware send debug traces at key points of the code can greatly help the debugging
process.
The AT91SAM7SE512 found on AT91SAM7SE-EK evaluation boards features two internal
memories: a 512 KB Flash and 32 KB SRAM. In addition, it provides an External Bus Interface
(EBI), enabling the connection of external memories; a 32MB SDRAM chip is present on the EK.
6295A–ATARM–27-Mar-07
3.1.3.2Buttons
3.1.3.3LEDs
3.1.3.4Debug Unit
3.2Implementation
The Getting Started example software can be compiled and loaded on the internal Flash and the
external SDRAM.
The AT91SAM7SE Evaluation Kit features two pushbuttons, connected to pins PB22 and PB25.
When pressed, they force a logical low level on the corresponding PIO line.
The Getting Started example uses both buttons (PB22 and PB27).
There are two general-purpose green LEDs on the AT91SAM7SE-EK, as well as a softwarecontrollable yellow power LED; they are wired to pins PA1, PA2 and PA0, respectively. Setting a
logical low level on these PIO lines turns the corresponding LED on.
The example application uses the two green LEDs (PA1 and PA2).
On the AT91SAM7SE, the Debug Unit uses pins PA9 and PA10 for the DRXD and DTXD signals, respectively.
As stated previously, the example defined above requires the use of several peripherals. It must
also provide the necessary code for starting up the microcontroller. Both aspects are described
in detail in this section, with commented source code when appropriate.
3.2.1C-Startup
Most of the code of an embedded application is written in C. This makes the program easier to
understand, more portable and modular. However, using the C language requires the initialization of several components. These initialization procedures must be performed using assembly
language, and are grouped into a file referred to as C-startup. The C-startup code must:
• Provide exception vectors
• Initialize critical peripherals
• Initialize stacks
• Initialize memory segments
These steps are described in the following paragraphs. More information about startup code can
be found in the AT91 Assembler Code Startup Sequence for C Code Applications Software
application note (literature no. 2644), available on http://www.atmel.com.
3.2.1.1Exception Vectors
When an exception occurs (e.g., data abort, undefined instruction, IRQ, etc.), the core instantly
jumps to one of the 8 instructions located between addresses 0x00 and 0x1C.
If the program does not need to handle an exception, then the corresponding instruction can
simply be set to an infinite loop, i.e. a branch to the same address. For vectors which are to be
handled, a branch instruction to a function must be provided. Since address 0x00 is used after a
Reset, the associated branch must always jump to the beginning of the code.
In this example, the only relevant vector is the one for IRQs (excluding the Reset vector). It must
simply branch to the IRQ handler, which is described in Section 3.2.1.2 on page 4.
The code for all eight vectors looks like this:
3
Application Note
6295A–ATARM–27-Mar-07
reset_vector:
ldr pc, =reset_handler
undef_vector:
b undef_vector /* Undefined Instruction */
swi_vector:
b swi_vector /* Software Interrupt */
pabt_vector:
ldr pc, =pabt_handler /* Prefetch Abort */
dabt_vector:
ldr pc, =dabt_handler /* Data Abort */
rsvd_vector:
b rsvd_vector /* reserved */
irq_vector:
b irq_handler /* IRQ : read the AIC */
fiq_vector:
b fiq_vector /* FIQ */
3.2.1.2Exception Vectors: IRQ Handler
The main purpose of the IRQ handler is to fetch the correct jump address for the pending interrupt. This information is held in the Interrupt Vector Register (IVR) of the AIC (see Section 3.2.3
on page 10 for more information about the AIC). Once the address is loaded, the handler just
Registers r0 to 12 are not banked, which means they are shared between (almost) all modes.
Since r0-r3 and r12 are defined as scratch registers by the ARM C calling convention, they must
be saved prior to the jump. In addition, r14 contains the interrupt handler return address plus 4,
so it must also be decremented and then saved. The following code saves registers on the stack
and jumps to the interrupt vector:
The final step is to acknowledge the pending interrupt in the AIC (by writing anything in the End
Of Interrupt Command Register), restore registers and then jump back to the main program:
Note that such a handler does not allow for nested interrupts (since IRQs are masked when the
core enters the IRQ mode).
3.2.1.3Low-Level Initialization
The first step of the initialization process is to configure critical peripherals:
• Embedded Flash Controller (EFC)
4
Application Note
6295A–ATARM–27-Mar-07
• Main oscillator and its PLL
• Advanced Interrupt Controller
• Watchdog
These operations are often grouped into one C function. Since it is likely the function tries to
access the stack, the stack pointer (r13) must be set to the top memory address before the call:
Whenever the microcontroller core runs too fast for the internal Flash, it uses one or more wait
states, i.e. cycles during which it does nothing but wait for the memory. The number of wait
states can be configured in the EFC.
After reset, the chip uses its internal slow clock (cadenced at 32 kHz), so there is no need for
any wait state. However, before switching to the main oscillator (in order to run at full-speed), the
correct number of wait states must be set. If not, the core may no longer be able to read the
code from the Flash.
Configuring the number of wait states is done in the Flash Mode Register (FMR) of the EFC. For
example, a 48 MHz operation requires the use of one wait state:
AT91C_BASE_MC->MC_FMR = AT 91C_FMR_FWS_1FWS;
For more information about the required number of wait states depending on the operating frequency of a microcontroller, please refer to the AC Electrical Characteristics section of the
corresponding datasheet.
3.2.1.5Low-Level Initialization: Main Oscillator and PLL
After reset, the chip is running using a slow clock, which is cadenced at 32 kHz. The main oscillator and its Phase Lock Loop (PLL) must be configured in order to run at full speed. Both can be
configured in the Power Management Controller (PMC).
The first step is to enable the main oscillator and wait for it to stabilize. Writing the oscillator startup time and the MOSCEN bit in the Main Oscillator Register (MOR) of the PMC starts the
oscillator; stabilization occurs when bit MOSCS of the PMC Status Register becomes set. The
following piece of code performs these two operations:
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS));
Calculation of the correct oscillator startup time value is done by looking at the DC characteristics given in the datasheet of the product. Note that the internal slow clock of the AT91SAM7SE
is generated using a RC oscillator; this must be taken into account as this impacts the slow clock
accuracy. Here is an example:
| AT91C_CKGR_MOSCEN;
RC oscillator frequency range in kHz:
5
Application Note
22 fRC42≤≤
6295A–ATARM–27-Mar-07
Oscillator frequency range in MHz:
Oscillator frequency on EK:
Oscillator startup time:
Value for a 2ms startup:
1ms t
OSCOUNT
f
Osc
Startup
3 f
1.4ms≤≤
20≤≤
Osc
18.432MHz=
420000.0014×
------------------------------------------8==
8
Once the oscillator is started and stabilized, the PLL can be configured. The PLL is made up of
two chained blocks: the first one divides the input clock, while the second one multiplies it. The
MUL and DIV factors are set in the PLL Register (PLLR) of the PMC. These two values must be
chosen according to the main oscillator (input) frequency and the desired main clock (output)
frequency. In addition, the multiplication block has a minimum input frequency, and the master
clock has a maximum allowed frequency; these two constraints have to be taken into account.
The PLL calculator (available on http://www.atmel.com) can be used to compute the best MUL
and DIV values. Example given for the AT91SAM7SE-EK:
f
Input
DIV14=
MUL73 1–()72==
f
Output
18.432=
18.432
------------------
14
73×96.109MHz==
Like the main oscillator, a PLL startup time must also be provided. Again, it can be calculated by
looking at the DC characteristics given in the datasheet of the corresponding microcontroller.
After PLLR is modified with the PLL configuration values, the software must wait for the PLL to
become locked; this is done by monitoring the Status Register of the PMC.
Finally, the prescaling value of the main clock must be set, and the PLL output selected. Note
that the prescaling value must be set first, to avoid having the chip run at a frequency higher
than the maximum operating frequency defined in the AC characteristics. As such, this step is
done using two register writes, with two loops to wait for the main clock to be ready:
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
AT91C_BASE_PMC->PMC_MCKR |= AT 91C_PMC_CSS_PLL_CLK;
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
At this point, the chip is configured to run on the main clock with the PLL, at the desired
frequency.
How to set up the AIC properly is described in Section 3.2.3 on page 10.
3.2.1.7Low-Level Initialization: Watchdog
The Watchdog peripheral is enabled by default after a processor reset. If the application does
not use it, which is the case in this example, then it shall be disabled in the Watchdog Mode
Register (WDMR):
6
Application Note
6295A–ATARM–27-Mar-07
3.2.1.8Initializing Stacks
Each ARM mode has its own stack pointer (register sp); thus, each mode which is used in the
application must have its stack initialized.
Since stacks are descending, i.e. the stack pointer decreases in value when data is stored, the
first stack pointer is located at the top of the internal SRAM. A particular length is reserved for
each mode, depending on its uses. Supervisor and user modes usually have big stacks, IRQ
and FIQ modes have a medium-sized stack, and other modes most often have only a few bytes.
In this example, only the Supervisor (SVC) and IRQ modes are used.
Stack initialization is done by entering each mode one after another, setting r13 to the correct
value. The top memory address is stored in a register, and decremented each time the stack
pointer is set. Note that interrupts are masked (i.e., I and F bits set) during this whole process,
except for the last mode (only F bit set). This results in the following code:
/*- Enter Supervisor mode, setup stack, IRQs unmasked */
msr CPSR_c, #ARM_MODE_SVC | F_BIT
mov r13, r0
3.2.1.9Initializing BSS and Data Segments
A binary file is usually divided into two segments: the first one holds the executable code of the
application, as well as read-only data (declared as const in C). The second segment contains
read/write data, i.e., data that can be modified. These two sections are called text and data,
respectively.
Variables in the data segment are said to be either uninitialized or initialized. In the first case, the
programmer has not set a particular value when declaring the variable; conversely, variables fall
in the second case when they have been declared with a value. Unitialized variables are held in
a special subsection called BSS (for Block Started by Symbol).
Whenever the application is loaded in the internal Flash memory of the chip, the Data segment
must be initialized at startup. This is necessary because read/write variables are located in
SRAM or SDRAM, not in Flash. Depending on the toolchain used, there might be library function
for doing this; for example, IAR Embedded Workbench
Initialized data is contained in the binary file and loaded with the rest of the application in the
memory. Usually, it is located right after the text segment. This makes it easy to retrieve the
starting and ending address of the data to copy. To load these addresses faster, they are explicitly stored in the code using a compiler-specific instruction. Here is an example for the GNU
toolchain:
_lp_data:
.word _etext
.word _sdata
.word _edata
®
provides __segment_init().
7
Application Note
6295A–ATARM–27-Mar-07
The actual copy operation consists of loading these values and several registers, and looping
through the data:
In addition, it is both safer and more useful for debug purposes to initialize the BSS segment by
filling it with zeroes. Theoretically, this operation is unneeded; however, it can have several benefits. For example, it makes it easier when debugging to see which memory regions have been
modified. This can be a valuable tool for spotting stack overflow and similar problems.
Initialization of the BSS and Data segments are similar, except register r2 is initialized at zero
after the ldmia instruction and never modified (c.f. the above code).
3.2.1.10Remapping Exception Vectors and Handlers
Several microcontrollers of the AT91SAM family feature an External Bus Interface, enabling the
connection of external memories. Those can be used to store an application and run it from
there, instead of using internal flash or internal SRAM.
The ARM core always fetches exception vectors at address 0. However, this poses a problem
for other memories: the exceptions vectors of the application, located at the beginning of the
memory space, are never read by the core.
In addition, having exception vectors in SRAM benefits performance, even when running from
the internal Flash. Indeed, since the SRAM is accessed at processor speed, this reduces interrupt latency. As such, a memory remap operation is performed in the software example
regardless of which memory model is used.
Placing exception vectors in SRAM can be done simply by putting them at the beginning of the
Data segment. Since it is itself located at the beginning of the SRAM, this means that exception
vectors is automatically copied during the segment initialization.
Figure 3-1 and Figure 3-2 show the memory mapping after loading an application in SDRAM,
and after the Data segment has been initialized and the remap command executed.
8
Application Note
6295A–ATARM–27-Mar-07
Loading...
+ 16 hidden pages
You need points to download manuals.
1 point = 1 manual.
You can buy points or you can get point for every manual you upload.