EmbeddedRelated.com
Forums

LPC2148 Timming

Started by atomsoftlive August 1, 2009
Hey guys. I wanted to know some info.

As you may know already. I have a LPC2148 board from olimex which is fine. The only trouble im having is timming.

i have a nice long piece of code which i got to work but only after tweaking the MicroSecond Delay code i have. Can someone help me understand the timing per cycle.

Like if i want to delay 10uS how do i know how many cycles is it? I know this is a silly question but at what speed is my ARM7 CPU running so i can calc this myself?

This is my PLL Code:

void Initialize(void) {

// Setting Multiplier and Divider values
PLL0CFG=0x23;
feed();

// Enabling the PLL */
PLL0CON=0x1;
feed();

// Wait for the PLL to lock to set frequency
while(!(PLL0STAT & PLOCK)) ;

// Connect the PLL as the clock source
PLL0CON=0x3;
feed();

// Enabling MAM and setting number of clocks used for Flash memory fetch (4 cclks in this case)
MAMCR=0x2;
MAMTIM=0x4;

// Setting peripheral Clock (pclk) to System Clock (cclk)
VPBDIV=0x01;

}
void feed(void)
{
PLL0FEED=0xAA;
PLL0FEED=0x55;
}

I assume im at 60mhz with this. Am i correct?

If so thats 60,000,000 Cycles in 1 second right?

so for a 1uS(microSecond) delay i should delay about 60 cycles right?

If thats the case why does this work so well:

void DelayUs(int us) {
int tmp;
for (; us>0; us--);
for(tmp=0;tmp<400;tmp++);
}

An Engineer's Guide to the LPC2100 Series

--- In l..., "atomsoftlive" wrote:
>
> i have a nice long piece of code which i got to work but only after tweaking the MicroSecond Delay code i have. Can someone help me understand the timing per cycle.
>

If you want accurate timing you should not depend on the time taken to execute instructions. Apart from being difficult to determine it also leads to unmaintainable code. There are too many variables involved in execution time to use a simple loop apart from when you need very crude timings. Consider these possibilities: What if you change (deliberately or accidentally) an optimisation option? What if you need to change the clock speed, move to a different LPC2xxx MCU etc. etc.

What you should do is use the Timer facilities of the LPC2148. Check to see if your development system libraries have the function call you need. e.g. Armaide users can use the uSecDelay and MSecDelay functions from standard Timer library module for delays accurate to a microsecond.

If you do not have access to such a library then read Chapter 15 of the LPC2148 User manual to find out how to program a delay using a Timer. There's not much to it - to give you an idea part of the version written in Oberon-07 looks like this:

PROCEDURE* uSecDelay*(CONST delay: INTEGER);
VAR
prescaleMax, count: INTEGER;
BEGIN
SYSTEM.PUT(controlRegister, reset);
prescaleMax := (LPC.PCLK DIV 1000000) * delay;
SYSTEM.PUT(prescaleRegister, prescaleMax);
SYSTEM.PUT(controlRegister, enable);
REPEAT SYSTEM.GET(counter, count) UNTIL count # 0;
SYSTEM.PUT(controlRegister, disable)
END uSecDelay;

Regards,
Chris Burrows
Armaide v2.1: LPC2000 Oberon-07 Development System
http://www.cfbsoftware.com/armaide

Thats the thing ill check the crossworks docs. But if there is none i still need to know how much ot count to using the Timer. Hence i still have this issue.

This is why i needed it....
It works but i want exact timing for other projects.
http://www.youtube.com/watch?vNid3VmXUg&eurl=http%3A%2F%2Fwww.electro-tech-online.com%2Fmicro-controllers%2F93351-graphic-lcd-96x64-w-sed1565-controller-13.html&feature=player_embedded

I tried this:

// Setting Multiplier and Divider values
PLL0CFG=0x24;
PLL0FEED=0xAA;
PLL0FEED=0x55;

// Enabling the PLL */
PLL0CON=0x1;
PLL0FEED=0xAA;
PLL0FEED=0x55;

// Wait for the PLL to lock to set frequency
while(!(PLL0STAT & 0x400)) ;

// Connect the PLL as the clock source
PLL0CON=0x3;
PLL0FEED=0xAA;
PLL0FEED=0x55;

But still when i do a 1us delay it takes too long. I know because i have a 400 ms delay that takes like 4 seconds.

This is my complete delay code so far it works pretty well but not sure how precise:

void DelayUs(int us) {
int tmp;
for (; us>0; us--){
for(tmp=0;tmp<2;tmp++){;}
}
}

void DelayMs(int ms) {
for (; ms>0; ms--){
DelayUs(1000);
}
}
void DelayS(int se) {
for (; se>0; se--){
DelayMs(1000);
}
}

--- In l..., "atomsoftlive" wrote:
>
> I tried this:
>
> // Setting Multiplier and Divider values
> PLL0CFG=0x24;
> PLL0FEED=0xAA;
> PLL0FEED=0x55;
>
> // Enabling the PLL */
> PLL0CON=0x1;
> PLL0FEED=0xAA;
> PLL0FEED=0x55;
>
> // Wait for the PLL to lock to set frequency
> while(!(PLL0STAT & 0x400)) ;
>
> // Connect the PLL as the clock source
> PLL0CON=0x3;
> PLL0FEED=0xAA;
> PLL0FEED=0x55;
>
> But still when i do a 1us delay it takes too long. I know because i have a 400 ms delay that takes like 4 seconds.
>
> This is my complete delay code so far it works pretty well but not sure how precise:
>
> void DelayUs(int us) {
> int tmp;
> for (; us>0; us--){
> for(tmp=0;tmp<2;tmp++){;}
> }
> }
>
> void DelayMs(int ms) {
> for (; ms>0; ms--){
> DelayUs(1000);
> }
> }
> void DelayS(int se) {
> for (; se>0; se--){
> DelayMs(1000);
> }
> }
>

The other problem with your approach is that compiler optimizations might just omit the entire code. The compiler knows the the 'us' paramter is not passed back to the caller (it isn't a pointer) and it know that tmp isn't used outside the function. At some level of optimization, the whole block disappears.

But, if you really want to do your delays this way, you need to find out what code is emitted and how long each instruction takes. The ARM Architecture Reference Manual has all the timing information. Not that it is useful because the code fetch from flash is more than one instruction so determining the exact timing is difficult.

It looks like you are trying to get the processor to run at 60 MHz (assuming a 12 MHz crystal - common for the LPC2148). But you haven't set the MAMTIM (to 0x03) and MAMCR (to 0x02). Not that it matters but you haven't set the VPDIV (to 0x00) to get a 15 MHz peripheral clock.

So, after you set PLL0coN to 0x3 and feed, add:

MAMTIM = 0x03;
MAMCR = 0x02;
VPBDIV = 0x00; // change as required

Richard