Not getting the right Frequency...

General discussions about working with the Astrobe IDE and programming ARM Cortex-M0, M3, M4 and M7 microcontrollers.
Post Reply
4GlCoder
Posts: 27
Joined: Fri Jul 22, 2011 2:47 pm

Not getting the right Frequency...

Post by 4GlCoder » Mon Aug 29, 2011 6:14 pm

I'm implementing some code to verify the frequency of the board i'm playing with. Have tried to adapt some routines from Olimex C code. But result is not good.
Below are 2 modules: 1) SYS.MOD gets frequency of board CPU / Periphery. 2) Test program to display some relevant values. Board is LPC2378-STK.
However I always end up with SystemClock = 6Mhz and RCClock = 15000 kHz. Which is no good..
Anybody an idea? :)

MODULE SYS;
IMPORT SYSTEM, LPC := LPC2378, Out;
CONST
HZ* = 1; KHZ* = 1000*HZ; MHZ* = 1000*KHZ;

(* Available PCLK offsets on LPC2378 *)
WDTPCLKOffset* =0; TIMER0PCLKOffset* =2; TIMER1PCLKOffset* =4; UART0PCLKOffset* =6;
UART1PCLKOffset* =8; PWM0PCLKOffset* =10; PWM1PCLKOffset* =12; I2C0PCLKOffset* =14;
SPIPCLKOffset* =16; RTCPCLKOffset* =18; SSP1PCLKOffset* =20; DACPCLKOffset* =22;
ADCPCLKOffset* =24; CAN1PCLKOffset* =26; CAN2PCLKOffset* =28; ACFPCLKOffset* =30;
BATRAMPCLKOffset* =32; GPIOPCLKOffset* =34; PCBPCLKOffset* =36; I2C1PCLKOffset* =38;
SSP0PCLKOffset* =42; TIMER2PCLKOffset* =44; TIMER3PCLKOffset* =46; UART2PCLKOffset* =48;
UART3PCLKOffset* =50; I2C2PCLKOffset* =52; I2SPCLKOffset* =54; MCIPCLKOffset* =56;
PCLKPCLKOffset* =60;

(*************************************************************************
* Function Name: SYS.GetFsclk
* Parameters: none
* Return: Integer
*
* Description: return Sclk [Hz]
*
*************************************************************************)
PROCEDURE GetFsclk*() : INTEGER;
CONST
IntRCOscFreq= 4*MHZ;
MainOscFreq = 12*MHZ;
RTCOscFreq = 32768*HZ;
PLLEBit = 24; PLLCBit = 25;
VAR
Mul, Div, Osc, Fsclk, cfgClk : INTEGER;
bits : SET;
BEGIN
SYSTEM.GET(LPC.PLLSTAT, bits);
IF (PLLCBit IN bits) & (PLLEBit IN bits) THEN
(* when PLL is connected *)
Mul := SYSTEM.VAL(INTEGER, bits * {14..0}) + 1;
Div := LSR(SYSTEM.VAL(INTEGER, bits * {23..16}), 16) + 1;
ELSE
Mul := 1; Div := 1;
END;
(* Find clk source *)
SYSTEM.GET(LPC.CLKSRCSEL, Fsclk);
Fsclk := Fsclk MOD 4; (* Only interessed in bits 0 and 1 *)
CASE Fsclk OF
0: Osc := IntRCOscFreq;
| 1: Osc := MainOscFreq;
| 2: Osc := RTCOscFreq;
| 3: Osc := 0; (* reserved value, so not relevant *)
END;
(* Calculate system frequency *)
SYSTEM.GET(LPC.CCLKCFG, cfgClk);
Fsclk := Osc*Mul*2;
Fsclk := Fsclk DIV (Div*(cfgClk+1));
Out.String("Mul="); Out.Int(Mul, 0); Out.String(",Div="); Out.Int(Mul, 0);
Out.String(",Osc="); Out.Int(Osc, 0); Out.Ln;
RETURN Fsclk
END GetFsclk;

(*************************************************************************
* Function Name: SYS.GetFpclk
* Parameters: Periphery As enumerated in the above defined const list
* Return: Integer
*
* Description: return Pclk [Hz]
*
*************************************************************************)
PROCEDURE GetFpclk*(Periphery : INTEGER) : INTEGER;
VAR
Fpclk, Reg, Val: INTEGER;
BEGIN
IF Periphery < 32 THEN
Reg := LPC.PCLKSEL0
ELSE
Reg := LPC.PCLKSEL1
END;
SYSTEM.GET(Reg, Val);
Periphery := Periphery MOD 32;
Val := LSR(Val, Periphery) MOD 4;
Fpclk := GetFsclk();
(* find peripheral appropriate periphery divider *)
CASE Val OF
0 : Fpclk := Fpclk DIV 4;
| 1 : (* None *)
| 2 : Fpclk := Fpclk DIV 2;
| 3 : Fpclk := Fpclk DIV 8;
END;
RETURN Fpclk
END GetFpclk;

