This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Delay calculation using for loop

Other Parts Discussed in Thread: MSP430G2452

Hi,

Iam trying to calculate delay of 30 u secs using for loop for MSP430 controller for which the crystal frequecy connected is 32kHz. The logic Iam using is as folows. Please correct me if Iam wrong

1/32kHz = 31.25 u sec.

Now how can i use for loop in calculating 30 u sec delay as single instruction cycle itself comes to be 31.25 u sec Please help me.

  • First, it's 32768Hz, not 32kHz, so 1 crystal cycle is 30.517µs, which is much closer :)

    Is your MCLK is running on this 32kHz clock too? If so, well, then one instruction cycle is 30.517µs. But I doubt it. You're probably running MCLK from a DCO-derived frequency which is much higher (1MHz? 16MHz?).

    Unfortunately, this frequency is not exactly known. Even with a calibrated DCO, you have an error which is >1%, so the difference between 1 crystal tick and your desired 30µs is not larger than anything you can guess or derive from a DCO based MCLK.

    So the question is: what do you need this delay for. Different purposes open different possibilities.

    Anyway: you should never, Never, NEVER use a for loop for doing any critical or precise delays. Depending on the compiler and optimization levels, the outcome can vary from zero to anything.
    Even if you don't have a precise timebase, using your MCLK signal on a timer gives way better and predictable results than any loop.

  • Hi Jens,

    Thank you for your time.

    Let me tell u my understandings.Regarding DCO  Iam not using any SCFQCTL registers. It is given in the datasheet that

    "After a PUC, MCLK and SMCLK are sourced from DCOCLK at 32 times the

    ACLK frequency. When a 32768-Hz crystal is used for ACLK, MCLK and

    SMCLK stabilize to 1.048576 MHz." So I guess my MCLK runs at 1.1Mhz by default afetr powering up my system.

    The delay is for reading the bits that come through i wire device that is connected. We need to give a delay before everytime a bit is read.

    As u suggested if we have to use the timer for delay calculation what would be the value given  to the CCRO. Is it like the same calculation I did before.

    1/1.1MHz = 909 nsec. So each tick is 909 nsec. so the count will be 30 usec/909 nsec = 33. Please correct me if Iam wrong. Also please tell me if any other factors affect this calculation.

  • Deepu,

    Look at the coding examples for the device that you are targetting. You will see examples using the timer as an interrupt to derive a constant time base.

     Look at example ta_01.

    It sets the timer source as the DCO (1.048576 MHz);

    At that frequency, you would need to load the timer with approx 31.

    I got to this value by doing the following:     .000030/( 1/1048576)

    Let me know if you have any other questions.

     

    -Jason

     

     

     

  • Hi Jason,

     

    Thank you for the example. I have a query on IO port interrupt. I have to set an interrupt when the falling edge is detected into an ISR which is a counting

    loop incrementing until a rising edge is detected in the output. Now based on the number of counts the frequency can be determined.

    I used the following code for this

    #define PIN 0x80   // sensor is connected to P1.7

    #define signal() (PIN&P1IN)

    void main(void)

    {

    WDTCTL=WDTPW+WDTHOLD;

    P1DIR |=0X40;

    P1OUT = 0X00;

    P1IE | =0X80;

    P1IES | = 0X80;

    P1IFG & =~0X80;

    _bis_SR_register(LPM4_bits+GIE);

    }

    #pragma vector=PORT1_VECTOR

    _interrupt void Port_1(void)

    {

    unsigned int i;

    while(signal()==0x00)       // till P1.7 detects low to high

    i++;

    }

    Please correct me if anything is wrong and also please tell me how to calculate frequency using the " i " count.

     

  • deepu said:
    So I guess my MCLK runs at 1.1Mhz by default afetr powering up my system.

    Well, actually not. At least not immediately and not cetainly.
    First, teh crystal needs to come up. This may take a long time in which the FLL has no reference and steps down teh DCO to minimum frequency of the current (default) RSEL range.

    Then, when (or rahter if?) the crystal is finally up and running, it will take up to 64 crystal cycles (=2ms) to reach the final frequency. This is an eternity for your code. You might be half through the whle job before your MCLK has stabilized. And then, FLL stabilized clock has a jitter on it. It constantly changes between two frequencies, one above, the other below the 'target'. The average (in the datasheet measured over 5ms) is correct, but the momentary frequency constantly changes.
    Normally it won't be a problem, but since the additional 0.5ms for a crystal tick-based delay seem to be a problem for you, this should be considered.

    Anyway, you don't know what the compiler generates from your loop, unless you write the loop in assembly language. There is a compiler intrinsic __delay_cycles() that does it for you. Still you don't knwo whether your delay was interrupted by one or many ISRs, whose execution tiem will add to the loop. Using a timer will prevent this from happening (except if the ISR is called at the end of the delay, so the main thread isn't running at the moment the delay expires).

    I wonder why people are so reluctant to implement timer delays? Once implemented, there are no more problems with any delays ever in the whole project (actually all projects, as the code can be re-used easily). Instead cycles are counted, instructions carefully aligned and with the next project/device revision/whatever, the whole code is worthless and needs to be rewritten.

     

  • Hi Jens,

    As per your suggestion i used timer for giving the delay. but I observed some problem. Initially i tried with an LED program  for 20 usec of timer in CRO i could observe the delay for 40 usec, for 30 it was giving 60 and it wnet on doubling. But when i tried for 10usec I could a delay of 1msec on CRO and this went on increasing whne i reduced the timer count. Iam giving my code here. Please correct me if Iam wrong and please suggest me if i can do it in any other way. I even try to give a delay of 2msec for the stabilisation.

    void main(void)
    {
      
      WDTCTL = WDTPW + WDTHOLD;                  // Stop watchdog timer
       SCFQCTL=0x1F;                                   // Crystal frequency is 1MHz (32.64*32)
     SCFI0=0x00;
      SCFI1=0x00;
      FLL_CTL0=0xB0;                                   // No division for the clock is n eeded
      FLL_CTL1=0x20;                                   // Turn of the other crystal XT2 As we rae using internal lfxt....
      start_time=0;
      timer_init();
     P4DIR |=0x02;

       _BIS_SR(GIE);

       while(start_time<500);                        // 2msec for stabilisation


       while(1)
       {
         flag1=1;
          P4OUT=0x02;                                    // LED connected to P4.1
        while(t1==2);
          P4OUT=0x00;
         while(t1==4);
         flag1=0;
         t1=0;
       }
        
    }

     


    void timer_init(void)
    {
       TACTL = TASSEL_2+TACLR+ID0;                  // SMCLK, counts to CCR0 and down to 0
       CCTL0 = CCIE;                                                   // CCR0 interrupt enabled
       CCR0 = 20;                                                         // since SMCLK is of 1.1 MHz frequency, the count 20 is equal to 20 usec approximately
       TACTL |=MC_1;
    }


    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A(void)
    {
      start_time++;
      if(flag1==1)
        t1++;
    }

  • Hi Jens,

     This is some more information i wnat to provide. Iam using a crystal of 32KHz and XIN and no other crystal is connected at XT2. Should i use any high frequency crystal to give less delay timings like 10usec? Please help me with this.

  • Two things:

    deepu said:
    // SMCLK, counts to CCR0 and down to 0

    No. Default is stopped, and MC_1, which you set later, uses up mode, whcih counts to CCR0 and begins from 0, so it counts CCR0+1 cycles each.

    deepu said:
    // since SMCLK is of 1.1 MHz frequency, the count 20 is equal to 20 usec approximately

    Yes. And also to exactly 21 MCLK cycles. Since callign the ISR and returning takes 11 cycles, there are only 10 left for the code inside. Basically, you're using up almost 100% of the CPU inside teh ISR or while entering and exiting it. Going below 20 will hold your CPU inside the ISR completely, so your main loop completely freezes except for some interference effects where you were so late with responding to the last IRQ that you already handle the newest one and have some cycles left for main then.

    As for the doubling, well, you toggle the LED on each interrupt, so the LED frequency is 1/2 the ISR frequency. The light and dark periods of the LED will EACH reflect one delay.

    Anyway, for delays below 1ms I use a different aproach: the timer is running in continuous mode (MC_2) with 1MHz. If I need a delay of, say 10µs, I write TAR+10 to TACCRx and wait for the CCRx bit being set. Then the 10µs have passed. (the time for programming needs to be considered too, so it works only for delays >4µs and 4 needs to be subtracted from the delay time). It does not involve any ISR, just a macro that does the wait - and a dedicated CCRx register (ccr0 is used for a continuous 1ms interrupt)

    Normally, there is no need to count sub-ms intervals in a variable or such, they just have to pass.

    If you need to act on shorter delays than several µs, then you definitely need to speed up your MCLK. :)

  • Hello Jens,

    I  found the discussion going on quite uefull and interesting.

    I have one doubt, During power up of my product which uses 32....kHz external crystal and 4.25Mhz DCO frequency.

    I want to wait for calibration of DCO till 32....kHz stablizes,

    for which i want to use below code:

    do
      {
        IFG1 &= ~OFIFG;                         // Clear oscillator fault flag
        for (i = 50000; i; i--);                // Delay
      }
      while (IFG1 & OFIFG)                    

    My question here is how do i decide on Delay? whether 50000 is a correct delay factor or not?

    With Best Regards,

    Deepak

  • deepak raina said:
    for (i = 50000; i; i--);                // Delay

    This is no delay at all.
    Any optimizing compiler will detect that there's nothing going on inside teh loop and teh loop can be replaced by a simple i=0 instead. Worse, if I is a local variable and not used anywhere after in this funciton it might get optimized away totally.
    If you use a global variable an ddeclare it volatile, then the compiler will not optimize the 50000 decrements, but it sill may decide to make only 5000 loops over a series of 10 decrements. Which is a bit longer but executes faster.

    So a for loop is no reliable delay.
    Normally you should use timers for delay, btu since it is in teh clock system setup, the alternative is usign the __delay_cycles(x) intrinsic instead. You still do not know how much 'real' time passes during this loop, but you know at least that it will be x CPU cycles.

    In this case, however, delay isn't that important. On older MSPs, you can clear OFIFG and it will take some time (see device datasheet for worst case minimum fault frequency) to get set agian, which you'll need to wait before checking it again.

    Onnewer MSPs you cannot clear OFIFG at all if the fault condition persists. Which means the crystal hasn't responded for a minimum number of consecutive oscillations. Here, you don't need a delay at all. Once you're able to clear OFIFG, all configured oscillators are working properly. But it might be necessary to check some other fault bits in this loop, as it may be that e.g. the FLL has problems with the currend DCO settings, requiring a config change. This won't go away at all without doing something, no matter how long you wait.

    So the proper code depends on teh used MSP and its clock system, and your wanted configuration of this clock system.

  • Thanks for the details.

    Infact i was planning to use __delay_cycles(x) only.

    i am using MSP430G242, so please suggest how do i check whether 32...kHz crystal is stablized during power up when my program counter hits main().

    Regards,

    Deepak

     

  • The MCU is MSP430G2452,

  • What to do:

    1) switch the port pins that share the XT1IN/XT1OUT funcitonality to module use by setting the proper PxSEL bits. On the G2452 these are P2.6 and P2.7. On many MSPs, these pins are not shared with port pins, then this can be skipped.

    2) if the MSP has an XT1OFF bit, clear it (the 2x series doesn't, so skip this, but the 5x has)

    3) set the proper load capacitance for your crystal (see crystal datasheet) with the XCAPx bits. If you have external capacitors, set them to 0 (1pF = pin parasitic capacitance)

    4) clear the OFIFG bit. Wait some time (depending on the fault detection time in the datasheet) to give OFIFG a chance to get set again. if it isn't clear anymore after the delay, loop to 4. If it stays clear, you're done. On 5xx clock system, the fault detection has been improved, OFIFG cannot be cleared at all unless the crystal didn't have a fault for a certain time, so no delay is needed in the loop.

  • Regarding point 4)

    the datasheet says fault frequency from 10Hz to 10000Hz which means delay of 100ms to 0.1ms, so ideally we select 100ms.

    Only one concern I have here is since crystal is not stabilized, so whatever the delay we mention above will not be precise, so how to take care of that?

     

  • Basic engineers rule: Carefully calculate the required value for at least 10 digits. Add a 10% safety margin, and the double the result just to get sure :)

    deepak raina said:
    ideally we select 100ms

    Yes, that's the worst-case time for OFIFG to be set again.

    deepak raina said:
    since crystal is not stabilized, so whatever the delay we mention above will not be precise

    Indeed. Without a stabilized crystal, you cannot switch MCLK to the crystal (You probably won't anyway, since it would result in only 32768Hz core clock for the CPU). So you'll have to live with the DCO. You can see the default DCO settings in the family users guide and the resulting minimum/maximum frequencies in teh datasheet. Then you know how many cycles you'll need worst case for a 100ms delay. More won't hurt :)

     

  • Secondly,i came to know that if OFIFG flag is set, it doesnt mean crystal is 100% stable, could you please tell me what is the % error at which OFIFG flag works or gets cleared indicating crystal is stable?

  • Also, you have mentioned that we can use DCO,How fast does DCO stablize for MSP430G242 assuming vcc/vdd voltage level has crossed 2.2V in 2.5ms?

  • deepak raina said:
    could you please tell me what is the % error at which OFIFG flag works or gets cleared indicating crystal is stable?

    On the older MSPs, it is ratehr a retriggered monoflop. The monoflop is started when you clear OFIFG and whenever it gets an oscillation edge form the crystal, it is retriggered. If there is no oscillation from the crystal for (worst case) 100ms, then the monoflop expires and the OFIFG bit is set. In this case, the oscillator circuit gives the crystal another starting kick once you clear OFIFG again.

    The OFIFG bit does not indicate that the required frequency isn't reached (if the MSP would know this frequency, it wouldn't require a crystal at all), but rather that there was NO crystal pulse for the whole fault time period.

    Usually, a crystal will either start and sooner or later stabilize, or the ascillation will cease after some oscillations.

    Later clock systems have a different algorithm where the fault bit cannot be cleared until a certain number of oscillatons has happened in a row (and the oscillation can be considered stable)

  • DCO stabilizes almost immediately after being switched on. It is no (mechanical) crystal but a (digitally controlled) R/C oscillator. Typical stabilization time is <6µs. On some MSP series <1µs (a guess, based on the LPM1 wakeup time since LMP1 disables DCO). And this happens as soon as the hardware is initialized  (this means while RST is still low)

    This is, however, for reaching the frequency that is currently programmed.
    With FLL stabilization, this means that the DCO is constantly reprogrammed in relation to the reference, to get an average frequency that matches the desired result. This stabilization process goes one reprogramming step each clock tick of the reference clock. So the DCO reaches the desired average frequency worst case when all possible adjustment steps of DCO and modulation have been stepped through (depends on MSP series). However, the highest or lowest DCO setting does not mean that the desired frequency has been reached, but rather that the FLL has reached the adjustment limit and maybe a change of the RSEL (the base frequency resistor selection) is required. This then causes a DCO oscillator fault condition. (here it is not a 'fault' = malfunction of DCO, as it is still working, just that the FLL was unable to program the DCO to the desired frequency with the current RSEL setting).

    Soo how many different steps are possible with modulation and DCO and ou know how many reference ticks ar eneeded before the DCO has reached the 'correct' frequency range. And this is after the reference (e.g. the watch crystal) has been stabilized, since before, the 'reference' may be 0Hz and therefore the FLL tries to adjust the DCO towards n*0Hz = 0Hz)

**Attention** This is a public forum