Файл: Real-time processing with the Philips LPC ARM mcu using GCC and uCOS II RTOS (D.W. Hawkins, 2006).pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 15.06.2025

Просмотров: 482

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

AR1803

May 10, 2006

/* Constants (used as immediate values) */

.equ PLLCON_OFFSET, 0x0

.equ PLLCFG_OFFSET, 0x4

.equ PLLSTAT_OFFSET, 0x8

.equ PLLFEED_OFFSET, 0xC

.equ PLLCON_PLLE,

(1 <<

0)

.equ PLLCON_PLLC,

(1 <<

1)

.equ PLLSTAT_PLOCK,

(1 <<

10)

.equ PLLFEED1,

0xAA

.equ PLLFEED2,

0x55

.equ PLLCFG_VALUE,

0x24

pll_init:

/* Use r0 for indirect addressing */ ldr r0, PLLBASE

/* PLLCFG = PLLCFG_VALUE */ mov r3, #PLLCFG_VALUE

str r3, [r0, #PLLCFG_OFFSET]

/* PLLCON = PLLCON_PLLE */ mov r3, #PLLCON_PLLE

str r3, [r0, #PLLCON_OFFSET]

/* PLLFEED = PLLFEED1, PLLFEED2 */ mov r1, #PLLFEED1

mov r2, #PLLFEED2

str r1, [r0, #PLLFEED_OFFSET] str r2, [r0, #PLLFEED_OFFSET]

/* while ((PLLSTAT & PLLSTAT_PLOCK) == 0); */ pll_loop:

ldr r3, [r0, #PLLSTAT_OFFSET] tst r3, #PLLSTAT_PLOCK

beq pll_loop

/* PLLCON = PLLCON_PLLC|PLLCON_PLLE */ mov r3, #PLLCON_PLLC|PLLCON_PLLE

str r3, [r0, #PLLCON_OFFSET]

/* PLLFEED = PLLFEED1, PLLFEED2 */ str r1, [r0, #PLLFEED_OFFSET]

str r2, [r0, #PLLFEED_OFFSET]

The code uses one word of storage for the address of the PLL base address register, and then uses 8-bit immediate values for the remaining constants. The immediate values become coded as part of the assembly instruction, so do not require additional storage (see Ch. 5 of the ARM-ARM, eg. pA5-4 to A5-7 for mov and orr encoding [12]).

21

AR1803

May 10, 2006

3.5.2MAM setup

The access times of on-chip Flash memories usually limit the maximum speed of microcontrollers. Reference [11] explains how Philips solved this problem for the LPC21xx microcontroller family with the Memory Accelerator Module (MAM), and contains a nice introduction to the microcontroller features. Chapter 4 of the User Manual (p42 [10]) details the MAM. The MAM includes three 128-bit bu ers called the Prefetch Bu er, the Branch Trail Bu er and the Data bu er. The 128-bit bu ers allow Flash memory accesses to deliver four 32-bit ARM-instructions or eight 16-bit Thumb instructions. Nevertheless the CPU still must wait for the first instruction until the memory access is finished. Only then can the next three (ARM) or seven (Thumb) instructions be made available without further delay [11]. Reference [11] shows benchmark results of operation the MAM; disabled, partially enabled, and fully enabled (p44 [10] explains the three modes).

The MAM registers consist of a control register and a timing control register (p44 [10]). Two configuration bits select the three MAM operating modes. The configuration mode can be changed at any time, so the startup code fully enables the MAM (MAM_mode_control = 10b). The MAM Timing register determines how many processor core clock cycles are used to access the Flash memory. This allows tuning MAM timing to match the processor operating frequency. There is no code fetch penalty for sequential instruction execution when the CPU clock period is greater than or equal to one fourth of the Flash access time (p42 [10]). For a system clock slower than 20MHz (50ns period) the MAMTIM register can be set to 1 (p47 [10]). At 60MHz, the clock period is 16.7ns, four times this is 66.7ns, which is greater than 50ns, so MAMTIM can be set to 4. The MAM initialization code is;

/* Constants (and storage, used in ldr statements) */ MAMBASE: .word 0xE01FC000

/* Constants (used as immediate values) */

.equ MAMCR_OFFSET, 0x0

.equ MAMTIM_OFFSET, 0x4

.equ

MAMCR_VALUE,

0x2

/*

fully

enabled */

.equ

MAMTIM_VALUE,

0x4

/*

fetch

cycles */

mam_init:

/* Use r0 for indirect addressing */ ldr r0, MAMBASE

/* MAMCR = MAMCR_VALUE */ mov r1, #MAMCR_VALUE

str r1, [r0, #MAMCR_OFFSET]

/* MAMTIM = MAMTIM_VALUE */ mov r1, #MAMTIM_VALUE

str r1, [r0, #MAMTIM_OFFSET]

3.5.3Stacks setup

Figure 1 shows the seven ARM operating modes. The figure shows that there are 6 di erent stack pointers; user/system mode, supervisor mode, IRQ mode, FIQ mode, abort mode, and undefined mode. The ARM processor resets to supervisor mode, a privileged mode (pA2-13, pA2-14 [12]). The control and program status register (CPSR) M[4:0] bits can be modified from within a privileged mode to switch between processor modes and setup the di erent stacks.

22


AR1803

May 10, 2006

The size of the stack required for each processor mode is application dependent. When an exception occurs, the banked versions of the link register (LR or R14) and the saved processor status register (SPSR) for the exception mode are used to save state (see pA2-13 [12]). The ARM processor does not use the stack during the exception entry, it is only the handler code that uses the stack. If the default handler uses a branch or load instruction to ‘lock-up’, then no stack setup is required. If a more complex handler is installed, eg. an abort handler that writes a console message and then locks-up, then the stack size is determined by the function call requirements. The stacks that are generally required are the system and supervisor mode stacks for operating system usage, the user stack for task usage, the IRQ and FIQ stacks for interrupt handlers, and optionally the abort and undefined handlers.

An example of stack initialization code for the LPC2138 is;

/* Constants (and storage, used in ldr statements) */ STACK_START: .word 0x40008000

/* Constants (used as immediate values) */

/* Processor modes (see pA2-11 ARM-ARM) */

.equ FIQ_MODE,

0x11

.equ IRQ_MODE,

0x12

.equ SVC_MODE,

0x13

/* reset mode */

.equ ABT_MODE,

0x17

.equ UND_MODE,

0x1B

.equ SYS_MODE,

0x1F

/* Stack sizes */

.equ FIQ_STACK_SIZE,

0x00000080

/*

32x32-bit words */

.equ IRQ_STACK_SIZE,

0x00000080

.equ SVC_STACK_SIZE,

0x00000080

.equ ABT_STACK_SIZE,

0x00000010

/*

4x32-bit words */

.equ UND_STACK_SIZE,

0x00000010

.equ SYS_STACK_SIZE,

0x00000400

/* 256x32-bit words */

/* CPSR interrupt disable bits */

.equ IRQ_DISABLE,

(1 << 7)

.equ FIQ_DISABLE,

(1 << 6)

/* Setup the stacks */ ldr r0, STACK_START

/* FIQ mode stack */

msr CPSR_c, #FIQ_MODE|IRQ_DISABLE|FIQ_DISABLE mov sp, r0

sub r0, r0, #FIQ_STACK_SIZE

/* IRQ mode stack */

msr CPSR_c, #IRQ_MODE|IRQ_DISABLE|FIQ_DISABLE mov sp, r0

sub r0, r0, #IRQ_STACK_SIZE

/* Supervisor mode stack */

msr CPSR_c, #SVC_MODE|IRQ_DISABLE|FIQ_DISABLE mov sp, r0

23


AR1803 May 10, 2006

sub r0, r0, #SVC_STACK_SIZE

/* Undefined mode stack */

msr CPSR_c, #UND_MODE|IRQ_DISABLE|FIQ_DISABLE mov sp, r0

sub r0, r0, #UND_STACK_SIZE

/* Abort mode stack */

msr CPSR_c, #ABT_MODE|IRQ_DISABLE|FIQ_DISABLE mov sp, r0

sub r0, r0, #ABT_STACK_SIZE

/* System mode stack */

msr CPSR_c, #SYS_MODE|IRQ_DISABLE|FIQ_DISABLE mov sp, r0

/* Leave the processor in system mode */

The initialization code sets up the system mode stack last, and leaves the processor in system mode. The processor mode is not left in supervisor mode, since a software interrupt (SWI) exception causes the processor to change to supervisor mode (pA2-13 [12]). Interrupts should not be enabled while the processor is in an exception mode, otherwise the link register can be over-written (pA2-6 [12]). The stack sizes are guesses, and will need to be checked for specific examples.

Example 5 repeats the LED blinking code from Example 3(b). The startup code was modified to setup the PLL, fully enable the MAM, and setup stacks for all modes. The delay loops in the main application had to be increased by a factor of 35 to obtain one second LED blink rate. A factor of 5 in speed-up was expected by enabling the PLL since that causes the core to be clocked at 60MHz, and a factor of 4 was expected due to enabling of the MAM, however, the observed improvement was a factor of 7.

To confirm the source of the unexpected increase in performance, the reset label was moved around in the startup code. First the reset label was moved such that it skipped the PLL setup and the MAM setup; the resulting period was 35 seconds. Next the label was moved to enable the MAM; the resulting period was 5 seconds. Moving the label back to its original location, enabling the PLL, put the period back at 1 second. So the source of the speed-up was the MAM.

To get an alternative measurement of the increase in performance between Example 5 and Example 3(b), the delay loops were commented out, and an oscilliscope was used to probe the first LED (P1.16). Example 3(b) produced a 40kHz square-wave (10.0µs high-time and 15.0µs low-time), while Example 5 produced a 518kHz square-wave (0.60µs high-time and 1.33µs low-time); an increase in frequency of about 13 times.

24

AR1803

May 10, 2006

3.6Example 6: Exception handling

Figure 1 shows the seven ARM operating modes and the five exception modes (pA1-3 [12]);

fast interrupt (FIQ)

normal interrupt (IRQ)

memory aborts, which can be used to implement memory protection or virtual memory

attempted execution of an undefined instruction

software interrupt (SWI) instruction which can be used to make a call to an operating system

Figure 1 shows that each exception mode has banked versions of the stack-pointer (R13) (each exception has a separate stack) and link-register (R14). The fast interrupt mode has additional banked registers to reduce the context save and restore time for fast interrupts. When an exception handler is entered, the link-register holds the return address for exception processing. The address is used to return from the exception, or determine the address that caused the exception. The saved program status register (SPSR) register saves the state of the current program status register (CPSR) at the time of the exception. Exceptions are described in detail in the ARM-ARM [12] ppA2-13 to 21 and in Chapter 9 of the ARM System Developer’s Guide [13]. The ARM7TDMI-S Technical Reference Manual [1] pp2-19 to 27 details exceptions for the ARM core used in the Philips LPC2138 microcontroller.

The recommended entry and exit sequence for an interrupt (FIQ or IRQ) is (pA2-14 [12]);

sub lr, lr, #4

stmfd sp!, {<other_registers>, lr}

... interrupt handler ...

ldmfd sp!, {<other_registers>, pc}^

The adjustment to the link register value required to determine an exception return address can be found in the ARM7TDMI-S manual (pp2-19 to 27 [1]).

An exception handler can be coded directly in ARM assembler, or C-compiler specific keywords can be used to generate the appropriate prolog and epilog code. The GCC compiler has a set of non-ANSI extensions to declare exception handlers from C code. The declaration syntax for an IRQ handler is

void irq_handler(void) __attribute__ ((interrupt("IRQ")));

The exception source keywords are; IRQ, FIQ, SWI, ABORT, and UNDEF (see Chapter 5 Extensions to the C Language Family, Declaring attributes of functions, in any recent GCC manual eg. the 3.4.4 or 4.0.1 manual on www.gnu.org).

The empty interrupt handler (with no exception source attribute):

/* handler.c */

/* Function declaration */

void handler(void) __attribute__((interrupt));

/* Function definition */ void handler(void)

{

/* Handler body */

}

25


AR1803 May 10, 2006

compiled to assembler using arm-elf-gcc -mcpu=arm7tdmi -Wall -O2 -S handler.c produces the (edited) assembler code

.text

.align 2

.global handler

handler:

subs

pc, lr, #4

i.e., produces code appropriate for return from an FIQ, IRQ, or ABORT. Adding the FIQ, IRQ, or ABORT attribute causes no change in the assembler. The attribute SWI or UNDEF changes the return sequence to movs pc, lr. The ARM7TDMI-S manual pages 2-19 to 20 [1] shows the recommended return sequences for exceptions. The return sequences produced by the GCC compiler matches the recommendations for all but a data abort. The interrupt keyword changes the return sequence of the interrupt handler, it does not setup the interrupt vector table to point to the handler. The processor initialization code containing the exception vector table needs to be modified to point to the exception handler.

The ARM core contains an FIQ or IRQ interrupt pin, and most ARM processors include interrupt controllers that route external interrupt sources onto the FIQ or IRQ pins. Use of FIQ or IRQ interrupts requires setting up the interrupt controller prior to enabling the interrupt. The Philips LPC family uses the Vectored Interrupt Controller (VIC) defined by ARM.

The MCB2130 has a push button connected to the LPC2138 external interrupt pin (EINT1). Example 6(a) sets up the MCB2130 board so that on reset LED[0] is on, and each time the push button is pressed, an FIQ interrupt is generated. The interrupt handler moves the LED that is on to the next LED (eg. cycles through LED[0], LED[1], . . . , LED[7], and then starts back at LED[0]). Example 6(b) starts with LED[7] on, and button presses generate an IRQ interrupt which moves the LED on in the opposite direction to Example 6(a) The LPC213x User Manual [10] details the LPC2138 peripherals setup for this example;

The startup file initializes the processor and leaves it in system mode with FIQ and IRQ enabled.

The application code configures the PINSEL0 register so that the P0.14 pin is setup for EINT1 operation (p75 [10]).

External interrupt configuration is detailed on p17, and pp20-24 [10]. The code sets up EINT1 for falling-edge, edge-sensitive mode. The EXTINT register is written to after the mode change, and to clear the interrupt.

The VIC select register is used to select EINT1 as an FIQ interrupt in Example 6(a), and an IRQ interrupt in Example 6(b). Example 6(b) sets up the VIC for a priority interrupt from EINT1 at VIC vector priority 0. The VIC enable register is then use to enable EINT1 (Chapter 5 [10]).

Once the LPC2138 is configured, the main application drops into an infinite loop. After that point, button pushes generate FIQ or IRQ interrupts, and the interrupt handler updates the LEDs.

There are some minor changes to the startup file, ex6_start.s, relative to ex5_start.s. First, the IRQ and FIQ interrupt vectors are modified;

_start:

b reset

/* reset */

b loop

/* undefined instruction */

b

loop

/* software interrupt */

b

loop

/* prefetch abort */

26