Chibios/RT and Arduino Multitasking

In the last post I showed how the simple Blink program can be implemented on an Arduio using both C/C++ and the Chibios/RT real-time operating system (RTOS).

Because of their simplicity, the two are practially identical. The only action they’re taking is to turn on the LED, wait, turn off the LED, and wait. In that case using the Arduino’s blocking delay() function doesn’t matter because there isn’t anything else to do. But for most practical programs this isn’t the case.

Consider a program that takes two actions. Every 1250 msec it changes the state of the LED and every 500 msec it prints a message to the serial port. In that case the Arduino’s blocking delay() function can’t be used because blocking either action (the LED or the print) would interfere with the other’s timing.

Multitasking on the Arduino

On the Arudino using C/C++ this problem can be overcome using the millis() function and timing accumulators. A different method is written for each action to be performed. These methods are called each time through the Arudino loop() function. Within them the millis() function is used to determine how much time has passed since the last time the method was called and a timing accumulator is updated to keep track. Once the appropriate amount of time has passed the corresponding action is performed.

The Adafruit site has a good tutorial describing this technique. The listing below shows one possible implementation.

    #include <Streaming.h>

    #define  LED_TIMEOUT 1250
    #define  SERIAL_TIMEOUT 500

    // Blink method.
    //
    void blinkLed()
    {
        static unsigned long _ledTimer = 0;
        static bool _lightLed = false;

        static unsigned long _lastTime = 0;

        // Get the current time, calculate the time since last time,
        // and save the current time for later.
        //
        unsigned long time = millis();
        unsigned long delta = time - _lastTime;
        _lastTime = time;

        // Update the accumulator.  Execute the code if
        // you've reached the timeout value.
        //
        _ledTimer += delta;
        if (_ledTimer >= LED_TIMEOUT)
        {
            _lightLed = !_lightLed;
            digitalWrite(LED_BUILTIN, _lightLed ? HIGH : LOW);
            _ledTimer -= LED_TIMEOUT;
        }
    }

    // Serial print method.
    //
    void printSerial()
    {
        static unsigned long _serialTimer = 0;
        static unsigned long _lastTime = 0;
        static unsigned long _count = 0;

        // Get the current time, calculate the time since last time,
        // and save the current time for later.
        //
        unsigned long time = millis();
        unsigned long delta = time - _lastTime;
        _lastTime = time;

        // Update the accumulator.  Execute the code if 
        // you've reached the timeout value.
        //
        _serialTimer += delta;
        if (_serialTimer >= SERIAL_TIMEOUT)
        {
            _count += 1;
            Serial << "Hello world! " << _count << endl;
            _serialTimer -= SERIAL_TIMEOUT;
        }
    }

    // Main routines.
    //
    void setup() 
    {
        // Open serial communications and wait for port to open:
        //
        Serial.begin(9600);
        while (!Serial) ;
    }

    void loop() 
    {
        blinkLed();
        printSerial();
    }

Multitasking Using Chibios/RT

Chibios/RT accomplishes the same thing using threads. A thread is initialized for each action to be performed and once started it will run independently. The listing below shows how to use threads to perform the actions described above.

    #include <ChRt.h>
    #include <Streaming.h>

    #define  LED_TIMEOUT 1250
    #define  SERIAL_TIMEOUT 500

    // Blink thread.
    //
    static THD_WORKING_AREA(waBlink,48);
    static THD_FUNCTION(Blink, arg) 
    {
        static bool _lightLed = false;
        while (!chThdShouldTerminateX()) 
        {
            // Toggle the LED.
            //
            digitalWrite(LED_BUILTIN, _lightLed ? HIGH : LOW);
            _lightLed = !_lightLed;
            chThdSleepMilliseconds(LED_TIMEOUT);
        }
    }

    // Serial print thread.
    //
    static THD_WORKING_AREA(waSerialPrint, 48);
    static THD_FUNCTION(SerialPrint, arg) 
    {
        static uint16_t _printCount = 0;
        while (!chThdShouldTerminateX()) 
        {
            Serial << "Hello world! " << _printCount << endl;
            _printCount += 1;
            chThdSleepMilliseconds(SERIAL_TIMEOUT);
        }
    }

    // Main routines.
    //
    void setup () 
    {
        chBegin(mainThread);
    }
    
    void mainThread () 
    {
        // Open serial communications and wait for port to open.
        //
        Serial.begin(9600);
        while (!Serial) ;

        // Spawn the threads.
        //
        thread_t *tpBlink = chThdCreateStatic(
            waBlink, sizeof(waBlink), NORMALPRIO + 1, Blink, NULL);
        thread_t *tpSerial = chThdCreateStatic(
            waSerialPrint, sizeof(waSerialPrint), NORMALPRIO + 1, SerialPrint, NULL);
    }
    
    void loop() 
    {
    }

Of the two, I think the Chibios version functionality is easier to understand. There’s some additional set up required but since each thread is self contained there’s no need to maintain timing accumulators. You can just use the chThdSleepMilliseconds() function like in the Blink program since it’s a non-blocking call.

However, the Chibios version uses 4082 bytes of program space and 708 bytes of memory while the Arduino C/C++ version uses only 2256 bytes of program space and 223 bytes of memory. This is probably because each thread in the Chibios version maintains its own working area while in the Arduino C/C++ version, all functions work within the same program space. So if you’re running up against the memory limits of your processor the Arduino C/C++ version is the winner.

Advertisements

1 Comment

    Trackbacks

    1. Chibios/RT and Arduino Timers | Computer/Electronics Workbench

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out /  Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out /  Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out /  Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out /  Change )

    Connecting to %s

    This site uses Akismet to reduce spam. Learn how your comment data is processed.

    DuWayne's Place

    Computers, Electronics, and Amateur Radio from KC3XM

    QRP HomeBuilder - QRPHB -

    Computers, Electronics, and Amateur Radio from KC3XM

    Open Emitter

    Computers, Electronics, and Amateur Radio from KC3XM

    Ripples in the Ether

    Emanations from Amateur Radio Station NT7S

    m0xpd's 'Shack Nasties'

    Computers, Electronics, and Amateur Radio from KC3XM

    %d bloggers like this: