Slide 1

Slide 1 text

rpi-ws281x Martin Schuhfuss – @usefulthink something with raspberry-pi, hardware-hacking, node.js and other stuff

Slide 2

Slide 2 text

step0: demystify

Slide 3

Slide 3 text

(image from http://www.electrobob.com/ws2812-level-translator/) this is what bits actually look like.

Slide 4

Slide 4 text

rpi-ws281x

Slide 5

Slide 5 text

rpi-ws2811 ws2812 LED-Controller full-color LED with
 integrated controller

Slide 6

Slide 6 text

ws2812 (image from 5mm ‣ SMD5050 Package ‣ ws2811 controller ‣ three separate LEDs red green blue HARDWARE controller

Slide 7

Slide 7 text

3.75µs 1.25µs ws2811 one-wire serial data-signal 0V +5V t wavelength λ pulsewidth frequency 800kHz wavelength 1.25µs 0 2.5µs 5µs 1 0 1 1

Slide 8

Slide 8 text

ws2811 one-wire serial data-signal 0V +5V λ = 1.25µs (±600ns) 
 (f = 800kHz) 350ns (±150ns) 800ns (±150ns) 0 t

Slide 9

Slide 9 text

ws2811 one-wire serial data-signal 0V +5V λ = 1.25µs (±600ns) 
 (f = 800kHz) 750ns (±150ns) 600ns (±150ns) 1 t

Slide 10

Slide 10 text

ws2811 one-wire serial data-signal 1 0 1 1 0 0 1 0 1 0 0 0 0 0 0 0 1 1 1 1 0 1 0 0 0 8 2 b f 4 #80b2f4 in HTML-Notation

Slide 11

Slide 11 text

ws2811 one-wire serial data-signal LED 01 DIN DOUT Register #000000 LED 02 DIN DOUT Register #000000 LED 03 DIN DOUT Register #000000 +5V GND +5V GND +5V GND +5V GND

Slide 12

Slide 12 text

ws2811 one-wire serial data-signal LED 01 DIN DOUT Register #ff8800 #ff8800 1 LED 02 DIN DOUT Register #000000 LED 03 DIN DOUT Register #000000 — — +5V GND +5V GND +5V GND +5V GND

Slide 13

Slide 13 text

ws2811 one-wire serial data-signal LED 01 DIN DOUT Register #ff8800 #00ffff 2 LED 02 DIN DOUT Register #00ffff LED 03 DIN DOUT Register #000000 #00ffff — +5V GND +5V GND +5V GND +5V GND

Slide 14

Slide 14 text

ws2811 one-wire serial data-signal LED 01 DIN DOUT Register #ff8800 #0000ff 3 LED 02 DIN DOUT Register #ffff00 LED 03 DIN DOUT Register #0000ff #0000ff #0000ff +5V GND +5V GND +5V GND +5V GND

Slide 15

Slide 15 text

ws2811 one-wire serial data-signal LED 01 DIN DOUT Register #000000 reset 4 LED 02 DIN DOUT Register #000000 LED 03 DIN DOUT Register #000000 reset reset +5V GND +5V GND +5V GND +5V GND

Slide 16

Slide 16 text

neopixel etc. where to get your ws2812 http://www.watterott.com/index.php?page=search&keywords=ws2812 http://www.adafruit.com/category/168 USA https://www.sparkfun.com/search/results?term=ws2812 GERMANY OTHER INTERNATIONAL ebay, amazon (search "ws2812") direct from china: banggood.com, www.dx.com, alibaba.com

Slide 17

Slide 17 text

build your own :)

Slide 18

Slide 18 text

step1: control

Slide 19

Slide 19 text

Raspberry Pi ‣ Broadcom BCM2xxx SoC ‣ 700MHz ARM CPU / 512MB RAM ‣ SD-Card as Harddrive ‣ 100MBit LAN / HDMI / USB / Audio ‣ raspbian OS Ethernet HDMI micro-USB (power supply) SD-Card GPIO Digital-Audio Analog-Audio USB Status-LEDs

Slide 20

Slide 20 text

Raspberry Pi ‣ interface to external hardware ‣ sensors, motors, anything ‣ SPI / UART / I2C ‣ controllable logic-pins GPIO

Slide 21

Slide 21 text

step2: drivers

Slide 22

Slide 22 text

(image from http://www.electrobob.com/ws2812-level-translator/) the signal-level needs to be changed 1.6 Million times per second. problem

Slide 23

Slide 23 text

Arduino: no problem* ‣ CPU running at 16MHz ‣ 62 nanoseconds per instruction ‣ lots of time™ in between level changes… * assembler-programming required :(

Slide 24

Slide 24 text

awesomeness solutions programming it with arduino sleep solution awesomeness #hhjs (based on a totally representative study with 1 participant)

Slide 25

Slide 25 text

Raspbian: problem ‣ because multitasking. ‣ when the process runs depends on lots of factors we can’t control

Slide 26

Slide 26 text

Raspberry Pi PWM ‣ „serializer“-mode ‣ bits in data-registers represent
 signal-level per PWM-cycle ‣ only a few bytes in registers ‣ needs DMA to transport data

Slide 27

Slide 27 text

Raspberry Pi PWM 0V +5V (frequency: 2.4 MHz) 0 t PWM cycle: 416ns 1 0 0 bits written to PWM-Registers

Slide 28

Slide 28 text

Raspberry Pi PWM 0V +5V (frequency: 2.4 MHz) 1 t PWM cycle: 416ns 1 1 0 bits written to PWM-Registers

Slide 29

Slide 29 text

Raspbian: problem ‣ store prepared pixel-data in memory ‣ let the DMA-Controller transfer data to PWM-Module ‣ CPU or OS are not involved!

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

awesomeness solutions arduino sleep solution awesomeness #hhjs program it in C on raspberry build a server in C and control with node write a node-addon.

Slide 32

Slide 32 text

step3: node!

Slide 33

Slide 33 text

‣ based on a C-Library by Jeremy Garff ‣ wrapper handles only type-checking and conversions between V8-types and C ‣ simple JS-interface: ws281x = { init: function(numLeds, options) { … }, /** @param ledData {Uint32Array} */ render: function(ledData) { … }, reset: function() { … } }; node-rpi-ws281x C-Library source:

Slide 34

Slide 34 text

‣ first challenge: get it to compile. ‣ hard to find documentation ‣ solution was actually pretty simple // binding.gyp (some stuff left out) {
 targets: [{
 target_name: "rpi_ws281x",
 sources: ["./src/rpi-ws281x.cc"],
 dependencies: ["libws2811"]
 }, {
 target_name: "libws2811",
 type: "static_library",
 sources: [ … ],
 }
 ]
 } writing node-addons (required reading: http://nethack4.org/blog/building-c.html)

Slide 35

Slide 35 text

writing node-addons // rpi_ws281x.cc #include 
 #include 
 using namespace v8;
 Handle Reset(const Arguments& args) {
 HandleScope scope; // ... binding-code here ... return scope.Close(Undefined());
 }
 void initialize(Handle exports) { // exports.reset = function Reset() {};
 exports->Set(String::NewSymbol("reset"), FunctionTemplate::New(Reset)->GetFunction());
 }
 
 NODE_MODULE(rpi_ws281x, initialize) no arguments / return undefined

Slide 36

Slide 36 text

writing node-addons // rpi_ws281x.cc Handle Init(const Arguments& args) {
 HandleScope scope;
 
 if(args.Length() < 1 || !args[0]->IsNumber()) {
 ThrowException(Exception::TypeError( String::New("init(): argument 0 is not a number")));
 return scope.Close(Undefined());
 }
 int numLEDs = args[0]->Int32Value();
 // ... the actual binding-code ... 
 return scope.Close(Undefined());
 } accepting arguments/ throwing exceptions

Slide 37

Slide 37 text

writing node-addons ‣ writing a simple node addon is not as complicated as it seems ‣ i should write more C++ ‣ most of the code to deal with arguments and type-checking ‣ better understanding how V8 works lessons learned…

Slide 38

Slide 38 text

finally: Javascript

Slide 39

Slide 39 text

hello ws281x-native var ws281x = require('../lib/binding/ws281x-native');
 
 var NUM_LEDS = 100,
 data = new Uint32Array(NUM_LEDS);
 
 ws281x.init(NUM_LEDS);
 
 data[42] = 0xff0000;
 ws281x.render(data);
 
 setTimeout(function() { ws281x.reset(); }, 2000); the javascript-side

Slide 40

Slide 40 text

hello ws281x-native ‣ API feels a bit too low-level ‣ numbers as colors are complicated ‣ need to manually manage the data-array of course it didn't end there

Slide 41

Slide 41 text

matrix-API var ws281x = require('../lib/ws281x'), m = ws281x.createMatrix(10,10)
 Color = ws281x.Color;
 
 var offset = 0, c1 = new Color('red'), c2 = new Color('blue');
 
 setInterval(function() {
 m.clear();
 for(var i=0; i<10; i++) {
 var color = Color.mix(c1, c2, ((i % 10) / 10));
 
 m.set(i%10, (i+offset)%10, color);
 }
 
 offset++;
 m.render();
 }, 1000 / 30); the javascript-side

Slide 42

Slide 42 text

awesomeness solutions arduino sleep solution awesomeness #hhjs program it in C on raspberry build a server in C and control with node write a node-addon. ✔

Slide 43

Slide 43 text

awesomeness solutions sleep solution awesomeness #hhjs program it in C on raspberry build a server in C and control with node write a
 node-addon. use

Slide 44

Slide 44 text

canvas-API ‣ web-technology FTW! ‣ has more stuff than we need. ‣ can be rendered server-side with node-canvas ‣ also works in the browser

Slide 45

Slide 45 text

canvas-API var ws281x = require('../lib/ws281x'),
 canvas = ws281x.createCanvas(10,10),
 ctx = canvas.ctx,
 Color = ws281x.Color;
 
 var c1 = new Color('red'), c2 = new Color('blue');
 
 function rnd(max) { return (max || 1) * Math.random(); }
 function rndi(max) { return Math.round(rnd(max)); }
 
 setInterval(function() {
 var c = Color.mix(c1,c2, rnd());
 
 ctx.clearRect(0,0,10,10);
 ctx.fillStyle = 'rgb(' + c.rgb.join(',') + ')';
 ctx.fillRect(rndi(10)-2, rndi(10)-2, rndi(10), rndi(10));
 
 canvas.render();
 }, 1000/5); the javascript-side

Slide 46

Slide 46 text

more to come… ‣ open-source everything [really soon] ‣ browser-based IDE on the raspberry [in progress] ‣ integrate with other hardware [planning] ‣ improved 3d-printed casing [some day…]

Slide 47

Slide 47 text

final thoughts ‣ do something you love. just for the fun. ‣ understand how stuff works. ‣ learn something new. ‣ no deadlines (well, except you do a talk about it) why would you want to do that?

Slide 48

Slide 48 text

thank you! come to me if you have any questions… <3 Martin Schuhfuss – @usefulthink