Skip to content

Commit

Permalink
streaming channels for task communication
Browse files Browse the repository at this point in the history
  • Loading branch information
teachop committed Mar 9, 2014
1 parent ac80057 commit 7c3a30f
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 40 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

This repo is a simple multi-core xCore test of a two-task approach to driving an Adafruit NeoPixel LED Strip. The source is in XC, an extension of C with concurrency and support for high speed timing synchronized I/O capability at the language level.

The latest version uses interfaces instead of the channel syntax to link the tasks.

For a view of how XCore I/O works compare the driver code in neopixel_led_task() to some other NeoPixel waveform generator code. An example would be the Adafruit_NeoPixel::show() routine here:

https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp
Expand All @@ -13,10 +11,14 @@ This particular code is able to do precise timing on AVR CPUs by employing cycle
This application is designed for and tested on the XMOS startKIT, but it should be possible to change the XMOS target in the makefile (alter "TARGET = STARTKIT").

###xcore_neopixel_leds
Two tasks make up the application, a pattern generator task and a driver task. These are connected with an interface, which is a language and hardware communication feature. These two tasks are started in main using par. Main connects them together with an interface passed to the tasks.
Two tasks make up the application, a pattern generator task and a driver task. These are exchanging data through a channel, which is a language and hardware communication feature. These two tasks are started in main using par. Main connects them together with a channel passed to the tasks.

The task communication uses "streaming channels" - their high performance is important in this application (see the wiki).

In the example, 4 sets of paired tasks execute in parallel, each pair driving its own NeoPixel strip pattern. While this is likely not the best approach (4 bit wide port?) it is easy and tests multi-tasking on the XCore chip.

Note that the driver tasks use extra test output pins for timing measurements. These were used to evaluate channels vs. streaming channels vs. interfaces for performance. The test outputs can be eliminated if desired.

####blinky_task

The pattern generator task presents a "wheel" rolling multi-color pattern on the RGB LEDs. This pattern code came from an Adafruit or PJRC source but I lost track which - both have some nice code for driving NeoPixels!
Expand Down
68 changes: 31 additions & 37 deletions neopixel_leds.xc
Original file line number Diff line number Diff line change
Expand Up @@ -14,50 +14,43 @@
#define SPEED 1900
#define SPEED_INC 1000

// interface for LED data
interface led_comm {
void next(unsigned int color, int led_index);
};


// ---------------------------------------------------------
// neopixel_led_task - output task for single neopixel strip
//
void neopixel_led_task(port neo, port tp, interface led_comm server comm) {
void neopixel_led_task(port neo, port tp, streaming chanend comm) {
const unsigned int delay_third = 42;
unsigned int delay_count;
unsigned int color_shift;
int bit_count = 24;
unsigned int bit;

while (1) {
select {
case comm.next(unsigned int color_shift, int led_index):
// have new color data
if ( !led_index ) {
// beginning of strip, resync counter
neo <: 0 @ delay_count;
delay_count += delay_third;
}
do {
// output low->high transition
delay_count += delay_third;
tp <: 1;
neo @ delay_count <: 1;

// output high->data transition
bit = (color_shift & 0x800000)? 1 : 0;
color_shift <<=1;
delay_count += delay_third;
neo @ delay_count <: bit;
tp <: 0;

// output data->low transition
delay_count += delay_third;
neo @ delay_count <: 0;
} while ( --bit_count );
bit_count = 24;
break;
comm :> color_shift;
// have new color data
if ( 0x80000000 & color_shift ) {
// beginning of strip, resync counter
neo <: 0 @ delay_count;
delay_count += delay_third;
}
do {
// output low->high transition
delay_count += delay_third;
tp <: 1;
neo @ delay_count <: 1;

// output high->data transition
bit = (color_shift & 0x800000)? 1 : 0;
color_shift <<=1;
delay_count += delay_third;
neo @ delay_count <: bit;
tp <: 0;

// output data->low transition
delay_count += delay_third;
neo @ delay_count <: 0;
} while ( --bit_count );
bit_count = 24;
}

}
Expand Down Expand Up @@ -91,7 +84,7 @@ unsigned int wheel(unsigned char wheelPos) {
// ---------------------------------------------------------------
// blinky_task - rainbow cycle pattern from pjrc and / or adafruit
//
void blinky_task(unsigned int delay, int length, interface led_comm client comm) {
void blinky_task(unsigned int delay, int length, streaming chanend comm) {
timer tick;
unsigned int next_pass;
int loop, outer;
Expand All @@ -101,9 +94,10 @@ void blinky_task(unsigned int delay, int length, interface led_comm client comm)
while (1) {
for ( outer=0; outer<256; ++outer) {
// cycle of all colors on wheel
for ( loop=0; loop<length; ++loop) {
comm <: (wheel(outer) | 0x80000000);
for ( loop=1; loop<length; ++loop) {
// emit data to the driver
comm.next( wheel(( (loop*256/length) + outer) & 255), loop );
comm <: wheel(( (loop*256/length) + outer) & 255);
}

// wait a bit, must allow strip to latch at least
Expand All @@ -124,7 +118,7 @@ port test_pin[4] = { // j7.23, j7.21, j7.20, j7.19
XS1_PORT_1P, XS1_PORT_1O, XS1_PORT_1I, XS1_PORT_1L
};
int main() {
interface led_comm comm_chan[4];
streaming chan comm_chan[4];

par {
// 4 led stips - possible to have differing speeds / lengths
Expand Down

0 comments on commit 7c3a30f

Please sign in to comment.