Go Down

Topic: SCoop - multitask and Simple COOPerative scheduler AVR & ARM (Read 65844 times) previous topic - next topic


Version 1.2, manual corrections and volatile

I see that a new version 1.2 has been posted on <https://code.google.com/p/arduino-scoop-cooperative-scheduler-arm-avr/>, thanks for that. I am just starting a new project and I think Scoop is the right tool for me and am going to try it.

I would like to propose some corrections to the manual, but I do not seem to find the source of it, which would make the job much easier: can I access it anywhere? In any case, where should I send proposal for changes?

By the way, one of the things I notice in the manual is the use of volatile in the very first example, the one on the first page. As far as I can tell, volatile is useless here, because the compiler will never optimise out accesses to this variable. That would happen if we had an infinite while loop instead of the loop entry point and if the scheduler were preemptive, but none of these two conditions are true here.



I m sure you will get success in using SCOOP, plese let us know!

for the document, just give me your email adress by private message and I ll send you the original .doc file.

for the volatile count ... you are probably right in this example. But in general, when the variabe is used accross tasks, my experience is that you avoid loosing time in trouble shooting by putting them volatile , even in coopreative mode  :P

hope you succeed in your project


I sent you my mail address with a private message.

As far as volatile is concerned, you may be right that there are cases where this is necessary even with cooperative scheduling (even if I do not see on off the top of my head), but stating in the first example that this is necessary is confusing and adds unnecessary complexity and black magic.


Thanks for the excellent simple kernel which does not have many issues that come with preemptive ones when using standard Arduino libraries.

Now I don't have to use superloop to call state machines to handle different events. State machines are often hard to write and difficult to understand. Each task can now almost can behave as if it is an independent program, similar to rtos.
Hope to introduce to my project students.

As for the volatile, I suppose it is often better to be safe.

Thank you.


Thanks for your nice and very useful scheduler libraries.

After having worked with SCoop, I discovered that I was using no one of the many goodies provided, apart from stack printing. So I tried the SchedulerARMAVR and I discovered that it saves over 1500 bytes of program memory and 58 bytes of data memory with respect to SCoop, both of which are important to my project. Having to use dynamic allocation for the stack is a non-issue for me, as I allocate it during setup() and never free it.

The only thing  I was missing is the printing of the size of the stack left free for the tasks. So I got down and wrote my own functions, which appear to work for me.

It is possible to make them slightly more compact by incorporating them into SchedulerARMAVR.cpp, I can provide a patch if you wish. I think they would be a useful addition to SchedulerARMAVR.  Here they are:

Code: [Select]

