Thursday, July 29, 2010

speeding up the clock

The prior example showed that when booting from flash you are running using the slow clock. This clock reading the docs is something like 32768 hz. pretty slow.

Looking at section 25.7 as a reference for how to switch to the off chip/main oscillator and to use the pll to run faster than that oscillator.

48mhz is a useful frequency in case you decide to do usb stuff in the future, so lets go for that speed. The oscillator on the SAM7-H256 is 18.432, a prescribed Atmel sam7 frequency for these parts. Using this calculator from atmel

http://www.atmel.com/dyn/resources/prod_documents/AT91SAM_pll.htm

Knowing the oscillator is 18.432 mhz, the pll minimum is 1mhz and the desired is 48mhz I got a divide by 5 and multiply by 13. The code below is the same as my prior examples except it adds a function to switch to the main clock. The details of the registers is an exercise for the reader, note though that the multiply value is the number in the register plus 1 so if we want to multiply by 13 we should put a 12 in the register.



void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
void ASMDELAY ( unsigned int );

#define WDT_BASE 0xFFFFFD40
#define WDT_CR (WDT_BASE+0x04)

#define PMC_BASE 0xFFFFFC00
#define CKGR_MOR (PMC_BASE+0x0020)
#define CKGR_PLLR (PMC_BASE+0x002C)
#define PMC_MCKR (PMC_BASE+0x0030)
#define PMC_SR (PMC_BASE+0x0068)

#define PIOA_BASE 0xFFFFF400

#define PIO_PER 0x0000
#define PIO_OER 0x0010
#define PIO_SODR 0x0030
#define PIO_CODR 0x0034
#define PIO_PUDR 0x0060

#define PIOA_PER (PIOA_BASE+PIO_PER)
#define PIOA_OER (PIOA_BASE+PIO_OER)
#define PIOA_SODR (PIOA_BASE+PIO_SODR)
#define PIOA_CODR (PIOA_BASE+PIO_CODR)
#define PIOA_PUDR (PIOA_BASE+PIO_PUDR)


#define LED_BIT (1<<8)

void switch_to_mainclock ( void )
{
PUT32(CKGR_MOR,0x701);
while(1) if(GET32(PMC_SR)&1) break; //wait for MOSCS
//div by 5, mul by 13 should give 48mhz
PUT32(CKGR_PLLR,0x000C3F05);
//PUT32(CKGR_PLLR,0x00013F01); //mul by 2? 30864 mhz?
//PUT32(CKGR_PLLR,0x00023F01); //mul by 3?

while(1) if(GET32(PMC_SR)&(1<<2)) break; //waitfor LOCK
while(1) if(GET32(PMC_SR)&(1<<3)) break; //waitfor MCKRDY

PUT32(PMC_MCKR,0x01); //MAIN clock no prescale

while(1) if(GET32(PMC_SR)&(1<<3)) break; //waitfor MCKRDY
}

int notmain ( void )
{
PUT32(WDT_CR,1<<15); //disable wdt
switch_to_mainclock();
PUT32(PIOA_PER,LED_BIT); //enable/connect PIO control to led output
PUT32(PIOA_PUDR,LED_BIT); //disable pull up resistor
PUT32(PIOA_OER,LED_BIT); //enable/set as an output pin
PUT32(PIOA_CODR,LED_BIT); //turn on led. other side of led is 3.3v so to turn it on drive/sink 0 volts.

while(1)
{
PUT32(PIOA_CODR,LED_BIT);
ASMDELAY(0x300000);
PUT32(PIOA_SODR,LED_BIT);
ASMDELAY(0x300000);
}
return(0);
}



we can see that we have to make the counter value bigger between led on and off in order to make it blink at a human readable/tolerable rate. so we have indeed booted from flash and increased the arm's clock speed.

Ideally you do not want to loop instructions like this to time things, you want to use a timer, which is a future example.

use the makefile and vectors.s and memmap from prior posts in order to build this test program. the prior (sam-ba) post describes how to erase and load the program into flash.

No comments:

Post a Comment