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 not consistent - MSP430F5310

Other Parts Discussed in Thread: SYSBIOS

I am setting a port line in my highest priority task, calling Task_sleep(3), and then setting the port line low.  I get a mix of ~3ms pulses and 2 second pulses. There is a timer interrupt that is flashing an LED every 200ms, and another task performing I/O periodically using a semaphore from the timer.  Both of these are rock solid.  What can be effecting the Task_sleep timing?

  • Can you share your .c and .cfg files?

    Alan

  • Here are the *.cfg file and *.c files.  Have to hit a graduation now. So I'm off-line until tomorrow. 

    var Defaults = xdc.useModule('xdc.runtime.Defaults');
    var Diags = xdc.useModule('xdc.runtime.Diags');
    var Error = xdc.useModule('xdc.runtime.Error');
    var Log = xdc.useModule('xdc.runtime.Log');
    var LoggerBuf = xdc.useModule('xdc.runtime.LoggerBuf');
    var Main = xdc.useModule('xdc.runtime.Main');
    var Memory = xdc.useModule('xdc.runtime.Memory')
    var SysMin = xdc.useModule('xdc.runtime.SysMin');
    var System = xdc.useModule('xdc.runtime.System');
    var Text = xdc.useModule('xdc.runtime.Text');
    var BIOS = xdc.useModule('ti.sysbios.BIOS');
    var Task = xdc.useModule('ti.sysbios.knl.Task');
    var Timer = xdc.useModule('ti.sysbios.family.msp430.Timer');
    var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');
    var ti_sysbios_BIOS = xdc.useModule('ti.sysbios.BIOS');
    var Swi = xdc.useModule('ti.sysbios.knl.Swi');
    var ti_sysbios_hal_Timer = xdc.useModule('ti.sysbios.hal.Timer');
    var Clock = xdc.useModule('ti.sysbios.knl.Clock');
    Text.isLoaded = false;
    Defaults.common$.namedModule = false;
    BIOS.libType = BIOS.LibType_Custom;
    BIOS.logsEnabled = false;
    BIOS.clockEnabled = true;
    BIOS.swiEnabled = true;
    BIOS.heapSize = 0;
    BIOS.runtimeCreatesEnabled = true;
    BIOS.cpuFreq.lo = 25000000;
    BIOS.assertsEnabled = false;
    Program.stack = 0x200;
    Task.idleTaskStackSize = 200;
    Task.defaultStackSize = 200;
    var task0Params = new Task.Params();
    task0Params.instance.name = "host";
    task0Params.stackSize = 250;
    Program.global.host = Task.create("&UpdateOledTask", task0Params);
    var task1Params = new Task.Params();
    task1Params.instance.name = "UpdateADC";
    task1Params.stackSize = 250;
    task1Params.priority = 2;
    Program.global.UpdateADC = Task.create("&updateADCTask", task1Params);
    var timer0Params = new Timer.Params();
    timer0Params.instance.name = "timer1";
    timer0Params.period = 200000;
    Program.global.timer1 = Timer.create(1, "&myRealTickFxn", timer0Params);
    var mySemParams = new Semaphore.Params();
    mySemParams.instance.name = "mySem";
    Program.global.mySem = Semaphore.create(null, mySemParams);
    var mySem2Params = new Semaphore.Params();
    mySem2Params.instance.name = "mySem2";
    Program.global.mySem2 = Semaphore.create(null, mySem2Params);
    var thermsemParams = new Semaphore.Params();
    thermsemParams.instance.name = "thermsem";
    Program.global.thermsem = Semaphore.create(null, thermsemParams);
    var ThermtaskParams = new Task.Params();
    ThermtaskParams.instance.name = "Thermtask";
    ThermtaskParams.priority = 3;
    ThermtaskParams.stackSize = 300;
    Program.global.Thermtask = Task.create("&monitorThermTask", ThermtaskParams);
    var rfidsemParams = new Semaphore.Params();
    rfidsemParams.instance.name = "rfidsem";
    Program.global.rfidsem = Semaphore.create(null, rfidsemParams);
    var monitorRFIDParams = new Task.Params();
    monitorRFIDParams.instance.name = "monitorRFIDt";
    monitorRFIDParams.stackSize = 300;
    monitorRFIDParams.priority = 4;
    Program.global.monitorRFIDt = Task.create("&monitorRFIDTask", monitorRFIDParams);
    Clock.timerId = 2;

    ==================================================================================

    void main()
    {
        /*
         * Uncomment this next line to initialize the port direction for the LED.
         */
        hw_init();
        led_toggle = 0;
        /*
         * Print "Hello world" to a log buffer.
         */
        Log0();

        /*
         * Start BIOS.
         * Begins task scheduling.
         */

    //    while(1)
    //        ;
        myBIOS_start();
    }

    /*
     *  ======== myTickFxn ========
     *  Timer ISR function that posts a Swi to peform
     *  the non-realtime service functions.
     */
    void myRealTickFxn()
    {

        //this ticks every 200ms
        if (led_toggle ==1)
            turn_on_test_io();
        else
            turn_off_test_io();

        led_toggle ^= 1;

        tickCount += 1;      /* increment the counter */

        /* every 10 timer interrupts post the semaphore */
        if ((tickCount % 10) == 0) {
            myPostSem();
        }

        if ((tickCount % 20) == 0) {
            postRFIDSem();
        }

        if ((tickCount % 4) == 0) {
            myPostSem2();
        }
        postTherm();
    }


    /*
     *  ======== myTaskFxn ========
     *  Task function that pends on a semaphore until 10 ticks have
     *  expired.
     */
    void UpdateOledTask()
    {
        ConfigOLED();            //Get the OLED ready to show data

        /*
         * Do this forever
         */
        while (1) {
            /*
             * Pend on "mySemaphore" until the timer ISR says
             * its time to do something.
             */
            myPendSem();
            tickCount2++;
            msgdex++;
            if (msgdex >= MSGMAX)
                msgdex = 0;
            outputMessage();


            OLED_PrintfSetColumnRow(1,1,LARGE_FONT);

            OLED_Printf("%d", Tambient);

            /*
             * Print the current value of tickCount to a log buffer.
             */
    //        Log1(tickCount);
        }
    }

    //Reads the ADC, and set the global variable to be output by the OLED task
    void updateADCTask()
    {
        for (;;)
        {
            adjustPWM();
            myPendSem2();
        }
    }

    void monitorThermTask()
    {
        configThermopile();

        for(;;)
        {
            pendTherm();
            Vobject = readThermopile(0);            //address 0 is Vobject
            Tambient = readThermopile(1);            //address 1 is Tambient
        }
    }

    void monitorRFIDTask()
    {
        monitorRFID();
    }

    void monitorRFID()
    {
        int x;

        for (;;)
        {
            pendRFIDSem();
            RFIDENPORT |= RFIDENBIT;

    //        for (x = 0; x < 5000; x++)
    //            ;

            //Delay 1-2 ms
            OSTask_Sleep(3);

    //        Trf796xInitialSettings();

            //time to read the RFID
            RFIDENPORT &= ~RFIDENBIT;
        }
    }

  • Your Task_sleep() call is AFTER you come back from pending on a semaphore:

        for (;;)
        {
            pendRFIDSem();


            RFIDENPORT |= RFIDENBIT;

            OSTask_Sleep(3);

            RFIDENPORT &= ~RFIDENBIT;
        }

    The semaphore appears to get posted every 20 ticks of your timer ISR

        if ((tickCount % 20) == 0) {
            postRFIDSem();
        }

    The timer was configured with a period of 200Ms.

    So the semaphore should only get posted every 4 seconds if I calculate correctly.

    Alan

  • Yes.  You calculate correctly.  I posted this rather hastily yesterday.  The design that I'm trying to implement is timer0 is solely used for PWM output.  Timer1 generates periodic interrupts in which semaphores are posted.  Timer2 is the system tick timer, and is used to implement sleep calls.  This has morphed to this point because I couldn't get the system tick and sleep to behave.  Code space was the last issue.  I originally wanted to use only the sleep calls, but couldn't get them to work so I went with the periodic interrupt.  Now, if I can get the sleep calls to work, I will set my pseudo periodicity using sleep calls, and get rid of the complication of the periodic interrupt.  So this jump from ~3 ms to 2 seconds has me holding off on that plan of action.

  • I am still not understanding why you suspect Task_sleep(). The code you provided seems to be behaving properly in regards to Task_sleep().

    Alan

  • I have done a poor job of explaining what I am seeing.  What I would expect to see is that the RFID task wakes up every 4 seconds, and outputs a 2-3 ms pulse on the scope through the port line that I am using.  So I should see a stream of 2-3ms pulses with a 4 second period.  What I actually see is a mix of 2-3 ms pulses and 2 second pulses with a consistent 4 second period.  I'm suspecting sleep because it is the call that is setting the width of the pulse.  The 4 second period is consistent.  I hope this explains it.  Can I use these timers in the way that I am with SYS/BIOS?  Timer ID 0 = PWM. Timer ID 1 = interrupt generation, and Timer ID 2 = system tick.

    The Blue is what I expect.  The red is what I'm seeing.  (the small pulses are expanded)

  • I get it now, thanks!

    You may be running into a side effect associated with the clock tick suppression mechanism we use by default.

    It is described here:

         http://processors.wiki.ti.com/index.php/SYS/BIOS_for_the_MSP430#Clock_Tick_Suppression

    A 2 second anomaly can occur if interrupts are disabled by an application for too long, causing the clock rollover interrupt to be serviced too late (as described in the "Important Notes..." section of the above app note.

    You can test this hypothesis by disabling clock tick suppression in your config file:

        var Clock = xdc.useModule('ti.sysbios.knl.Clock');
        Clock.tickMode = Clock.TickMode_PERIODIC;

    Alan

  • This looks right.  I'm going to try setting the timer2 to PERIODIC, and removing the timer1 periodic semaphore posting.

  • Thank you.  I'm now running timer 0 as PWM, and timer 2 as the system tick.  Sleep is accurate.  I had to deal with a CCS5 crash in between, but E2E came to the rescue again.