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.

Task_sleep in SYS/BIOS 6.32 for MSP430

Other Parts Discussed in Thread: MSP430F5418A, SYSBIOS

I'm having problem to get Task_sleep to work correctly.

Attached is a project based on the MSP430 SYS/BIOS task example. Here are some changes I made to the project: 

- changed myTimer to tick at 10ms instead of 0.5 second. 

- added clock module, enabled SWI, use timer B for sys/bios clock. The sys/bios clock ticks at 1000us.  

- toggle P1.0 in myTaskFxn.

- added Task_sleep(1) in myTaskFxn. I meant to let the task sleep for 1ms since the sys/bios tick at 1000us.

If I commented out Task_sleep(1), I got 5 Hz 50% duty cycle square wave at P1.0. If I added Task_sleep(1), the timing is all wrong when measured at P1.0.

Could you please take a look at the project and let me know what else I need to do to make Task_sleep work? Thank you very much for your help.

Chun 

1261.taskExmpl.zip

  • Hi Chun,

    Which version of BIOS are you using?

    Can you try un-winding your changes (e.g. timerParams.period = 10000 and Clock.timerId = 2;).  Basically, go back to the original working example, and then add the Task_sleep() to that?

    Doe it work properly with the original timer settings?

    Thanks,

    Steve

  • If I change the timerParams.period to 500000us and sys/bios clock ID to ANY, myTaskFxn will be called every 5 seconds. But Task_sleep(1) sleeps anywhere from 7 ms to 4 s instead of 1ms.

    If I change sys/bios clock ID to ANY, sys/bios will use Timer A1.0 for its clock. The attached file shows the settings of Timer A1.0 I see in ROV and register views. I also see that sys/bios automatically created Hwi_49 for the timer A1.0. It feels like that timer A1.0 is not set up correctly by the sys/bios. Where in the project can I find the source code generated by SYS/BIOS for the Timer A1.0? Thanks.

    Chun

     

    4075.taskROV.doc

  • I am using SYS/BIOS 6.32 and CCS 4.2

    Chun

  • If I manually initialize Timer B0.0 and call Clock_tick() in Timer B0.0 interrupt, Task_sleep works correctly. Attached is the working project. I am still not sure why sys/bios was not able to set up its clock correctly though. By the way, my processor is MSP430F5418A. Chun
    taskExmpl_a.zip
  • Can you go back to the original working example, and then add the Task_sleep() to that?

    Doe it work properly with the original timer settings?

    Thanks,

    Steve

  • Chun,

    I was typing a reply and I see Steve just replied too.   I was thinking along similar lines, going back to the original example and trying Task_sleep() there, after enabling Clock, but without specifying additional Clock configuration parameters (other than the tick period). 

    As you noticed, Clock will automatically configure the appropriate Hwi for the physical timer it will use (like Hwi #49 for TimerA1).  It will also use other defaults to generate the expected period.  I’m thinking that maybe the extra statements in your configuration file may explain what you are seeing.  But I don’t see how you’d get a varying range like you describe. 

    I don’t have access to a board today, but I can try to recreate what you are seeing once I’m in the office tomorrow…

    Regards,
    Scott

  • I tried to add Task_sleep to a clean task example, the timing was not right either. Thanks.

    Chun

  • Chun,

    I modified the MSP430 Task example to use Clock, and to do Task_sleep(), and don’t see any issue.  This is what I did...

    I enabled Clock in the .cfg file:

    BIOS.clockEnabled = true;

    And then commented out the requirement for STATIC_POLICY (because Task_sleep() is going to be called, and it creates a Clock object for the timeout):

    // Defaults.common$.memoryPolicy = xdc.module("xdc.runtime.Types").STATIC_POLICY;

    To the .c file I uncommented the port initialization in main() for writing to the LED:

        P1DIR |= 0x1;

    And then added this at the top of myTaskFxn():

        while (TRUE) {
            P1OUT ^= 0x1;
           
            Task_sleep(500);
        }   

    When I run this I see the LED on the experimenter board toggling every 1/2 second as expected.  Just like the original behavior when the LED is toggled based upon a separate Timer.

    Can you post the .c and .cfg files for your simplified app where you aren’t seeing expected timing?

    Also, maybe try the above steps to see if this works for you?

    Thanks,
    Scott

  • Scott,

    I tried your way, it works correctly.

    But if I put  Task_sleep after Semaphore_pend, then it will not work. For example if I do

    // myTickFxn is called every 500ms

     

     

     

     

    Void myTickFxn(UArg arg)

    {

     

     

          Semaphore_post(mySem);

    }

     

     

     

     

     

     

     

     

     

    Void myTaskFxn(Void)

    {

     

    while (TRUE)

    {

    Semaphore_pend(mySem, BIOS_WAIT_FOREVER);

    P1OUT |= BIT0;

    Task_sleep(100);  // task sleep 100ms

    P1OUT &= ~BIT0;

     

    }

    }

     

     

     

     

    With that, I would expect 2 Hz square wave with 20% positive duty cycle at P1.0. But that is not the case. Why is Task_sleep not working correclty after Semaphore_pend? Thanks.

    Chun

     

     

  • Chun,

    OK, good.

    I think the reason you’re seeing variability is because the timer that is triggering myTickFxn() and the separate timer used by Clock are not synchronized to each another.  Depending upon the relative phase of the timers, and when the CPU calls Semaphore_pend(), the function may return immediately because the semaphore has already been posted by myTickFxn(), or it may have to wait for the timer to expire and post the semaphore.  And depending upon when Task_sleep() is called, the first tick may happen immediately, or it may take up to one Clock tick period before the first tick of the timeout occurs. 

    I think you will get better results if you use a single timer to generate the pulse train.  Either Clock, using alternating delays in the Task_sleep() calls, or the dedicated timer, posting the semaphore in a 1/5 tick count ratio.  I think you’ll see the best results if you create a Clock object that runs periodically every 100msec.  In your function that gets called every 100msec, do the 1/5 ratio counting and toggling of the port bit there.  On MSP430 the Clock module leverages the “compare” mode of the timers, allowing the timer to continuously count upwards, without phase skew that would occur if the timer was stopped/reprogrammed/restarted on every expiration.  So I think you should see a very stable pulse train with this approach.

    Does this make sense?

    Thanks,
    Scott

  • Scott,

    I am not trying to generate a pulse train. In my application, I have to check if a button is pressed down for 3 seconds. When the button is pressed, a falling edge interrupt is generated, which will post a semaphore. A task is pending on the semaphore. Once the semaphore is posted by a hwi, the task will check the input pin that is connected to the button to see if it stays low for 3 seconds. I do not want to continuously poll the pin in the task so I put the task to sleep and only check the pin every 0.5 second.  Below is the code to do that

    void hwi_port1(void)

    {

    if(P1IFG & BIT6)

    Semaphore_post(semButton);

    }

    void taskButton(void)

    {

    uint8_t i;

    do

    {

    Semaphore_pend(semButton, BIOS_WAIT_FOREVER);

    for(i=0; i<6; i++)

    {

    if(P1IN & BIT6)

    break;

    Task_sleep(500);   // task sleep 500ms

    }

    ...

    }while(true)

    }

    If I let sys/bios configure its clock, the code will not work correctly. But if I maunually configure Timer B to call Clock_tick every 1ms in its interrupt, it works.  I posted the manually configured Timer B code in a previous post. I do not like to have a hwi interrupt for timer B every 1 ms because that means the MCU is not in low power mode that much. If you know a better way to do this, please let me know. Thanks.

    Chun

  • Chun,

    I’d suggest using a Timer to do the periodic polling of the button to see if it continues to be pressed for 3 seconds.  And do all of the checking of the button state within ISRs, and only post the Semaphore to “ready” the task once it is determined that the button has been pressed long enough.  This will be lower overhead because it avoids multiple task activations, and the CPU can resume a low power mode after the brief ISRs, until it is time to actually run the task. 

    In the button ISR: you could set a flag that the initial press is received, and then start a statically configured Timer (with StartMode_USER) to run for 500msec.  If the button is not fully debounced in hardware, then you could disable further button interrupts until the Timer expires after half a second.

    In the Timer function: you could check the port bit to see if the button is still pressed.  If it isn’t, then clear the flag that says a button is being polled, re-enable the button interrupt if it was previously disabled, and return.  If the button is still pressed, then call Timer_start to start the 500msec timer again, maybe re-enable the button interrupt, and then return.  Continue this check-and-restart-the-timer process in the Timer function (which runs in ISR context)until the 3 seconds of press has been verified, and then post the Semaphore to run the task.

    You can add something like this to your configuration script that will cause the CPU to enter low power mode while waiting for button or Timer interrupts:

    var Power = xdc.useModule('ti.sysbios.family.msp430.Power');
    Power.idle = true;
    Power.idleMode = Power.LPM3;

    I think there are multiple ways you could do this, including using Clock, but I think this should be pretty clean, and efficient.

    Regards,
    Scott

  • Scott,

    That's a good idea. Thanks.

    Chun