Файл: Real-time processing with the Philips LPC ARM mcu using GCC and uCOS II RTOS (D.W. Hawkins, 2006).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 15.06.2025
Просмотров: 479
Скачиваний: 2
AR1803 |
May 10, 2006 |
|||||||||||
/ DWARF 2 / |
||||||||||||
. d e b u g |
i n f o |
0 |
: { ( . d e b u g |
i n f o . gnu . l i n k o n c e . wi . ) } |
||||||||
. debug |
abbrev |
0 |
: { ( . debug |
abbrev ) } |
||||||||
. d e b u g |
l i n e |
0 |
: { ( . d e b u g |
l i n e ) } |
||||||||
. debug |
frame |
0 |
: { ( . debug |
frame ) } |
||||||||
. d e b u g |
s t r |
0 |
: { ( . d e b u g |
s t r ) } |
||||||||
. d e b u g |
l o c |
0 |
: { ( . d e b u g |
l o c ) } |
||||||||
. debug |
macinfo 0 : { ( . debug |
macinfo ) } |
||||||||||||
/ SGI/MIPS DWARF 2 |
e x t e n s i o n s / |
|||||||||||||
. debug |
weaknames |
0 |
: { |
( . debug |
weaknames ) |
} |
||||||||
. debug |
funcnames 0 |
: { |
( . debug |
funcnames ) |
} |
|||||||||
. debug |
typenames 0 |
: { |
( . debug |
typenames ) |
} |
|||||||||
. debug |
varnames |
0 |
: { |
( . debug |
varnames ) |
} |
||||||||
}
Executable code (.text), and read-only data (.rodata) are linked to Flash addresses. Initialized variables (.data) are linked to SRAM at addresses between symbols _data and _edata, but the values of the initialized variables are stored in Flash after the .text and .rodata sections, at address _etext. The symbols are defined by the linker and are refereed to in the startup routine. The startup routine defines variables (storage) initialized to the linker symbol values. The startup routine then uses the data section symbols to copy values from Flash to SRAM. The application refers to the SRAM versions of the variables. The .bss section contains uninitialized data. The linker combines the .bss sections from the various object files that make up an application, and the linker script defines start (_bss) and end (_ebss) addresses for the uninitialized variables in the final linked application image. The startup code must zero the SRAM address range between _bss and _ebss. The startup code used for the examples is
/ e x 4 |
s t a r t . s / |
|||||||||||
. g l o b a l |
main |
|||||||||||
. g l o b a l |
s t a r t |
|||||||||||
/ Symbols d e f i n e d by |
t he |
l i n k e r s c r i p t |
/ |
|||||||||
. g l o b a l |
e t e x t |
|||||||||||
. g l o b a l |
d a t a |
|||||||||||
. g l o b a l |
e d a t a |
|||||||||||
. g l o b a l |
b s s |
|||||||||||
. g l o b a l |
e b s s |
|||||||||||
. t e x t |
||||||||||||
. arm |
||||||||||||
s t a r t : |
||||||||||||
/ Vectors (8 t o t a l ) / |
||||||||||||
b r e s e t |
/ r e s e t / |
|||||||||||
b l o o p |
/ u n defin ed i n s t r u c t i o n / |
|||||||||||
b l o o p |
/ s o f t w a r e i n t e r r u p t / |
|||||||||||
b l o o p |
/ p r e f e t c h a b o r t / |
|||||||||||
b l o o p |
/ data a b o r t / |
checksum / |
||||||||||
nop |
/ r e s e r v e d |
f o r |
t he b o o t l o a d e r |
|||||||||
bl o o p / IRQ /
bl o o p / FIQ /
16
AR1803 May 10, 2006
/ Setup C runtime :
− copy . data s e c t i o n t o SRAM− c l e a r . b s s
− s et u p s t a c k p o i n t e r− jump t o main
/
r e s e t :
/ Copy . data /
l d r r0 , d a t a |
s o u r c e |
||||||
l d r |
r1 , |
d a t a |
s t a r t |
||||
l d r |
r2 , |
d a ta |
e n d |
||||
c o p y |
d a t a : |
||||
cmp |
r1 , r 2 |
||||
l d r n e r3 , [ r 0 ] , #4 |
|||||
s t r n e r3 , [ r 1 ] , #4 |
|||||
bne |
c o p y |
d a t a |
|||
/ Clear . b s s / |
|||||
l d r r0 |
, =0 |
||||
l d r |
r1 , |
b s s |
s t a r t |
|||
l d r |
r2 , |
b s s |
e n d |
|||
c l e a r |
b s s : |
||||||
cmp |
r1 , |
r |
2 |
||||
s t r n e r0 , |
[ r 1 ] , #4 |
||||||
bne |
c l e a r |
b s s |
|||||
/ Stack p o i n t e r / l d r sp , s t a c k a d d r
b l |
main |
|||||||||||||||
/ Catch |
r et u r n from |
main / |
||||||||||||||
l o o p : |
b |
l o o p |
||||||||||||||
/ Constants / |
||||||||||||||||
/ LPC SRAM |
s t a r t s |
at |
0x40000000 , and t h e r e i s 32Kb = 8000 h / |
|||||||||||||
s t a c k |
a d d r : |
. word |
0 x40008000 |
|||||||||||||
/ Linker symbols / |
||||||||||||||||
d a t a |
s o u r c e : |
. word |
e t e x t |
|||||||||||||
d a t a |
s t a r t : |
. word |
d a t a |
|||||||||||||
d a t a |
e n d : |
. word |
e d a t a |
|||||||||||||
b s s |
s t a r t : |
. word |
b s s |
|||||||||||||
b s s |
e n d : |
. word |
e b s s |
|||||||||||||
. end
17
AR1803 |
May 10, 2006 |
Example 4(b) uses an initialized vector, so uses the .data section
/ ex4b main . c /
#include ” l e d . h”
static |
int l e d |
v a l u e [ 2 ] = {0x55 , |
0xAA} ; |
||||||
int main ( void ) |
|||||||||
{ |
i ; |
||||||||
int |
|||||||||
l e d |
i n i t ( ) ; |
||||||||
while ( 1 ) { |
|||||||||
l e d ( l e d |
v a l u e [ 0 ] ) ; |
||||||||
for ( i |
= 0 ; |
i < 0 x50000 ; |
i ++); |
||||||
l e d ( l e d |
v a l u e [ 1 ] ) ; |
||||||||
} |
for ( i |
= 0 ; |
i < 0 x50000 ; |
i ++); |
|||||
return 0 ;
}
Example 4(b) can be compiled using
arm-elf-gcc -O2 -mcpu=arm7tdmi -nostartfiles -T../lpc2138_flash.ld \ ex4_start.s ex4b_main.c led.c -o ex4b.elf
(where it is assumed that the LED functions are in the same directory as the example source) and then the sections dumped using
arm-elf-objdump -h ex4b.elf
ex4b.elf: file format elf32-littlearm
Sections: |
||||||
Idx Name |
Size |
VMA |
LMA |
File off |
Algn |
|
0 |
.text |
0000012c |
00000000 |
00000000 |
00008000 |
2**2 |
CONTENTS, |
ALLOC, LOAD, READONLY, CODE |
|||||
1 |
.data |
00000008 |
40000000 |
0000012c |
00010000 |
2**2 |
CONTENTS, |
ALLOC, LOAD, DATA |
|||||
2 |
.bss |
00000000 |
40000008 |
00000134 |
00010008 |
2**0 |
ALLOC |
||||||
3 |
.comment |
00000024 |
00000000 |
00000000 |
00010008 |
2**0 |
CONTENTS, |
READONLY |
|||||
The .data section LMA (load memory address) in Flash is the address at which the initial values are stored, while the VMA (virtual memory address) in SRAM is the start address at which the application refers to initialized variables.
18
AR1803 |
May 10, 2006 |
Table 1: LPC213x PLL control registers (p17 [10])
Name |
Description |
Access |
Reset Value |
Address |
PLLCON |
PLL Control |
R/W |
0 |
0xE01F C080 |
PLLCFG |
PLL Configuration |
R/W |
0 |
0xE01F C084 |
PLLSTAT |
PLL Status |
RO |
0 |
0xE01F C088 |
PLLFEED |
PLL Feed |
WO |
N/A |
0xE01F C08C |
3.5Example 5: LPC2138 processor initialization
Processor initialization code for all ARM-based processors follows a similar sequence of steps, however each processor has processor-specific steps. The Philips LPC21xx series of microcontrollers require the following processor initialization steps;
1.Exception vector setup
2.Phase-locked loop setup
3.Memory accelerator module setup
4.Setup stack pointers for each processor mode
5.Copy .data section to SRAM
6.Clear .bss
7.Jump to main
The initialization sequence starts with exception vector setup, since those vectors are located starting at address zero. The phase-locked loop (PLL) and memory accelerator module (MAM) are then setup so that the remaining code runs at the full processor clock speed. The memory accelerator module allows the LPC-microcontroller processor core to fetch instructions e ciently from slower on-chip flash RAM. The LPC213x User Manual [10] describes the PLL and MAM.
3.5.1PLL setup
The MCB2130 evaluation board contains an LPC2138 microcontroller connected to a 12MHz crystal. The PLL control registers are shown in Table 1, the crystal oscillator is described in Section 3.4 (p18 [10]) and the PLL is described in Section 3.7 (p26 [10]). The LPC2138 can operate with a processor clock frequency of up to 60MHz, so with a 12MHz crystal the PLL needs to be configured to e ectively multiply the crystal by 5. The phase-locked loop consists of a phase-detector, a Current Controller Oscillator (CCO), a divide-by-2×P output divider, and a divide-by-M feedback divider that follows the divide-by-2×P divider (so the PLL feedback division for the CCO is 2×M×P) (p28 [10] has a block diagram). The CCO operates over the frequency range 156MHz to 320MHz, and the output divider generates the processor clock frequency. The output divider options are 2, 4, 8, and 16, so for a desired 60MHz processor clock, the CCO can be operated at 240MHz with a divide-by-4 divider setting. The feedback multiplier required to get from 60MHz down to 12MHz is 5. The PLLCFG register settings are then PSEL[1:0] = PLLCFG[6:5] = 01b (P = 2) and MSEL[4:0] = PLLCFG[4:0] = 00100b (M = 5), i.e., PLLCFG = 0100100b = 24h (p29 [10]).
Programming of the PLL requires a special unlock (or feed) sequence, to avoid erroneous programming of the PLL. The PLL takes some time to lock, and so a status bit needs to be polled to
19
AR1803 |
May 10, 2006 |
check for lock (or an interrupt can also be generated). Once the PLL is locked, it can be used to clock the processor core. The sequence for programming the PLL (without using an interrupt) is;
1.Write the PLL PSEL and MSEL settings to the PLLCFG register (eg. 24h for the MCB2130).
2.Write 1 to the PLL enable bit 0 (PLLE) in the PLL control register (PLLCON) (p29 [10]).
3.Enable the PLL by writing the feed sequence to the PLLFEED register, i.e., 0xAA then 0x55 (p30 [10]). The feed sequence causes the values written during the first two steps to activate the PLL to lock and generate a 60MHz processor clock.
4.Poll bit 10 (PLOCK) in the PLL status register (PLLSTAT) until it becomes 1 (p30 [10]).
5.Write 1 to the PLL connect bit 1 (PLLC) in the PLL control register (PLLCON) (p29 [10]) (the enable bit, bit 0, should also remain set).
6.Connect the PLL clock to the processor core by writing the feed sequence to the PLLFEED register, i.e., 0xAA then 0x55.
Since the PLL is to be configured prior to stack setup, the PLL initialization sequence needs to be coded in assembler. An alternative processor initialization would be to setup the stacks first, and then call an _init function coded in C, prior to jumping to main. A C-coded PLL initialization sequence is
#define PLLCON (*(volatile unsigned int *)0xE01FC080) #define PLLCFG (*(volatile unsigned int *)0xE01FC084) #define PLLSTAT (*(volatile unsigned int *)0xE01FC088) #define PLLFEED (*(volatile unsigned int *)0xE01FC08C)
#define PLLCON_PLLE |
(1 << 0) |
|
#define PLLCON_PLLC |
(1 << 1) |
|
#define PLLSTAT_PLOCK |
(1 << 10) |
|
#define PLLFEED1 |
0xAA |
|
#define PLLFEED2 |
0x55 |
|
#define PLLCFG_VALUE |
0x24 |
|
void pll_init(void) |
||
{ |
||
PLLCFG |
= PLLCFG_VALUE; |
|
PLLCON |
= PLLCON_PLLE; |
|
PLLFEED = PLLFEED1; |
||
PLLFEED = PLLFEED2; |
||
while ((PLLSTAT & PLLSTAT_PLOCK) == 0); |
||
PLLCON |
= PLLCON_PLLC|PLLCON_PLLE; |
|
PLLFEED = PLLFEED1; PLLFEED = PLLFEED2;
}
This function can be compiled to assembler, and the output hand-optimized. An assembly-coded version of the PLL initialization is
/* Constants (and storage, used in ldr statements) */ PLLBASE: .word 0xE01FC080
20