// Use this rather than Scheduler.StarLoop() and save the pointer returned
// so that you can  pass it to stackUnused().
// This function relies on malloc to just give back the same pointer after free(),
// and on Scheduler.StarLoop() to do the first malloc() call to allocate the stack.
// If the SChedulerARMVR code is changed so that the above is not true, memory corruption will result.
byte *startLoop (SchedulerTask task, unsigned stackSize) {
  byte *stack = (byte *)malloc(stackSize); // the same allocation Scheduler.StarLoop will do
  // If we are being called from the main loop, let's fill our stack, too
  extern byte *__brkval;    // set after malloc, it is the top of the heap
  if ((byte *)&stack > __brkval)    // this function called from the main loop
    for (byte *end = (byte *)&end - 10;    // leave space for a small interrupt routine
__brkval < end;    // until end pointer smashes into the heap
*end-- = 0x55) ;    // fill stack with fixed value
  memset(stack, 0x55, stackSize);    // fill the stack's stack with fixed values
  free(stack);    // now we free the space allocate with malloc
  Scheduler.startLoop(task, stackSize);    // start the task
  memset(stack, 0x55, 4);    // rewrite over memory dirtied by free()
  return stack;    // stack base, to be passed to stackUnused()

// When not using the scheduler, call it from setup()
// Else, this work is done when calling startLoop(), so this function should not be used
void fillStack () {
  extern byte __heap_start, *__brkval;
  byte *beg = (byte*)(__brkval ? __brkval : &__heap_start);
  byte *end = (byte*)&end - 10; // leave space for a small interrupt routine
  while (beg < end) *beg++ = 0x55; // can't use memset here: it would use the stack

// Count bytes marked 0x55 from the stack base to the the local variables
// Should be called with either no arguments, for counting free stack on the main loop,
// or with two arguments, for the tasks.
unsigned stackUnused (byte *stackBase, unsigned stackSize) {
  byte *end = stackSize ? stackBase + stackSize : (byte *)&end - 10;
  byte *p = stackBase;
  while (*p == 0x55 && p < end)
    p += 1;
  return p - stackBase;

In order to use the code, you should use startLoop(task, stackSize) rather Scheduler.startLoop(task, stackSize), and save the return value, that is, the base of the stack of the task just created. Also, save the value of the stack size in a variable.

Then, you can call stackUnused() either from the main loop without arguments, or from wherever you want with two arguments: a task's stack base pointer and the task stack size. It returns the number of bytes on the stack that have been left unused for the main loop or for that task, respectively.


I've been looking for a simple task manager/scheduler for my project, and came across SCoop.

I did as I usually do first off with 'strange' libraries and tried to run the examples to get a 'feel' for SCoop.

I found that none of the examples would compile with the Arduino 1.5.4 IDE - they all gave multiple errors that appeared to be library related,  but I didn't look any deeper.

Is there an 'issue' with SCoop and the Arduino IDE?



Dec 12, 2013, 11:32 pm Last Edit: Dec 12, 2013, 11:36 pm by jimford Reason: 1
OK no response so far, so some details:


Gives the following compilation errors:

Arduino: 1.5.4 (Linux), Board: "Arduino Duemilanove or Diecimila, ATmega328"

example1:7: error: expected constructor, destructor, or type conversion before '(' token
example1:10: error: expected constructor, destructor, or type conversion before '(' token
example1:13: error: 'myTask2' has not been declared
example1.ino: In function 'void loop()':
example1:14: error: 'sleepSync' was not declared in this scope
example1.ino: At global scope:
example1:17: error: expected constructor, destructor, or type conversion before '(' token

 This report would have more information with
 "Show verbose output during compilation"
 enabled in File > Preferences.

All the the  other examples give similar errors, plus a whole load more!

Ideas, anyone - please?

(Come on 'fabriceo' SCoop's - your pet. You should be able to provide some input here!    ;^)  )



I have not tried, but it looks like <SCoop.h> is in fact not included.
As the message says, try to enable verbose output to get more information.
Make sure you have SCoop installed int he right place and enabled in the IDE.


I have not tried, but it looks like <SCoop.h> is in fact not included.
As the message says, try to enable verbose output to get more information.

The above message is verbose.

Make sure you have SCoop installed int he right place and enabled in the IDE.

It all appears to be installed in the correct place and appears in the IDE OK.

The only example I've managed to get to comple is the SCoopME template.ino. In fact I'm starting to use SCoopMe in my project and it shows some promise. I've abandoned SCoop! The 'basic sketch' on page 1 of the 'Scoop User Guide V1.2' doesn't compile for me either.

Do you know what the difference is between SCoop and SCoopME ? 'fabriceo' offers no clues and appears to have  gone silent on this thread!

Thanks for the  reply.



I had a look at the SCoopME sources, but without diving into it: it looks like a cleaned up version of SCoop, better written and probably smaller. I suggest you use that instead of SCoop, at least until fabriceo comes up and explains what are the differences.

In fact, I had tried SCoop and then witched to SchedulerARMAVR, which is much simpler, and which I am using right now, because I do not need all the goodies provided by SCoop, it is much smaller and has the same interface as the standard Arduino Scheduler library. The only thing is that I needed to measure the stack occupancy of tasks and I had to write those functions by myself (I posted them above).


Dec 17, 2013, 08:15 pm Last Edit: Dec 17, 2013, 08:19 pm by jimford Reason: 1

In fact, I had tried SCoop and then witched to SchedulerARMAVR, which is much simpler, and which I am using right now, because I do not need all the goodies provided by SCoop, it is much smaller and has the same interface as the standard Arduino Scheduler library.

Interesting - I'll have a look at the SchedulerARMAVR library. Like you, my project uses very little of the facilities that SCoop/SCoopME offer and SchedulerARMAVR may suit.

There's precious little documentation for SchedulerARMAVR and there appears to only the Scheduler.startloop and yield() functions. Do you happen to know of anything else that will enable me to get a 'handle' on it, please?

I notice in the 'Multiple Blinks' example:

Code: [Select]
 // When multiple tasks are running 'delay' passes control to
 // other tasks while waiting and guarantees they get executed.

I'm a bit confused as I thought it was yield() that passes control to the other tasks!



First look at the Scheduler library page, then at the page where Fabrice Oudert announces SchedulerARMAVR, you'll find many indications.

Anyway, if you use the 1.5.x library, the delay() function calls yield(). If you use the 1.0.x library, the delay() function does not call yield(), so you should use Scheduler.delay() rather than delay() to obtain the same effect.


Dec 28, 2013, 03:33 pm Last Edit: Dec 28, 2013, 03:48 pm by fabriceo Reason: 1

I m so sorry that I didnt pay attention to this thread in the past weeks... I was spending time on another fancy project more around electronic and DSP, but ok :)

for some of you having tried Scoop V1.2, for one year ago I havent tried it myself on the early release of Arduino and I ll try to do so in the comming days. I ve just received also a pair of teensy 3.1 and a pair of sparkcore and will check that the lib is working with arduino 1.05 and teense 1.18 and may be on spark later

it is fair to use the SchedulerARMAVR instead of SCoop as it is smaller. I ve just put the Assembly code in it to make it compatible with AVR, credit goes to others and the android team;

still Scoop can offer a bit more features, especially the ring token handling and some time allocation to task, which at some point in your devlopement might be needed to optimize the CPU time given to a task

SCoopeME is a concept which is a rework of SCoop 1.2 but using object templates instead of macros.
also it is ported for TexasIntrusment MSP430 (at least I got it to work)
I ve missed time to finish it as I wanted, and to write proper documentation, but it s not bad and can be considered if you are an early adopter :)

I still strongly beleive in cooperative scheduler concept and whish all the best to the 230+ people having downloaded it and the other to come

cheers and Happy new 2014


I'm relieved to see that you haven't abandoned SCoop, Fabrice!

Firstly, thank you for SCoopME - it's transformed my project and integrates nicely with the phi_prompt menu library I'm using.

As I mentioned in an earlier post, I couldn't get the SCoop examples to compile on Arduino 1.5.4, and switched to SCoopME, which works well.

One feature I ideally need is for the SCoopTimer to handle a time period of 1 Hour, so it needs a milliseconds input of a long unsigned int, rather than int as it is now.  Any ideas how I can work round this problem, please?




that the beauty of modern programing with templates,
in fact when you declare a SCoopTimer you can specify as a third paramter another object in charge of counting the time.
by default the object used is "SCtimerMs"
and this is visible in the source code line 240. here is the extract
Code: [Select]

// class for creating "timers"
template< class CHILD,
          unsigned TIME,
  class SCTIME = SCtimerMs >

struct SCoopTimer : SCoop< SCoopTimer< CHILD, TIME, SCTIME > > {

  static SCTIME timer;
  static SCTIME thresold;

if you create you own object called SCtimerSec then you can pass it when declaring your timer, as a third parameter, like this

Code: [Select]
struct myTimer1 : SCoopTimer< myTimer1, 100, SCtimerSec > { // every 100 second
static void run() {
  // user code go here.
} } myTimer1;

and for creating you own SCtimerSec, just copy paste and rework the SCtimerMs :)

I have tested some month ago and rember it worked. Hope you ll get successfull :)
this template stuff is really amaizing

or you could alsways enter in the timer.run() every second and manage to continue only after 3600 ticks :) thats the old fashion way but without risk!

Go Up