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.

Using idle loop together with tasks

Other Parts Discussed in Thread: MSP430F5529, SYSBIOS

Hi to all,

using a self built microcontroller board with MSP430F5529, I created a system based on the SYS/BIOS MSP430 task example and expanded it to use different harware and timer interrupts and all is working well. Now I want to use the idle time of the system to do some "housekeeping" jobs in the background, when the system is not active on interrupts or tasks.  Trying to add these by use of the XGCONF tool I was not able to get any idle function running. So I went back to the basic  SYS/BIOS MSP430 task example and tried to add it to that easy and small example and I am not able to get any idle function beeing called from the bios.

I am using MSP430 BIOS 6.33.5.46 and CCS 5.2

Here are the steps I did:

1: create new CSS project example from SYS/BIOS-MSP430Exanmples -- Task example.

2: with CGCONF under "System Overview": "Add the Idle function managment module to my configuration". under Advanced: added myIdleFxn

3: under "Runtime"->"Runtime Memory Option" enterd 32 to heap size ( if not: error message when startin the bios)

 

4: under "BIOS" activated the clock module (because I want tu use Task_sleep() instead of Semaphore_pend() in myTaskFxn.

5: under "Synchronisation" -> "Semaphore" switched it off, because don't need it anymore.

6: modified task.c: added myIdleFxn() as from the idle.c example,

     added isrFlag=True; to myTickFxn,

    added volatile Bool isrFlag=False;

   added Task_sleep(5000); to myTaskFxn instead of using Semaphore_pend()

   commented out all semaphore parts

after compiling and starting the debug,the Raw Logs show after a while:

0,1,,Main,""../task.c", line 64: Hello world",xdc.runtime.LoggerBuf.Instance#0
2,2,,Main,""../task.c", line 116: Task: Tick Count = 0",xdc.runtime.LoggerBuf.Instance#0
"160,169",3,,Main,""../task.c", line 116: Task: Tick Count = 9",xdc.runtime.LoggerBuf.Instance#0
"320,330",4,,Main,""../task.c", line 116: Task: Tick Count = 19",xdc.runtime.LoggerBuf.Instance#0

The Idle function "myIdleFxn" is never been called..

Has anybody any idea what I missed to do?

Here is task.c:

#include <msp430.h>

#include <xdc/std.h>
#include <xdc/runtime/Log.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Semaphore.h>

/* Semaphore handle defined in task.cfg */
//extern const Semaphore_Handle mySem;

/* Counter incremented by timer interrupt */
volatile UInt tickCount = 0;

/* Flag used by idle function to check if interrupt occurred */
volatile Bool isrFlag = FALSE;


/*
 *  ======== main ========
 */
Void main()
{
    /*
     * Uncomment this next line to initialize the port direction for the LED.
     */
    /* P1DIR |= 0x1; */

    /*
     * Print "Hello world" to a log buffer.
     */
    Log_info0("Hello world\n");

    /*
     * Start BIOS.
     * Begins task scheduling.
     */
    BIOS_start();        /* does not return */
}

/*
 *  ======== myTickFxn ========
 *  Timer ISR function that posts a Swi to peform
 *  the non-realtime service functions.
 */
Void myTickFxn(UArg arg)
{
    /*
     * Uncomment this next line to toggle the LED state.
     */
    /* P1OUT ^= 0x1; */


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

    isrFlag = TRUE;      /* tell background that new data is available */

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

/*
 *  ======== myTaskFxn ========
 *  Task function that pends on a semaphore until 10 ticks have
 *  expired.
 */
Void myTaskFxn(Void)
{
    /*
     * Do this forever
     */
    while (TRUE) {
        /*
         * Pend on "mySemaphore" until the timer ISR says
         * its time to do something.
         */
//        Semaphore_pend(mySem, BIOS_WAIT_FOREVER);

        /*
         * Print the current value of tickCount to a log buffer.
         */
        Log_info1("Task: Tick Count = %d\n", tickCount);

        Task_sleep(5000);
    }
}


/*
 *  ======== myIdleFxn ========
 *  Background idle function that is called repeatedly
 *  from within BIOS_start() thread.
 */
Void myIdleFxn(Void)
{
    if (isrFlag == TRUE) {
        isrFlag = FALSE;
        /*
         * Print the current value of tickCount to a log buffer.
         */
        Log_info1("Idle: Tick Count = %d\n", tickCount);
    }
}

and here is task.cfg:

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 Hwi = xdc.useModule('ti.sysbios.family.msp430.Hwi');
var Idle = xdc.useModule('ti.sysbios.knl.Idle');

/*
 * Program.argSize sets the size of the .args section.
 * The examples don't use command line args so argSize is set to 0.
 */
Program.argSize = 0x0;

/*
 * Uncomment this line to globally disable Asserts.
 * All modules inherit the default from the 'Defaults' module.  You
 * can override these defaults on a per-module basis using Module.common$.
 * Disabling Asserts will save code space and improve runtime performance.
Defaults.common$.diags_ASSERT = Diags.ALWAYS_OFF;
 */

/*
 * Uncomment this line to keep module names from being loaded on the target.
 * The module name strings are placed in the .const section. Setting this
 * parameter to false will save space in the .const section.  Error and
 * Assert messages will contain an "unknown module" prefix instead
 * of the actual module name.
Defaults.common$.namedModule = false;
 */

/*
 * Comment this line out if you want to dynamically create instance
 * objects.
 */
Defaults.common$.memoryPolicy = xdc.module("xdc.runtime.Types").STATIC_POLICY;

/*
 * Minimize exit handler array in System.  The System module includes
 * an array of functions that are registered with System_atexit() to be
 * called by System_exit().
 */
System.maxAtexitHandlers = 4;       

/*
 * Uncomment this line to disable the Error print function.  
 * We lose error information when this is disabled since the errors are
 * not printed.  Disabling the raiseHook will save some code space if
 * your app is not using System_printf() since the Error_print() function
 * calls System_printf().
Error.raiseHook = null;
 */

/*
 * Uncomment this line to keep Error, Assert, and Log strings from being
 * loaded on the target.  These strings are placed in the .const section.
 * Setting this parameter to false will save space in the .const section.
 * Error, Assert and Log message will print raw ids and args instead of
 * a formatted message.
Text.isLoaded = false;
 */

/*
 * Uncomment this line to disable the output of characters by SysMin
 * when the program exits.  SysMin writes characters to a circular buffer.
 * This buffer can be viewed using the SysMin Output view in ROV.
SysMin.flushAtExit = false;
 */

/*
 * Use SysMin for output (System_printf() and error messages) and
 * minimize the output buffer size to save data space.
 */
System.SupportProxy = SysMin;
SysMin.bufSize = 80;

/*
 * Create a LoggerBuf and make it the default logger for all modules.
 */
var LoggerBufParams = new LoggerBuf.Params();
LoggerBufParams.numEntries = 16;
var logger0 = LoggerBuf.create(LoggerBufParams);
Defaults.common$.logger = logger0;

Main.common$.diags_INFO = Diags.ALWAYS_ON;

/* System stack size (used by ISRs and Swis) */
Program.stack = 0x200;

/*
 * Application specific configuration
 */
 
/*
 * Disable unused BIOS features to minimize footprint.
 * This example uses Tasks but not Swis or Clocks.
 */
var BIOS = xdc.useModule('ti.sysbios.BIOS');
BIOS.swiEnabled = false;
BIOS.taskEnabled = true;
BIOS.clockEnabled = true;

/* Minimize system heap */
BIOS.heapSize = 32;

/* Use Custom BIOS lib to achieve minimal footprint */
BIOS.libType = BIOS.LibType_Custom;

/*
 * Create a timer instance to generate a periodic interrupts.
 *
 * The timer will be started within the BIOS_start()
 * thread
 */
var Timer = xdc.useModule('ti.sysbios.family.msp430.Timer');
var timerParams = new Timer.Params();
timerParams.startMode = Timer.StartMode_AUTO;
timerParams.runMode = Timer.RunMode_CONTINUOUS;
/* Timer period is 1/2 second (500,000 uSeconds) */
timerParams.period = 500000;
timerParams.periodType = Timer.PeriodType_MICROSECS;
var myTimer = Timer.create(0, '&myTickFxn', timerParams);

/* Create a task with priority 1 */
var Task = xdc.useModule('ti.sysbios.knl.Task');
var taskParams = new Task.Params();
taskParams.priority = 1;
var myTask = Task.create('&myTaskFxn', taskParams);

/* Inhibit the creation of a task to run idle functions */
Task.enableIdleTask = false;

/* Allow SYS/BIOS to idle the CPU while waiting for an interrupt */
var Power = xdc.useModule('ti.sysbios.family.msp430.Power');

/*
 * Build a custom BIOS library.  The custom library will be smaller than the
 * pre-built "instrumented" (default) and "non-instrumented" libraries.
 *
 * The BIOS.logsEnabled parameter specifies whether the Logging is enabled
 * within BIOS for this custom build.  These logs are used by the RTA and
 * UIA analysis tools.
 *
 * The BIOS.assertsEnabled parameter specifies whether BIOS code will
 * include Assert() checks.  Setting this parameter to 'false' will generate
 * smaller and faster code, but having asserts enabled is recommended for
 * early development as the Assert() checks will catch lots of programming
 * errors (invalid parameters, etc.)
 */
BIOS.libType = BIOS.LibType_Custom;
BIOS.logsEnabled = false;
BIOS.assertsEnabled = true;
Idle.idleFxns[0] = "&myIdleFxn";

  • Norbert,

    I think there are a couple of reasons for this…

    1) By default, that task example uses the SYS/BIOS Power module to put the CPU into LPM0 during idle time.  When an interrupt (like that for Clock) occurs, it is serviced, and then the CPU automatically transitions back to LPM0 upon the RETI instruction of the ISR - and does not execute anything else that might be configured within the Idle loop.  If you don’t want this behavior, in the Power module configuration you can uncheck the box “Idle CPU” and rebuild.  

    Or, you can comment out this line in task.cfg:
    var Power = xdc.useModule('ti.sysbios.family.msp430.Power');

    If you haven’t seen it, there is some discussion of the Power module and how it works here: http://processors.wiki.ti.com/index.php/SYS/BIOS_for_the_MSP430

    2) This example is configured to not create a separate Idle task.  In the Task configuration the check box “Enable Idle Task” is unchecked, and the corresponding source in task.cfg is:

    /* Inhibit the creation of a task to run idle functions */
    Task.enableIdleTask = false;

    When there is no task created for Idle, the application needs to explicitly call Idle_run(), or it can configure this to be called as the Task module’s allBlockedFunction.  This is not obvious, but is described in the cdoc for the Task.enableIdleTask configuration parameter:



    So... to get your idle function to run, you should additionally modify the application configuration to create a separate Idle task, or explicitly call Idle_run() in your application, or, configure Task’s allBlockedFunction to run the idle loop, as shown above.

    If you make these modifications, and then set a breakpoint on your “myIdleFxn”, I think you’ll see it running.

    Hope this all makes sense.  Please let me know if not…

    Scott

  • Hi, Scott,

    GREAT!

    Thank you very much for this very quick response.

    It was point 1, the PowerModule. The IdleTask creation and Task.allBlockedFunc did I check before, but with the PowerModule enabled it doesn´t work.

    Thank you very much again,

    best regards,

    Norbert