This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

C51: Questions regarding SYSCLK

Hi,

i am a student and needs some help.
Can someone help solve some of my doubts?

Hmm..may i know what does it means by SYSCLK/12/10?
How can i go about calculating the timer values using the SYSCLK/12/10 if i want to use the codes below to make the LED blink at 1Hz?

Thanx=)

//------------------------------------------------------------------------------------
// MAIN Routine
//------------------------------------------------------------------------------------
void main (void) {

   // disable watchdog timer
   WDTCN = 0xde;
   WDTCN = 0xad;

   SFRPAGE = CONFIG_PAGE;                 // Switch to configuration page
   PORT_Init ();

   SFRPAGE = TMR3_PAGE;                   // Switch to Timer 3 page
   Timer3_Init (SYSCLK /120/10);        // Init Timer3 to generate interrupts
                                          // at a 10 Hz rate.
   EA = 1;                                                                                      // enable global interrupts

   SFRPAGE = LEGACY_PAGE;                 // Page to sit in for now

   while (1) {                            // spin forever

   }
}

//------------------------------------------------------------------------------------
// PORT_Init
//------------------------------------------------------------------------------------
//
// Configure the Crossbar and GPIO ports
//
void PORT_Init (void)
{
   XBR2    = 0x40;                     // Enable crossbar and weak pull-ups
   P1MDOUT |= 0x40;                    // enable P1.6 (LED) as push-pull output
}

//------------------------------------------------------------------------------------
// Timer3_Init
//------------------------------------------------------------------------------------
//
// Configure Timer3 to auto-reload and generate an interrupt at interval
// specified by <counts> using SYSCLK/12 as its time base.
//
//
void Timer3_Init (int counts)
{
   TMR3CN = 0x00;                      // Stop Timer3; Clear TF3;
                                       // use SYSCLK/12 as timebase
   RCAP3   = -counts;                  // Init reload values
   TMR3    = 0xffff;                   // set to reload immediately
   EIE2   |= 0x01;                     // enable Timer3 interrupts
   TR3 = 1;                            // start Timer3
}

//------------------------------------------------------------------------------------
// Interrupt Service Routines
//------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------
// Timer3_ISR
//------------------------------------------------------------------------------------
// This routine changes the state of the LED whenever Timer3 overflows.
//
// NOTE: The SFRPAGE register will automatically be switched to the Timer 3 Page
// When an interrupt occurs.  SFRPAGE will return to its previous setting on exit
// from this routine.
//
void Timer3_ISR (void) interrupt 14
{
   TF3 = 0;                               // clear TF3
   LED = ~LED;                            // change state of LED
}

Parents
  • Your code have some hints that you are not using a standard 8051, but you have not identified the chip nor given any info on it.

    1) What is your external crystal frequency?
    2) What is the CPU clock division for 1 instruction cycle? Standard 8051 is 12 clocks/instruction, many others are 6 or 2 clocks/instruction.
    3) The symbol SYSCLK in your program is just a text symbol with a nice name. It bears no influence on the actual clock rate of your CPU.
    4) Is Timer3_Init() an actual function in your code, or is it pseudocode? It has problems in so many levels:

    - It simply does not compile. 'While' is not a C keyword. Unless you have a macro named 'While'.
    - Your code seems to refer to timer 3, but the comments say 'timer 2' instead. This is a bug per se.
    - You seem to be configuring the timer for compare mode, with interrupt on match.
    - Now comes the weird part: you are placing the timer initialization code inside a loop. Assuming that count is a global variable (bad idea), the loop will iterate zero or more times, up to 100 times depending on the value of count on entry.
    - Do you have a interrupt service routine to process the compare interrupt?

    You need to determine a few referential information before you proceed, like the clocks/instruction rate of your processor, and the correct init sequence to setup the timer resources. With this, you can load the correct values in the compare register and eventually use the timer compare flag to signal the event, or have the interrupt handler to set the event.

Reply
  • Your code have some hints that you are not using a standard 8051, but you have not identified the chip nor given any info on it.

    1) What is your external crystal frequency?
    2) What is the CPU clock division for 1 instruction cycle? Standard 8051 is 12 clocks/instruction, many others are 6 or 2 clocks/instruction.
    3) The symbol SYSCLK in your program is just a text symbol with a nice name. It bears no influence on the actual clock rate of your CPU.
    4) Is Timer3_Init() an actual function in your code, or is it pseudocode? It has problems in so many levels:

    - It simply does not compile. 'While' is not a C keyword. Unless you have a macro named 'While'.
    - Your code seems to refer to timer 3, but the comments say 'timer 2' instead. This is a bug per se.
    - You seem to be configuring the timer for compare mode, with interrupt on match.
    - Now comes the weird part: you are placing the timer initialization code inside a loop. Assuming that count is a global variable (bad idea), the loop will iterate zero or more times, up to 100 times depending on the value of count on entry.
    - Do you have a interrupt service routine to process the compare interrupt?

    You need to determine a few referential information before you proceed, like the clocks/instruction rate of your processor, and the correct init sequence to setup the timer resources. With this, you can load the correct values in the compare register and eventually use the timer compare flag to signal the event, or have the interrupt handler to set the event.

Children
  • <html>
    "Your code have some hints that you are not using a standard 8051, but you have not identified the chip nor given any info on it."

    Hi,
    hmm..i am using the C8051F12X.
    1) the external clock frequency is 22.1184 MHz.The crystal frequency is 11.0592MHz.
    2)it should be 12clocks/instruction
    3)Timer3_Init() is an actual function in the program

    "Your code seems to refer to timer 3, but the comments say 'timer 2' instead. This is a bug per se."
    hmm..in the comments i typed wrongly.It should be referring to timer3.Thanx=)

    Actually, i have managed to make the LED blink at 1Hz..
    This is the code:

    //------------------------------------------------------------------------------------
    // Blinky.c
    //------------------------------------------------------------------------------------
    // Copyright (C) 2005 Silicon Laboratories, Inc.
    //
    // AUTH: BD
    // DATE: 1 JUL 2002
    //
    // This program flashes the green LED on the C8051F120 target board about five times
    // a second using the interrupt handler for Timer3.
    // Target: C8051F12x
    //
    // Tool chain: KEIL Eval 'c'
    //
    
    //------------------------------------------------------------------------------------
    // Includes
    //------------------------------------------------------------------------------------
    #include <c8051f120.h>         // SFR declarations
    
    //-----------------------------------------------------------------------------
    // 16-bit SFR Definitions for 'F12x
    //-----------------------------------------------------------------------------
    
    sfr16 RCAP3    = 0xCA;         // Timer3 reload value
    sfr16 TMR3     = 0xCC;         // Timer3 counter
    
    //------------------------------------------------------------------------------------
    // Global CONSTANTS
    //------------------------------------------------------------------------------------
    
    #define SYSCLK 3062500 // appproximate frequency in Hz
    
    sbit  LED = P1^6;   // green LED: '1' = ON; '0' = OFF
    
    
    //------------------------------------------------------------------------------------
    // Function PROTOTYPES
    //------------------------------------------------------------------------------------
    void PORT_Init (void);
    void Timer3_Init (int count);
    void Timer3_ISR (void);
    
    //------------------------------------------------------------------------------------
    // MAIN Routine
    //------------------------------------------------------------------------------------
    void main (void) {
    
     // disable watchdog timer
     WDTCN = 0xde;
     WDTCN = 0xad;
    
     SFRPAGE = CONFIG_PAGE;// Switch to configuration page
     PORT_Init ();
    
     SFRPAGE = TMR3_PAGE;      // Switch to  Timer 3 page
       Timer3_Init ();  // Init Timer3 to generate
                        //interrupts at a 10 Hz rate.
       EA = 1;      // enable global interrupts
    
       SFRPAGE = LEGACY_PAGE;   // Page to sit in for now
    
       while (1) {              // spin forever
    
       }
    }
    
    //------------------------------------------------------------------------------------
    // PORT_Init
    //------------------------------------------------------------------------------------
    //
    // Configure the Crossbar and GPIO ports
    //
    void PORT_Init (void)
    {
       XBR2    = 0x40;// Enable crossbar and weak pull-ups
       P1MDOUT |= 0x40; /*enable P1.6 (LED) as push-pull
                       output*/
    }
    
    //------------------------------------------------------------------------------------
    // Timer3_Init
    //------------------------------------------------------------------------------------
    //
    // Configure Timer3 to auto-reload and generate an interrupt at interval
    // specified by <counts> using SYSCLK/12 as its time base.
    //
    //
    void Timer3_Init (int count)
    {
    
    
      TMR3CN = 0x00;      // Stop Timer3; Clear TF3;
                               // use SYSCLK/12 as timebase
      RCAP3 =-count;     // Init reload values
      TMR3 = 0xffff;     // set to reload immediately
    
      EIE2|= 0x01;      // enable Timer3 interrupts
      TR3= 1;           // start Timer3
    
    
    
    }
    
    //------------------------------------------------------------------------------------
    // Interrupt Service Routines
    //------------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------------
    // Timer3_ISR
    //------------------------------------------------------------------------------------
    // This routine changes the state of the LED whenever Timer3 overflows.
    //
    // NOTE: The SFRPAGE register will automatically be switched to the Timer 3 Page
    // When an interrupt occurs.  SFRPAGE will return to its previous setting on exit
    // from this routine.
    //
    void Timer3_ISR (void) interrupt 14
    {
    
     int b;
    
       TF3 = 0;         // clear TF3
    
    
      b++;
       if (b ==5)
      {
        LED = ~LED; //toggle state of LED
        b=0;
      }
    
    }
    

    hmm..though it works but i would like to know if i am able to make the LED blinks at 1Hz if i change the TMR3 value, which when the RCAP3 values underflows to the same value as TMR3,it will restart the timer and cause interrupts(if enabled).Is there any way to calculate the value? cause my teacher told me to change the value of TMR3 but i didnt mananged to do so..

    Thanx for ur reply=)

  • 1) the external clock frequency is 22.1184 MHz.The crystal frequency is 11.0592MHz.
    I guess that you mean that the crystal is a 11.0592 and the PLL makes the sysclk 22.1182.
    2)it should be 12clocks/instruction
    the f12x is a one clocker !!! Please read the manual

    a final note: the f12x hax a SFR that controls the clocking of the timers

    Erik

  • In your code:

    void Timer3_ISR (void) interrupt 14
    {
        int b;
    
        TF3 = 0;         // clear TF3
    
        b++;
        if (b ==5)
        {
            LED = ~LED; //toggle state of LED
            b=0;
        }
    }
    

    You are using the variable 'b' with a static lifetime, i.e., its value is retained between executions of the function. HOWEVER, you are not declaring 'b' as static. An optimizing compiler can do whatever it wants with the value of 'b' when your handler is not running. The only reason why your code works is that C51 will not reuse the interrupt handler local vars because it can't prove it's usage pattern. But that is not valid for other processors, or for other functions that are not declared as interrupt.

    Check out what is the meaning of the keyword static, and how it applies to your usage of 'b'.

    Another thing: please answer what is the value of 'b' when your program first runs. Hint: N-E-V-E-R trust that uninitialized variables have any meaningful initial value, especially local vars.

  • "1) the external clock frequency is 22.1184 MHz.The crystal frequency is 11.0592MHz.
    I guess that you mean that the crystal is a 11.0592 and the PLL makes the sysclk 22.1182."

    to: Erik

    Thanx=) i will go check that out.

  • "An optimizing compiler can do whatever it wants with the value of 'b' when your handler is not running."

    Actually, it has nothing to do with optimisation.

    The whole point of local variables is that they do cease to exist between calls to the function - unless you specifically make them static.

  • In your code:

    void Timer3_ISR (void) interrupt 14
    {
        int b;
    
        TF3 = 0;         // clear TF3
    
        b++;
        if (b ==5)
        {
            LED = ~LED; //toggle state of LED
            b=0;
        }
    }
    

    hmm..okie..does it means that i add in the variable declaration--static int b;--at the global constant..and declare b=0 in the ISR?Thanx=)

  • "does it means that i add in the variable declaration--static int b;--at the global constant"

    No, it doesn't.

    Back to the textbook!

  • i add in the variable declaration--static int b;--at the global constant..and declare b=0 in the ISR?

    Almost there.
    1) Yes, you must declare 'b' as static unsigned char b; (why waste one int when one char can do). This will NOT make 'b' global, its scope is still local to the function, but its lifetime will be infinite, i.e., it will retain its value across the whole execution time of the program.

    2) To initialize 'b', you should declare it with initialization: static unsigned char b = 0;
    Thus, the first time your program runs, the value of 'b' will automagically be zero.

  • Andy wrote: "Actually, it has nothing to do with optimisation. The whole point of local variables is that they do cease to exist between calls to the function ..."

    You are right, of course. My point is exactly that. The only reason for that particular code to run as written is that the storage allocated for the locals in interrupt handlers can't be reused for main code.

    Were that function a non-interrupt function, it would crash and burn.

  • "Almost there.
    1) Yes, you must declare 'b' as static unsigned char b; (why waste one int when one char can do)."

    Hi, Thanx for ur help=)

  • "No, it doesn't.

    Back to the textbook!"

    Hi, i have checked that out already, static variable is another class of local variable.it is not destroyed on the exit of the function and will be available when function is next called.

    thanx=)