Author Topic: Featherweight OS for Arduino  (Read 5133 times)

0 Members and 1 Guest are viewing this topic.

Offline ehsmengTopic starter

  • Contributor
  • Posts: 35
  • Country: gb
Featherweight OS for Arduino
« on: June 24, 2014, 03:54:00 pm »
Looking at Arduino examples, many seem content with making a stepper go 20 ticks and have the program blocked until done.

How does it look in real life if you have say a serial listener receiving commands and controlling 10 steppers? Would you have an event loop with say sleep(100us) and iterating a data structure or do you do something more intricate like Protothreads or some other featherweight "os"?
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Featherweight OS for Arduino
« Reply #1 on: June 24, 2014, 03:58:21 pm »
Implement an interrupt-driven receiver and you don't need stinky OS, featherweight or otherwise.
================================
https://dannyelectronics.wordpress.com/
 

Offline retrolefty

  • Super Contributor
  • ***
  • Posts: 1648
  • Country: us
  • measurement changes behavior
Re: Featherweight OS for Arduino
« Reply #2 on: June 24, 2014, 04:07:52 pm »
Many arduino projects have utilized simple 'state machine' concept using the internal millis() counter to allow the program to continue to loop without blocking, just check time status of each function and if interval has been reached, execute function, otherwise return to main loop function. User interrupts are also available if and when needed.



 

Offline Kremmen

  • Super Contributor
  • ***
  • Posts: 1289
  • Country: fi
Re: Featherweight OS for Arduino
« Reply #3 on: June 25, 2014, 12:24:39 pm »
That is what i usually do if / when i do something with Arduino. Like just now i have written a small app to drive a variable speed air rifle target trolley. The state machine cycles continuously and does all timings based on millis() without ever busy waiting for any changes. Works nicely but results in slightly complex looking applications due to the explicitly visible state machine.

I have actually run FreeRTOS on the ATMega 328 that powers many Arduinos and it runs without problems. There will of course be rather low limits on how many tasks and other OS resources can be made to work but at least 3 tasks and 3 message queues worked like a charm with pre-emptive scheduling. 1 ms schedule timer was not a problem, meaning 1000 context changes per second.
Nothing sings like a kilovolt.
Dr W. Bishop
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 28724
  • Country: nl
    • NCT Developments
Re: Featherweight OS for Arduino
« Reply #4 on: June 25, 2014, 12:27:35 pm »
Besides an OS there are two ways:
- use a timer interrupt (mostly when timing is critical)
- or use the statemachine approach using a system wide timer tick counter
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline Dago

  • Frequent Contributor
  • **
  • Posts: 659
  • Country: fi
    • Electronics blog about whatever I happen to build!
Re: Featherweight OS for Arduino
« Reply #5 on: June 25, 2014, 01:33:58 pm »
Usually program structure for these kinds of "multitasking" applications is a main event loop which "does everything" and then a bunch of interrupts that do everything that needs to be tended immediately (such as receiving UART data).

So basically for your example you'd have a main event loop where you'd keep checking some kind of a command buffer if there is any new commands, and stepping the motors if necessary. A separate interrupt would load data to the command buffer that would get parsed in the main event loop. After the last packet of the command would be loaded the main event loop would parse and empty the buffer and command the steppers to do something. Might set timer based interrupts for controlling the stepper motor steps or such. Idea is to keep the interrupts as light as possible and do all the "processing" in the main event loop. So instead of calculating something in the interrupts you'd just set a flag that this needs to be calculated and then you'd do it in the event loop.

Depending on the application and the peripherals of the MCU etc. this can be rather simple and straightforward or complicated. If it gets really complicated then you'd prolly need some other way to solve the problem (such as an RTOS). 10 steppers controlled via UART sounds like it should be fairly simple but depends on the speed of the steppers and amount of  timers available etc.
Come and check my projects at http://www.dgkelectronics.com ! I also tweet as https://twitter.com/DGKelectronics
 

Offline rob77

  • Super Contributor
  • ***
  • Posts: 2087
  • Country: sk
Re: Featherweight OS for Arduino
« Reply #6 on: June 25, 2014, 02:40:07 pm »
How does it look in real life if you have say a serial listener receiving commands and controlling 10 steppers?

ARM or other CPU suitable for such a thing ;)
i do like Atmega, i use it a lot, but for complex controls i wouldn't use it ;) you know.. it's like trying to do CAD/CAM on ZXspectrum or C64 :D
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3438
  • Country: gb
Re: Featherweight OS for Arduino
« Reply #7 on: June 25, 2014, 09:31:49 pm »
Implement an interrupt-driven receiver and you don't need stinky OS, featherweight or otherwise.

Stinky OS  :-DD

For 8 bit code that has a large number of separate "tasks" that must run concurrently, then state machines are the obvious answer.  Just implement a simple system timer with e.g. a 1 millisecond period, and then have each state machine test whether it is time to start running.  All state machines are called in sequence from the main loop, and simply return without doing anything if they are not ready to run.  I have implemented some fairly complex control systems like this, but you do have to be careful about how much time is used by each state.

Adam Dunkels Protothreads allow you to hide the state machine by clever use of the pre-processor, which can make you code look cleaner and easier to read.  However, it's not quite as efficient as a simple hand written state machine using enumerated state values, especially for large numbers of states.

You may also need FIFO's etc. for "inter-task" comms.
 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6365
  • Country: 00
Re: Featherweight OS for Arduino
« Reply #8 on: June 26, 2014, 06:50:21 pm »
Looking at Arduino examples, many seem content with making a stepper go 20 ticks and have the program blocked until done.

How does it look in real life if you have say a serial listener receiving commands and controlling 10 steppers? Would you have an event loop with say sleep(100us) and iterating a data structure or do you do something more intricate like Protothreads or some other featherweight "os"?

How do you generate the stepper signals, by software toggling pins high/low? If so what is the timing accuracy that you need to make these bit flips?

An arduino program looks like this

void setup() {
}
void loop() {
}

If you want to have multi tasking you can do it by emulating multiple arduino programs

void setup1() {
}
void loop1() {
}

void setup2() {
}
void loop2() {
}
...

and then implement the main as
void setup() {
  setup1();
  setup2();
  ...
}

void loop() {
  loop1();
  loop2();
  ...
}

Just make sure not to use delay() and similar busy loops in the loop() functions and make your timing decisions based on state variables and milliseconds().   For example, a led blinking task can look like this pseudo code

static long ms_at_last_chagne;
static boolean last_value;

void setup_led_blinking() {
  set LED pin mode to output
  set LED pin high
 
  ms_at_last_chagne = millseconds();
  boolean last_value = true;
}

void loop_led_blinking {
  // Need to do anything?
  if ((millisecods() - ms_at_last_chagne) < 500) {
    return;
  }

  // Flip pin.
  last_value = !last_value;
  set LED pin to last_value;
  // You can use the current time or keep tracking the old schedule.
  ms_at_last_chagne += 500;
}

 

Offline ehsmengTopic starter

  • Contributor
  • Posts: 35
  • Country: gb
Re: Featherweight OS for Arduino
« Reply #9 on: June 29, 2014, 11:33:41 am »
Hi all,

Thanks for your suggestions! I did a small test, and I think I tentatively like this below. I suppose that if I need some accurate pulse, I'll add a timer IRQ.

Code: [Select]
#include <limits.h>

const int ledpin = 7;
const int cpupin = 8;

// -----------library code---------------------------

unsigned int m_tickstart;
class TimeSlot
{
  public:
 
  int m_skipTicks; // How many ticks to skip
 
  TimeSlot()
  {
    m_skipTicks = 0;
  }

  virtual void init();
 
  // Return value is how many ticks should be skipped until this function is called the next time
  // If unsure, do a return 0
  virtual int tick();
 
  //static unsigned int m_tickstart; // why does this not work?
 
  static void timerstart_tasklist()
  {
    m_tickstart = micros();
  }
 
  static void timerstop_tasklist(unsigned int tickinterval)
  {
    unsigned int us_stop, us_total, us_start;
   
    us_start = m_tickstart;
    us_stop = micros();
   
    if (us_stop > us_start) {
      us_total = us_stop - us_start;
    } else {
      us_total = UINT_MAX - us_start;
      us_total += us_stop;
    }
 
    if (us_total < tickinterval) {
      delayMicroseconds(tickinterval - us_total);
    }
  }
 
  static void init_tasklist(TimeSlot *tasklist[])
  {
    for (int ii=0; NULL != tasklist[ii]; ii++)
    {
      tasklist[ii]->init();
    }
  }
 
  static void tick_tasklist(TimeSlot *tasklist[])
  {
    for (int ii=0; NULL != tasklist[ii]; ii++)
    {
      TimeSlot *ts = tasklist[ii];
      if (0 < ts->m_skipTicks)
      {
        ts->m_skipTicks--;
      }
      else if (0 == ts->m_skipTicks)
      {
        ts->m_skipTicks = ts->tick();
      }
      else
      {
        // if negative, then not called!
      }
    }
  }
};

class Button : public TimeSlot
{
  public:
 
  int m_port;
 
  Button(int port)
  {
    m_port = port;
  }
 
  void init()
  {
    pinMode(m_port, INPUT);
  }
 
  virtual int tick();
 
};

// -----------Project code---------------------------
class myButton : public Button
{
  public:
 
  int m_state;
 
  myButton(int a) : Button(a)
  {
    m_state = LOW; // to get it predictable
  }
 
  int tick()
  {
    int present_state = digitalRead(m_port);
    if (present_state != m_state)
    {
      m_state = present_state;
      digitalWrite(ledpin, m_state);
      return 10; // ignore mechanic bounce
    }
    return 0;
  }
};

TimeSlot *tasklist[] = {
  new myButton(2),
  NULL
};


void setup()
{
  pinMode(ledpin, OUTPUT);
  pinMode(cpupin, OUTPUT);
  TimeSlot::init_tasklist(tasklist);
}

int ledstate = 0;
void loop()
{
  digitalWrite(cpupin, HIGH);
  TimeSlot::timerstart_tasklist();
  TimeSlot::tick_tasklist(tasklist);
  digitalWrite(cpupin, LOW);
  TimeSlot::timerstop_tasklist(1000);
}

And a meme:


       I don't usually use ii for loop variable

                      (o_o)

But when i do, it's because [ii] does not mean italic in bbcode

« Last Edit: June 29, 2014, 03:22:25 pm by GeoffS »
 

Offline sunnyhighway

  • Frequent Contributor
  • **
  • Posts: 276
  • Country: nl
Re: Featherweight OS for Arduino
« Reply #10 on: June 29, 2014, 03:15:54 pm »
And a meme:


       I don't usually use ii for loop variable

                      (o_o)

But when i do, it's because [ii] does not mean italic in bbcode



Code: [Select]

[i] don't seem to have this problem.  ;-)

 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf