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.

RTOS/MSP432P401R: Strange behaviour of SimpleLink Timer driver

Part Number: MSP432P401R
Other Parts Discussed in Thread: SYSBIOS

Tool/software: TI-RTOS

G'Day all,

This question is with respect to the attached project.

Its a relatively simple project.  The guts of it is a RTOS/Simplelink Timer running with a clock of 1MHz, toggling pin 3.2 every 1.666mSec.

If you load this code into your MSP432 launchpad, connect a scope to pin 3.2 and watch you will see something odd. 

Most of the time the pin toggles every 1.666mSec or near enough just as you would expect, but after about 20sec (and every 5sec thereafter) pin 3.2 goes crazy and toggles like mad for about 1.6mSec.

If I break point in testTimer_HWI when everything is working normally, the TAR and TACCR0 registers increment as I expect.  For example:

TAR TACCR0
13109 14760
14776 16426
16441 18092
18107 19758

This makes sense.  We are moving on in steps of 1666 counts (1.666mSec on a 1MHz timer).  But if I break point when pin3.2 is rapidly toggling I get something more like this

TAR TACCR0
36 3322
98 6654
159 9986
220 13318
282 16650
343 19982
404 23314

This pattern continues until TACCR0 roles over back to 0, then normal operation resumes.  This makes no sense!  TACCR0 is incrementing twice as far as it should (3332 instead of 1666) and TAR seems to be moving forward in steps of about 61 instead of 1666.

During this time I also notice in ROV -> Timer(ti.sysbios.family.arm.msp432) -> Device -> Timer_A1 that the "currCount" is negative...

Do you have a suggestion what might be going on here??  You help on this is much appreciated!

Cheers

Julian

/// EDIT - Replaced original project with a simplified one that still exhibits the same problem

