QuickStart 5: Multiple Cogs

The Propeller chip’s unique capabilities stem from its eight-core design.  Most people are familiar with the concept of multi-core processing from personal computers. The computer’s operating system splits up the workload between the cores, allowing the software to operate faster.  In the single-core microcontroller world, handling multiple tasks usually requires an “interrupt” — stopping the current operation momentarily to perform another function.

The Propeller is different in this regard.  Its eight cores allow eight operations to run simultaneously, with the ability to share information between cores.  Think of these cores, called cogs, as eight tiny engines running independently, each starting and stopping as the demand for power changes.

The multi-cog design of the Propeller provides unmatched flexibility for applications which require multiple interfaces.  A perfect example is an industrial application where one cog maintains serial communication with a device, while another cog tracks user input from a keyboard, and a third displays information on an LCD. Or, think of a video game where a cog or two are maintaining a TV display, while another cog is collecting data from a controller, and still another is generating audio. 

With eight cogs and a growing library of objects at your disposal, the Propeller can be deployed quickly in an unlimited variety of configurations.

In the Quick Start lesson Introduction to Objects, a simple LED flasher was given greater sophistication by adding a few additional methods to gradually raise the brightness of an LED instead of just turning it on.  The LED object used did not require additional cogs for operation, so the typical start method was not needed to use the additional object. 

Buried at the root of every object’s start method call is the Spin command, cognew.

The cognew command performs the actual task of kick-starting a method, or group of methods, into a new cog.  Consider the following example, based on a program from QuickStart: Introduction to Spin Objects:

CON

  _clkmode = xtal1 + pll16x         'Establish speed
  _xinfreq = 5_000_000              '80Mhz

OBJ

  led: "E555_LEDEngine.spin"        'Include LED methods object

VAR

  byte Counter                      'Establish Counter Variable                                    
  long stack[90]                    'Establish working space

PUB Main

  cognew(Twinkle(16,clkfreq/50), @stack[0])    'start Twinkle cog 1
  cognew(Twinkle(19,clkfreq/150), @stack[30])  'start Twinkle cog 2
  cognew(Twinkle(22,clkfreq/100), @stack[60])  'start Twinkle cog 3

PUB Twinkle(PIN,RATE)                  'Method declaration 

  repeat                               'Initiate a master loop
  
    repeat Counter from 0 to 100       'Repeat loop Counter
      led.LEDBrightness(Counter, PIN)  'Adjust LED brightness 
      waitcnt(RATE + cnt)              'Wait a moment
      
    repeat Counter from 100 to 0       'Repeat loop Counter
      led.LEDBrightness(Counter,PIN)   'Adjust LED brightness 
      waitcnt(RATE + cnt)              'Wait a moment
      

 

The added variable stack provides each cog a small amount of work space.   Each cognew line in PUB Main now starts the method “Twinkle” in a new cog, passing to it an I/O pin number and a delay rate, as well as part of the stack space.  The resulting three repeat loops operate independently of each other, in a separate cog. Were we to add more instructions, PUB Main could  continue on to additional tasks while the LEDs keep flickering up and down.

We could have just as easily passed the value of each cog’s “Counter” variable back to the main program instead of using it to adjust the brightness of an LED.

Passing Information to a Method

In the original version of the LED flicker program (used in Introduction to Objects), the I/O pin for the LED and the delay rate were static because we were dealing with a single LED and speed in that example. 

Without the ability to pass information to the method, we would have had to create three completely different methods with a different I/O pin, and different delay.

Each cognew statement sent two pieces of information, separated by commas, to an instance of the method Twinkle. This two-item parameter list provides initial values for the Twinkle method’s (PIN, RATE) parameters. The values are stored in the stack space assigned at the end of the cognew statement.

Single bits, or volumes of information, can be passed to a method in this manner providing the method’s parameter names don’t duplicate an existing VAR variable, or a Spin reserved word. 

The number and order of items sent to a method must match the expected parameters at the top of the method declaration. Simply calling “cognew(Twinkle(16)...” would have created an error, as the Twinkle method is looking for two pieces of information.

Here we passed parameters with a call to a method that exists within the same object. This technique of parameter passing extends to calling PUB methods that exist in other objects, as long as they are listed in the calling object's OBJ block.  

Additional information regarding the Propeller’s multi-cog design and its usage can be found in Propeller Education Kit Labs Fundamentals: Methods and Cogs[1].

References: 
  1. Propeller Education Kit Labs:Fundamentals text and code are free downloads from www.parallax.com/go/pekit