KSduino 

 The Device Network
ABOUT | BLOG | FORUM | DOWNLOADS | DEVELOPMENT | DEVICES | DONATE | USER
Your IP Address is:

BLOG

  • Multitasking and real time systems at Arduino

    Posted on Wed March 6, 2013

    image

    to make your sketch more professional

    Real time operating system

    A real-time operating system (RTOS) is an operating system (OS) intended to serve real-time application requests. It must be able to process data as it comes in, typically without buffering delays. Processing time requirements (including any OS delay) are measured in tenths of seconds or shorter.

    It’s not a secret that the Arduino has small system resources. Is it possible to run RTOS at Arduino? Fortunately, yes! There is some RTOS which can run at Arduino. We have used some of them and our choice is ChibiOS.

    ChibiOS/RT is designed for deeply embedded real time applications where execution efficiency and compact code are important requirements. This RTOS is characterized by its high portability, compact size and, mainly, by its architecture optimized for extremely efficient context switching.

    What plus we get when use RTOS

    All examples which you see when study Arduino or KSduino is a Linear program. The basic part of program are placed to Loop function and run from its begin to the end. There is a delay at the end of loop when our Arduino does nothing. This kind of program for similar tasks, for example: we read some sensors one time per second. What should we do if we need read light sensor every ten milliseconds and read temperature sensor one time per five seconds. We can write this program in standard loop using millis function and much if which will perform this task. This program will work but the loops code will very long with much conditions. Programs like this is not readable, heavily modified and may contain difficult to debug errors.

    When we use RTOS we can create separate processes (threads). Each of the processes looks like separate loop function. So we can create a program with much loops each of they will execute its separate task. In our example the first process will read light sensor with quick delay the second process will read temperature sensors with long delay. Both of this process will send information to KSduino.

    Setup RTOS and create sketches

    How the RTOS for Arduino looks and what we will use to create programs? The ChibiOS is a simple library which should be copied to your Arduinos library folder. And the program is simple Arduino sketch created in Arduino IDE.

    OK, Let us download ChibiOS and create your first ChibiOS Arduino sketch!

    We get the ChibiOS from http://code.google.com/p/rtoslibs/ page. This page contain information about other RTOS and link for official ChibiOS website.

    There is direct download link, we use version ChibiOS20130208: http://ksdu.in/o/45

    You can download also this archive from the KSduino website:
    http://ksduino.org/downloads/ChibiOS20130208.zip

    The ChibiOS and KSduino example

    We modify example from previous article: Pseudo multitasking. Using timer in Arduino sketch

    In this example we create process:

    • Thread 1 for sending parameters to KSduino
    • Thread 2 for calculate DS18b20 temperature
    • Thread 3 for read KSduino answers

    To synchronize KSduino tasks we use semafor so in one time moment only one KSduino task can run.
    
    // Includes
    #include "SPI.h"
    #include "EthernetUdp.h"
    #include "OneWire.h"    // one wire library to connect ds18b20
    #include "ksDS18B20.h" 	// subclass to read ds18b20 values
    #include "KSduino.h"	// KSduino Library
    #include "ChibiOS_AVR.h" // ChibiOS library
    
    // DS18B20 address
    uint8_t  devAddr1[] = { 0x28, 0x16, 0x05, 0xB2, 0x03, 0x00, 0x00, 0x00 };
    
    // Define OneWire, DS18B20 & Timer classes
    OneWire ds(7);   // OneWire on pin 7
    ksDS18B20 ds18b20_1 (&ds, devAddr1);
    
    // KSduino User definition -----------------------------------------
    
    // This Arduino ID and Password
    // Change this values to yours
    unsigned int deviceID = 0000;	// set your Device ID
    unsigned int devicePwd = 1111;  // set your Device Password
    
    // This Arduino MAC, IP,DNS, Gateway and port 
    // Change this values to yours
    byte mac[] = { 0x74,0x69,0x69,0x2D,0x00,0x00 };
    byte ip[] =     { 192, 168, 1, 222 };
    //byte dns[] = { 192, 168, 1, 1 };
    //byte gateway [] = { 192, 168, 1, 1 };
    //byte subnet [] = { 255, 255, 255, 0 };  
    unsigned int port = 40000 + deviceID;
    
    // KSduino Server definition ----------------------------------------
    
    // Server address & port
    byte serverIp[] = { 178,63,53,233 };   // Global IP address
    unsigned int serverPort = 9930;        // Port number
    
    // ----------------------------------------------------------------
    
    // Define KSduino class
    KSduino ksd (deviceID, devicePwd, serverIp, serverPort);
    
    // Define some KSduino parameters with KSduinoParameter class
    KSduinoParameter d1 (&ksd, "d1", 0.5, 15*60);
    KSduinoParameter f1 (&ksd, "f1", 0.5, 15*60);
    
    // Semaphore to trigger context switch
    Semaphore sem;
    
    // Idle time counter
    volatile uint32_t count = 0;
    
    
    //------------------------------------------------------------------
    void setup()
    {
      ksd.begin(mac, ip, port);    // start KSduino
      // ksd.begin(mac, ip, dns, gateway, port);
      // ksd.begin(mac, ip, dns, gateway, subnet, port);
    
      // Setup ChibiOS
      chBegin(mainThread);
    }
    
    
    //------------------------------------------------------------------------------
    // thread 1 - this task send KSduino parameters
    // 160 byte stack for KSduino task, beyond task switch and interrupt needs
    static WORKING_AREA (waThread1, 160);
    
    static msg_t Thread1(void *arg) 
    {  
      #define WAIT_FOR_ANSWER 2
    
      for (;;) 
      {
        // Create D1 test value
        int d1_generator = random(1,1000);
        byte d1_value =  d1_generator < 10 ? 1 : 0; // will high ones per second
    
        // Send values to KSduino if something changed
        if (d1.check (d1_value) || ds18b20_1.getTemp () && f1.check(ds18b20_1.celsius))
        {
          chSemWait(&sem); // only one KSduino task should run at this moment
          
          ksd.beginPacket ();
          d1.addParameter (d1_value);
          f1.addParameter( ds18b20_1.celsius);
          ksd.endPacket (WAIT_FOR_ANSWER);
    
          chSemSignal(&sem);
        }
        chThdSleepMilliseconds(10);
      }
      
      return 0;
    }
    
    
    //------------------------------------------------------------------------------
    // thread 2 - calqulate DS18b20 thermometer every second
    // 64 byte stack beyond task switch and interrupt needs
    static WORKING_AREA (waThread2, 64);
    
    static msg_t Thread2(void *arg) 
    {
      
      for (;;) 
      {
        ds18b20_1.readTermometer();
        
        chThdSleepMilliseconds(1000);
      } 
    
      return 0;  
    }
    
    
    //------------------------------------------------------------------------------
    // thread 3 - KSduino update 
    // 160 byte stack for KSduino task, beyond task switch and interrupt needs
    
    static WORKING_AREA(waThread3, 160);
    
    static msg_t Thread3 (void *arg)
    {
      for (;;)
      {
        chSemWait(&sem); // only one KSduino task should run at this moment
        ksd.update ();
        chSemSignal(&sem);
    
        chThdSleepMilliseconds(5);
      }
      
      return 0;
    }
    
    
    //------------------------------------------------------------------------------
    void mainThread() {
      
      // initialize semaphore
      chSemInit(&sem, 1);
    
      // start blink thread
      chThdCreateStatic(waThread1, sizeof(waThread1),
        NORMALPRIO + 1, Thread1, NULL);
        
      // start print thread
      chThdCreateStatic(waThread2, sizeof(waThread2),
        NORMALPRIO + 1, Thread2, NULL);
        
      // start ksduino send thread
      chThdCreateStatic(waThread3, sizeof(waThread3),
        NORMALPRIO + 1, Thread3, NULL);
        
      // Main thread (iadle thread) loop 
      for (;;) 
      {
        // must insure increment is atomic
        // in case of context switch for print
        noInterrupts();
        count++;
        interrupts();
      }
    }
    
    
    //------------------------------------------------------------------
    void loop()
    {
      // not used
    }
    
    To use this example you need one DS18b20 sensor: https://ksdu.in/o/3h
    This sketch is using ksDS18B20 class. You can download this example with ksDS18B20 class at: http://ksdu.in/o/46

    Best regards,
    Kirill Scherba
    The founder and main developer of KSduino project.
     

    Sea also:

    How to skip repeated parameter values?
    Pseudo multitasking. Using timer in Arduino sketch





  • comments powered by Disqus
Created with KSNews

HOME | CONTACTS | INFORMER | SHORTENER | DOCUMENTATION | HELP

Copyright © 2012-2013, The KSduino Project