TestRTOSTimer.zip

  • Hi Julian,

    Let us take a look at your code and we'll get back to you.

    Thanks,

    David
  • G'Day David,

    I appreciate you taking the time too look.
    I've updated the project attached above to be a bit simpler (and to support lower SMCLK rates) .

    I've been poking around the edges of this a little and observed that this problem gets worse with lower MCLK/SMCLK (more specifically lower initialPerfLevel in the power configuration). It also seems that there are some timer periods where this rapid toggling does not occur. All the "good periods" I've found are multiples of 400.

    initPerfLevel = 0 (MCLK = 12MHz, SMCLK = 3MHz), No fast toggling for period of 1600
    initPerfLevel = 1 (MCLK = 24MHz, SMCLK = 6MHz), No fast toggling for period of 800, 1600, 2400
    initPerfLevel = 2 (MCLK = 48MHz, SMCLK = 12MHz), No fast toggling for period of 400, 800, 1200, 1600, 2400, 2800
    initPerfLevel = 3 (MCLK = 48MHz, SMCLK = 24MHz), No fast toggling for period of 400, 800, 1200, 1600, 2400, 2800

    Cheers
    Julian
  • Hi Julian,

    I was able to reproduce this behavior.

    I'm looping the TI-RTOS experts so they can comment on this. My guess that this has to do on how the timer was created using "Timer_create" and the Hwi.

    In the meantime, could you please run this example code: timerled example with these modifications:

    1. In timerled.c

    void *mainThread(void *arg0)
    {
        /* Period and duty in microseconds */
        Timer_Handle timer0;
        Timer_Params params;
    
        /* Call driver init functions */
        GPIO_init();
        Timer_init();
    
        /* Turn off user LED */
        GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
    
        /* Setting up the timer in continuous callback mode that calls the callback
         * function every 1,000,000 microseconds, or 1 second.
         */
        Timer_Params_init(&params);
    //    params.period = 1000000;
        params.period = 166;
        params.periodUnits = Timer_PERIOD_US;
        params.timerMode = Timer_CONTINUOUS_CALLBACK;
        params.timerCallback = timerCallback;
    
        timer0 = Timer_open(/*Board_TIMER0*/Board_TIMER2, &params);
    
        if (timer0 == NULL) {
            /* Failed to initialized timer */
            while (1);
        }
    
        if (Timer_start(timer0) == Timer_STATUS_ERROR) {
            /* Failed to start timer */
            while (1);
        }
    
        while(1)
        {
            sleep(2);
        }
    }

    2. In MSP_EXP432P401R.c

    const TimerMSP432_HWAttrs timerMSP432HWAttrs[MSP_EXP432P401R_TIMERCOUNT] = {
        /* Timer32_0 */
        {
            .timerBaseAddress = TIMER32_0_BASE,
            .clockSource = TIMER_A_CLOCKSOURCE_SMCLK,
            .intNum = INT_T32_INT1,
            .intPriority = ~0
        },
        {
            .timerBaseAddress = TIMER32_1_BASE,
            .clockSource = TIMER_A_CLOCKSOURCE_SMCLK,
            .intNum = INT_T32_INT2,
            .intPriority = ~0
        },
        /* Timer_A1 */
        {
            .timerBaseAddress = TIMER_A1_BASE,
            .clockSource = /*TIMER_A_CLOCKSOURCE_ACLK*/TIMER_A_CLOCKSOURCE_SMCLK,
            .intNum = INT_TA1_0,
            .intPriority = ~0
        },
        /* Timer_A2 */
        {
            .timerBaseAddress = TIMER_A2_BASE,
            .clockSource = TIMER_A_CLOCKSOURCE_ACLK,
            .intNum = INT_TA2_0,
            .intPriority = ~0
        },
        /* Timer_A3 */
        {
            .timerBaseAddress = TIMER_A3_BASE,
            .clockSource = TIMER_A_CLOCKSOURCE_ACLK,
            .intNum = INT_TA3_0,
            .intPriority = ~0
        }
    };

    With that code I was not able to reproduce this behavior, but maybe you will have different results.

     Best regards,

      David 

  • G'Day David,

    I've tried your example and it works correctly for me too - no rapid toggling.

    It would appear your example is using the SimpleLink driver while my approach seems to dig directly into the TI-RTOS timer driver.
    (I notice that both drivers have a function called Timer_Params_init(), but they work with different structs )

    Your example does give me a way forward but if you don't mind, I'd like to wait and hear if the TI-RTOS experts have any advice to fix the code I already have.

    Cheers
    Julian
  • G'Day David,

    I think I've found the problem.

    Refer to [SIMPLELINK1.4]\kernel\tirtos\packages\ti\sysbios\family\arm\msp432\Timer.c, function Timer_setNextTick().

    The particlar problem is in the calculation of "next" (line 182). Next is declared as UInt (32bits), but its dealing with 16 bit register values from the Timer_A1.

    "next" is calculated as the previous CCR0 value + the timer period. This is fine for writing back to the CCR register (line 185) because writing a 32bit value to the 16bit register will lop off the upper 16 bits giving the modulo operation that you need when "next" exceeds 65535.

    But, using "next" to determine which "region" (see the comments starting at line 188) is broken because "next" will not roll over in the same way that the "now" variable (read directly from the TAR register) does. So when we get to the roll over, the region is determined incorrectly and Timer_setNextTick() starts firing the timer interrupt thinking that its late in setting the time for the next tick. It keeps firing the interrupt like this until the issues flushes through.

    Here is an example where the time is setup to have a period of 400 ticks (=400uSec because timer is set to 1MHz)
    (prevoius, now and next are variables in Timer_setNextTick().

    previous now next
    65120 65143 65520
    This is fine! 65520 - 65120 = 400. "now" is in "region A" and everything works correctly.

    previous now next
    65520 7 65920
    65920 - 65520 = 400, but 65920 is more than 16 bits!.
    The logic in this function now incorrectly assumes "now" is in region C, which leads to a timer interrupt being forced.
    But if "next" had been 16its correctly rolled over to 384 it would have been region "E" which would not force an interrupt.

    previous now next
    384 57 784
    "previous" has correctly rolled over. "now" has only moved on 50 instead of 400 because of the forced interrupt in the previous step. "next" - "previous" is 400 as expected. Once again, "now" is in region C and a timer interrupt is forced.

    I think the fix here is to make all the UInt variables in this function uint16_t. I'll try recompiling the RTOS with this change in place and see if the problem is resolved.


    Cheers
    Julian
  • G'Day David,

    I've tested a solution that works for me.

    1. Change the variable declarations in Timer_setNextTick() to

    uint16_t newPeriod = (uint16_t)(obj->period) * (uint16_t)ticks;
    uint16_t next;
    uint16_t previous;
    uint16_t now;

    2. Recompile TI-RTOS starting from [SIMPLELINK1.4]kernel\tirtos


    Cheers
    Julian

**Attention** This is a public forum