END SYS.

MODULE TestSYS;
IMPORT Out, SYS, Main;
VAR
f : INTEGER;
BEGIN
f := SYS.GetFsclk();
Out.String("SystemClock = "); Out.Int(f DIV SYS.MHZ, 0); Out.String("MHz"); Out.Ln;
f := SYS.GetFpclk(SYS.RTCPCLKOffset);
Out.String("RTCClock = "); Out.Int(f DIV SYS.KHZ, 0); Out.String("KHz"); Out.Ln;
END TestSYS.

4GlCoder
Posts: 27
Joined: Fri Jul 22, 2011 2:47 pm

Re: Not getting the right Frequency...

Post by 4GlCoder » Mon Aug 29, 2011 6:17 pm

Forgot to mention that it seams the PLL is not locked, because Mul and Div always return 1. :?

cfbsoftware
Site Admin
Posts: 493
Joined: Fri Dec 31, 2010 12:30 pm
Contact:

Re: Not getting the right Frequency...

Post by cfbsoftware » Mon Aug 29, 2011 10:18 pm

Post your message again with the original code formatting preserved - it's difficult to comprehend without it.

To preserve the formatting, select your code after pasting it into your message and click on the 'Code' pushbutton beneathe the Subject line. If you do that, instead of:

IF (PLLCBit IN bits) & (PLLEBit IN bits) THEN
(* when PLL is connected *)
Mul := SYSTEM.VAL(INTEGER, bits * {14..0}) + 1;
Div := LSR(SYSTEM.VAL(INTEGER, bits * {23..16}), 16) + 1;
ELSE
Mul := 1; Div := 1;
END;

you will see:

Code: Select all

IF (PLLCBit IN bits) & (PLLEBit IN bits) THEN 
  (* when PLL is connected *)
  Mul := SYSTEM.VAL(INTEGER, bits * {14..0}) + 1;
  Div := LSR(SYSTEM.VAL(INTEGER, bits * {23..16}), 16) + 1;
ELSE
  Mul := 1; Div := 1;
END;

4GlCoder
Posts: 27
Joined: Fri Jul 22, 2011 2:47 pm

Re: Not getting the right Frequency...

Post by 4GlCoder » Tue Aug 30, 2011 6:04 pm

Ok, Here we go again...

Code: Select all

MODULE SYS;
IMPORT SYSTEM, LPC := LPC2378, Out;
CONST
  HZ* = 1; KHZ* = 1000*HZ;  MHZ* = 1000*KHZ;
  
  (* Available PCLK offsets on LPC2378 *)
  WDTPCLKOffset*    =0;   TIMER0PCLKOffset* =2;   TIMER1PCLKOffset* =4;   UART0PCLKOffset* =6;
  UART1PCLKOffset*  =8;   PWM0PCLKOffset*   =10;  PWM1PCLKOffset*   =12;  I2C0PCLKOffset*  =14;
  SPIPCLKOffset*    =16;  RTCPCLKOffset*    =18;  SSP1PCLKOffset*   =20;  DACPCLKOffset*   =22;
  ADCPCLKOffset*    =24;  CAN1PCLKOffset*   =26;  CAN2PCLKOffset*   =28;  ACFPCLKOffset*   =30;
  BATRAMPCLKOffset* =32;  GPIOPCLKOffset*   =34;  PCBPCLKOffset*    =36;  I2C1PCLKOffset*  =38;
  SSP0PCLKOffset*   =42;  TIMER2PCLKOffset* =44;  TIMER3PCLKOffset* =46;  UART2PCLKOffset* =48;
  UART3PCLKOffset*  =50;  I2C2PCLKOffset*   =52;  I2SPCLKOffset*    =54;  MCIPCLKOffset*   =56;
  PCLKPCLKOffset*   =60;

(*************************************************************************
 * Function Name: SYS.GetFsclk
 * Parameters: none
 * Return: Integer
 *
 * Description: return Sclk [Hz]
 *
 *************************************************************************)
PROCEDURE GetFsclk*() : INTEGER;
CONST
  IntRCOscFreq=     4*MHZ;
  MainOscFreq =    12*MHZ;
  RTCOscFreq  = 32768*HZ;
  PLLEBit = 24; PLLCBit = 25;
VAR
  Mul, Div, Osc, Fsclk, cfgClk : INTEGER;
  bits : SET; 
BEGIN
  SYSTEM.GET(LPC.PLLSTAT, bits);
  IF (PLLCBit IN bits) & (PLLEBit IN bits) THEN 
    (* when PLL is connected *)
    Mul := SYSTEM.VAL(INTEGER, bits * {14..0}) + 1;
    Div := LSR(SYSTEM.VAL(INTEGER, bits * {23..16}), 16) + 1;
  ELSE
    Mul := 1; Div := 1;
  END;
  (* Find clk source *)
  SYSTEM.GET(LPC.CLKSRCSEL, Fsclk);
  Fsclk := Fsclk MOD 4;   (* Only interessed in bits 0 and 1 *)
  CASE Fsclk OF
    0: Osc := IntRCOscFreq;
  | 1: Osc := MainOscFreq;
  | 2: Osc := RTCOscFreq;
  | 3: Osc := 0; (* reserved value, so not relevant *)
  END;
  (* Calculate system frequency *)
  SYSTEM.GET(LPC.CCLKCFG, cfgClk);
  Fsclk := Osc*Mul*2;  
  Fsclk := Fsclk DIV (Div*(cfgClk+1));
  Out.String("Mul="); Out.Int(Mul, 0); Out.String(",Div="); Out.Int(Mul, 0);
  Out.String(",Osc="); Out.Int(Osc, 0); Out.Ln;
  RETURN Fsclk
END GetFsclk;

(*************************************************************************
 * Function Name: SYS.GetFpclk
 * Parameters: Periphery As enumerated in the above defined const list
 * Return: Integer
 *
 * Description: return Pclk [Hz]
 *
 *************************************************************************)
PROCEDURE GetFpclk*(Periphery : INTEGER) : INTEGER;
VAR
  Fpclk, Reg, Val: INTEGER;
BEGIN
  IF Periphery < 32 THEN
    Reg := LPC.PCLKSEL0
  ELSE
    Reg := LPC.PCLKSEL1
  END;
  SYSTEM.GET(Reg, Val); 
  Periphery := Periphery MOD 32;
  Val := LSR(Val, Periphery) MOD 4;
  Fpclk := GetFsclk();
  (* find peripheral appropriate periphery divider *)
  CASE Val OF 
    0 : Fpclk := Fpclk DIV 4;
  | 1 : (* None *)
  | 2 : Fpclk := Fpclk DIV 2;
  | 3 : Fpclk := Fpclk DIV 8;
  END; 
  RETURN Fpclk
END GetFpclk;

END SYS.
And the second part:

Code: Select all

MODULE TestSYS;

IMPORT Out, SYS, Main;

VAR
  f : INTEGER;
BEGIN
  f := SYS.GetFsclk();
  Out.String("SystemClock = "); Out.Int(f DIV SYS.MHZ, 0); Out.String("MHz"); Out.Ln;
  f := SYS.GetFpclk(SYS.RTCPCLKOffset);
  Out.String("RTCClock = "); Out.Int(f DIV SYS.KHZ, 0); Out.String("KHz"); Out.Ln;
END TestSYS.

cfbsoftware
Site Admin
Posts: 493
Joined: Fri Dec 31, 2010 12:30 pm
Contact:

Re: Not getting the right Frequency...

Post by cfbsoftware » Wed Aug 31, 2011 12:34 pm

The value of m must be less than n when you use a SET range {m .. n}
i.e. m .. n is a shorthand for m, m+1, ... , n-1, n.

Currently the compiler does not object but as a result of this report we will modify it so that it reports an error message when this error is detected in the future.

When I changed the statements in your example from:

Code: Select all

    Mul := SYSTEM.VAL(INTEGER, bits * {14..0}) + 1;
    Div := LSR(SYSTEM.VAL(INTEGER, bits * {23..16}), 16) + 1;
to:

Code: Select all

    Mul := SYSTEM.VAL(INTEGER, bits * {0..14}) + 1;
    Div := LSR(SYSTEM.VAL(INTEGER, bits * {16..23}), 16) + 1;
the resulting output was:

Mul=12,Div=12,Osc=12000000
SystemClock = 72MHz
Mul=12,Div=12,Osc=12000000
RTCClock = 18000KHz

4GlCoder
Posts: 27
Joined: Fri Jul 22, 2011 2:47 pm

Re: Not getting the right Frequency...

Post by 4GlCoder » Wed Aug 31, 2011 4:18 pm

Thanks, problem has been solved.
A reason why I did this: The NXP doc always works from MSB to LSB so I reflected this in code.
On the other side.. I -THOUGHT I had tested this in onther testcode, but didn't bump into it.
Couldn't find any evidence that the range MUST be from low..high
Thanks anyway for pointing this out!

Post Reply