Hey everybody! So I’ve been mucking through and learning as much as I can about my little ARM7tdmi and I’ve run into a bit of a problem. I wrote some code to boot up my PLL to divide down by 8, multiply up by 160, and then the CPU clock divider divides down by 4 (the main oscillator is 14.318180 MHz). I wrote the following code to boot up my PLL:
/* crt0.S -- The capital S is important! */
/* Take advantage of the fact that we're using the C preprocessor */
#define OSCEN (0x01 << 5)
#define OSCSTAT (0x01 << 6)
#define PLLSTAT (0x01 << 26)
#define SCSSAFE (0x000000FB)
.text
.arm
.extern main
.global _start
_start:
/* Vectors (8 total) */
b reset /* reset */
b loop /* undefined instruction */
b loop /* software interrupt */
b loop /* prefetch abort */
b loop /* data abort */
.word 0x99fffe4f /* hand-calculated bootloader checksum */
b loop /* IRQ */
b loop /* FIQ */
/* Setup the C environment:
* Setup the PLL
* Copy .data into SRAM
* Zero out .bss
* setup stack pointer
* Jump to main */
reset:
/* Setup PLL */
/* Start by making sure it's disabled! */
ldr r0, =0
ldr r1, pllcon_addr
str r0, [r1]
/* You'll notice this code a number of times
It's the "feed sequence" which copies the
data from the edited registers into the real
registers somewhere. */
ldr r0, =0xAA
ldr r1, =0x55
ldr r2, pllfeed_addr
str r0, [r2]
str r1, [r2]
/* Activate the main oscillator */
ldr r0, scs_addr
ldr r1, [r0]
orr r1, r1, #OSCEN
and r1, r1, #SCSSAFE /* Mask out all reserved bits */
str r1, [r0]
/* Wait for main oscillator to settle */
ldr r1, =OSCSTAT
osc_loop:
ldr r2, [r0]
and r2, r2, r1
cmp r2, #0
beq osc_loop
/* Switch from the internal clock to the main oscillator */
ldr r0, =1
ldr r1, clksrcsel_addr
str r0, [r1]
/* Now set up the PLLCFG register */
ldr r0, =((0x08 << 16) | 160)
ldr r1, pllcfg_addr
str r0, [r1]
/* Now that the PLLCFG register will multiply up by
160 and divide down by 8, FEEED MEEEEE */
ldr r0, =0xAA
ldr r1, =0x55
ldr r2, pllfeed_addr
str r0, [r2]
str r1, [r2]
/* Now we enable the PLL */
ldr r0, =1
ldr r1, pllcon_addr
str r0, [r1]
ldr r0, =0xAA
ldr r1, =0x55
ldr r2, pllfeed_addr
str r0, [r2]
str r1, [r2]
/* Now we set the divider to match the value it will need after the PLL */
ldr r0, =3
ldr r1, cclkcfg_addr
str r0, [r1]
/* Now we loop while we wait fot the PLL output to stabalize */
ldr r0, =PLLSTAT
ldr r1, pllstat_addr
pll_loop:
ldr r2, [r1]
and r2, r0
cmp r2, #0
beq pll_loop
/* Now that the PLL has locked we simply connect it up */
ldr r0, =3
ldr r1, pllcon_addr
ldr r0, [r1]
ldr r0, =0xAA
ldr r1, =0x55
ldr r2, pllfeed_addr
str r0, [r2]
str r1, [r2]
/* PLL setup complete! Hope you don't see any magic smoke! */
/***************************************************/
/* I removed all the stuff which copies everything into RAM */
/***************************************************/
/* Constants:*/
/* System Controls and Status register */
scs_addr: .word 0xe01fc1a0
/* PLL constants */
clksrcsel_addr: .word 0xe01fc10c
pllcon_addr: .word 0xe01fc080
pllcfg_addr: .word 0xe01fc084
pllstat_addr: .word 0xe01fc088
pllfeed_addr: .word 0xe01fc08c
/* Clock divider constants */
cclkcfg_addr: .word 0xe01fc104
Can anyone spot what I’m missing? Currently the processor seems like it boots up fine, and is running slightly slower than it would had I not run the PLL at all, which would make sense if it was running directly from the 14.31818MHz oscillator then dividing down by 4 (giving ~3.57MHz. A smidge under 4MHz).
One thing which is confusing me is that when I step through “ldr r1, =OSCSTAT” I get the message (in openOCD):
"address + size wrapped(0xfffffffe, 0x00000004)
address + size wrapped(0xffffffff, 0x00000004)"
(Or maybe with the pipeline it could be “and r1, r1, #SCSSAFE” or “str r1, [r0]”), which almost sounds like it’s playing with the uninitialized stack?
Something weird is going on! I don’t know what it is! Any help/suggestions?
Thanks!