Simultaneous Multitasking With the Propeller

pinkybrain.jpg

This is part 3 of a multi-part series.  The other parts are here.

Let's imagine a hypothetical 'obstacle avoidance' robot with a set of wheels and a ping sensor.  But instead of being controlled by an microcontroller, it's controlled by a little rat.  Here's what you tell the rat to do;

  1. Push the robot forward a bit.
  2. Run up to the top and check the distance reported from the ping sensor.  If it's greater than 10, go back down and push the robot forward a bit more, then run back up and check it again.
  3. If it's less than 10,
    1. turn the sensor left and write down the measurement.
    2. Then turn it right and write down the measurement.
    3. If the left measurement is smaller, run down and push the robot to the right and start all over again
    4. If the right measurement is smaller, run down and push the robot to the left and start all over again.

As you can see, this is a linear, single-threaded activity.  To speed things up, we can use a faster rat, but he can only work on one thing at a time.  Simultaneous Multitasking lets you recruit another rat to help out.  Rat #2 will man the ping sensor, and tell rat #1 which way to push.

You'll instruct Rat #2; "Watch the ping sensor.  If it gets under 10, measure left and right.  Tell the other rat which direction is larger."
And tell Rat #1; "Push the robot forward.  If Rat #2 shouts a direction, push the robot that way."

No more running around, and no pausing to get distance measurements.  Each rat has a simple task that's easy to understand and optimize.  That's the idea of simultaneous multitasking.

WHY SIMULTANEOUS MULTITASKING

1 - You can always hire more rats
As a task becomes more complex, we can bring more rats in to help out.  But there is a limit to how much a single rat can do alone.

2 - Splitting up the work is often more efficient and easier to understand.
By compartmentalizing tasks, we make each task easier to understand, debug, and optimize.

3 - It's good practice
Simultaneous Multitasking isn't the wave of the future, it's 'the wave of the current'.  Practice now so that when you have a design that requires multitasking, you'll have the skills to do it.

WHY NOT SIMULTANEOUS MULTITASKING

Primarily, it's when the task is so simple that there is no benefit to dividing the labor.  But understanding multitasking will only help you to better understand when it is and isn't a good approach.  You don't have to implement simultaneous multitasking on the Prop, it supports either approach.

ARCHITECTURES

There are 3 approaches I can think of;

1 - Multi-CPU
Several microcontrollers can work on something at the same time.  They don't share resources, but talk to each other via a buss

2 - Multi-core
The microcontroller has several logic units that can each work on their own thing.  They have some private resources and some shared resources.

3 - Peripherals
The microcontroller has a few 'helpers' on-board to take care of specific tasks.  These helpers can only help out with certain tasks, but they can do so in the background, without interrupting the program flow.

All 3 approaches are possible with the Propeller.  I'm going to talk about #2 (multi-core) in this walkthrough.

PROPELLER MULTITASKING

The Prop has 32k of RAM that's shared by all cogs. When the Prop starts up, it loads your code into RAM, and the first cog starts running it.  If you want to start a second cog on a task, you use the command:
COGNEW(method, @stack)

COGNEW tells the active cog to start a new cog and have it run the method specified.  You can also pass values to the method, just like calling any other method.  The only thing that might look odd is '@stack'.  Each cog needs a bit of working space. In your VAR section, just declare:
LONG stack[20]

How much stack space to reserve depends on the method you're going to run.  But you can start with 20 LONG stack[20]) and bump it up if you have any problems or have extra memory.  Once your object is complete, there are a couple tools in the object exchange to help you see exactly how big your stack needs to be.

Here's the code for our obstacle avoider;


Full

Let's walk through it;

You already know from previous walkthroughs what that CON block holds program constants.  I've decided to put the motor control pins there, and the pin that gets ping data. The VAR block reserves some stack space and one variable (direction).  The second cog will figure out what direction to go and place the result in that variable.  The first cog will read it and do as told.

There's already an object that comes with the Propeller tool for reading ping sensors.  So I'm including that in the Object block.

The first PUB block is where execution begins;
First, I tell the (currently only) running core that the motor control pins should be outputs.  Then, I tell it to start up another cog running the method checkping. Finally, to my main loop, where cog0 is tasked with pushing the robot wherever cog1 tells it, based on the value of the direction variable.

Cog1 starts up with checkping, where it runs through a loop;  if there's something within 10mm, check to the right and left.  Tell Cog0 to push the robot by writing a value to the direction variable.

And that's it!  That's an example of how to get multiple cogs to work at the same time on the Prop.  In summary;

  1. Simultaneous Multitasking means doing several things at the same time
  2. On the Prop, any cog can start a new cog with the command: COGNEW(Method, @stack)
  3. Variables are scoped to the object and can be shared between cogs.

As usual, let me know if you have any questions!