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.

Clock independent sleep time - SMCLK div /8 troubles

Hello TI community,

some less important text

I have switched from the MSP430 F series to the G series when doing things for personal use (cheaper and i can use the launchpad as a programmer - plus the F series is mostly overkill).


I'm starting off by programming some basic functionalities to make my future life with the G series easier.

what i try to do

Im trying to program a sleep function that puts the device to sleep for a defined time (either n seconds or n / 10 milliseconds), independent of the selected clock source and speed.

current status

I have written two functions:

  • Initilization function with clock source (TACLK, ACLK ...) and clock speed as parameters (will be oboslete later as im looking to calculate this automated in future - if not external clock).
  • sleep function with sleep time and unit (either s or 10th ms): the function calculates how many timer clocks are necessary to create a delay of the given time, calculates the number of necessary timer overflows and the number of cycles for the final timer run. Puts the device to LPM0 and wakes it after the calculated number of overflows and final run are done.

what is achieved

I ran tests with the timer set to 5 seconds and 50,000 1/10 ms, so 5 seconds in both cases. After each run, an LED is toggled.

I measured how long it takes to have the LED toggle five times and got good results (~ 25 seconds) using SMCLK. I tested 8MHz and 1MHz for the DCO and tried all SMCLK clock dividers for both. I also tested 12MHz with SMCLK dividers of 1 and 8.

the problem

There is one exception that does not lead to good results: Setting the SMCLK divider to 8 resulted in a total time of 36 seconds (1 MHz), 28 seconds (8MHz) and 27 seconds (12MHz) instead of 25 seconds. Any other SMCLK divider works well and leads to a result of 25±0,3 seconds (manually triggered stopwatch).

I would guess that my code works fine, as it works for all other dividers and for 1,8,12 MHz. I input the SMCLK frequency manually into the function, so a huge amount of values is covered by going from Div4 on 1MHz to Div0 at 12MHz. The SMCLK divider is not used in any calculation.

I do not understand why the system behaves differently as soon as the divider is set to 8 and would appreciate any hints and tips.


Thank you for your time and help,

Lars Heinrichs

  • Are you using a 32k crystal?
    Are you sure the calibration data in infoA is still there?

    I like to use 32k aclk with div8 and then ta1/4 so one tick is ~1milliSec and max is 64sec

    As I don't change clocks on the fly I declare it as a compiler-constant

    TA1second EQU 1024 /* Aclk = 32768/8 then timerA1 is further div by 4 */

    In the code I use 1/4 or 1/20 of a second (rounded down) or *10 etc

    add.w #TA1second/4,&TA1CCR1 ; add 1/4 second delay long beeps

    ...
     add.w #TA1second*9/10,&TA1CCR0 ; add another 900ms as this takes time

  • thanks for your reply.

    Tony Philipsson said:
    Are you using a 32k crystal?

    No, Im using the DCO to generate SMCLK to generate the timer clock.

    Tony Philipsson said:
    Are you sure the calibration data in infoA is still there?

    hm what do you mean by that?

    Tony Philipsson said:
    I like to use 32k aclk with div8 and then ta1/4 so one tick is ~1milliSec and max is 64sec

    with my setup i could theoretically cover down to maybe a millisecond (depends on clock frequency and necessary calculation times) up to like 72 hours. I used the 32k aclk crystal when i programmed for the F-Series, but iirc the the G-series needs it to be added externally. It is possible to select any source, but i tested with SMCLK.

    Tony Philipsson said:
    add.w #TA1second/4,&TA1CCR1 ; add 1/4 second delay long beeps

    Im writing in C =)

  • Use your compiler to view memory at Info,
    if the last 8 bytes are 0xff your calibration data got erased (by mistake) and trying do any long term wait it could be off by ±5%


    Even if there your wait could be off by  ±1.5%, as internal DCO is not powered by a crystal but at Resistor-Capacitor Oscillator (this type are not accurate)

    Create a software RTC for the minute and hour waits and use the 1ms to 64sec pauses as I mention above is I good way to do it.

    Though it's not impossible to create a Universal pause system that you have in mind, just have to make sure you have the math right.
    Recommend to base variables on 32bit fixed point (not necessary 16b.16b as maybe 8b.24b could be better) to simplify overflow and precision
    and also use Bresenham's Algorithm: http://www.romanblack.com/one_sec.htm

  • Lars Heinrichs said:
    I would guess that my code works fine, as it works for all other dividers and for 1,8,12 MHz.

    This is a common assumption and often proved wrong.

    There are three types of bugs:
    1) a general mistake. The code is always not working. This is the type of bug easiest to detect.
    2) intermittent bugs. The code sometimes behaves wrong, but it is not repeatable. This kind of bug is very difficult to track and is usually caused by false assumptions about external circumstances that are sometimes no as expected but not considered as function parameters.
    3) repeatable bugs (like yours). The code usually does what it does, but with certain parameters it does not. A typical cause is a problem with physical limitations. Like an overflow in a variable during calculation, that only happens for certain parameters. When tested with a calculator, the code seems to be correct and should give the correct result, but due to a limited variable type used, the values are clamped during calculation. It requires careful stepping through the code and considering variable types during every step of an expression.

    example:
    x*y/z and x/z*y should be equivalent. But they aren't. While in the first, x*y may cause an overflow before the division (even though the 'correct' result would be within the allowed range after the division), x/z will cause a truncation of the decimals of the result, giving an unexpected result.
    E.g. 5/3*3 should be 5 but gives 3 when using integers. Note that constants are resolved by the compiler directly. So if x and z are constants, even if y is a float, the result will be 3.

    Replace all variables by float type vars and all constants by float constants (add a .0 prefix) and check again. If it works, then you have a problem with your variable type ranges and should check your formula.
    It's still possible that the final truncation (all MSP registers only take integers) may accumulate to a significant error.

    Not knowing your code, it is difficult to analyze. However, on 1MHz, with a divider of 8, you have 12.5 SMLCK cycles per 1/10ms. Which introduces an error of 4% (much more if using a divider >4). Well, you see almost 30%. Which would happen if you use a /8 divider in the timer. And using the calculated number of ticks for the timer period in CCR0 (ccr0 needs to be set to x-1, as 0 is a counting step too)

**Attention** This is a public forum