Category Archives: spi

Raspberry Pi A+ Update

wpid-20150728_112955-1.jpg

Today I have completed the initial set up of my RPi A+. Wow that took a while. I needed a specific set of tools ready on the device:

  • Network connected via WiFi
  • Basic Apache install to host the Client interface page
  • Basic FTP to simplify uploading code and files
  • Node JS to run the Wow Suit software
  • Node-SPI module to enable NodeJS to use the SPI port on the device

Installing and configuring Node and the SPI modules was the MOST difficult part. I was initially planning on using the MRAA module, but it has so many prerequisites and build failures that i bailed on it. I may go back to it if the current node module I’m using does not suffice.

This post was by the far the only advise that worked on the A+ board. I initially attempted to compile the latest version of NodeJS directly but the board kept crashing mid way. So I’m copying the instructions here for anyone else and for future reference for myself:

                     Update apt-get
sudo apt-get update
                     Upgrade apt-get
sudo apt-get upgrade
                     Download the latest node build
wget http://node-arm.herokuapp.com/node_latest_armhf.deb
                     Install the package using dpkg
sudo dpkg -i node_latest_armhf.deb
                     Test Node and NPM
node -v
npm -v

At this point Node works perfectly as well as npm. Now on to the next issue. SPI!

This is the “pi-spi” nodejs module. It is the ONLY one that would compile and run. I have not yet tested that it works as I’m at the office, but its good to know that it compiles and runs!

Rendering a Line in a 2D bitmap…who would have thought that was hard? Here is some code I hacked up from the Rosetta archive lineTest

My new Raspberry Pi A+

Its s nice little device. No bullshit set up. Easy to use Linux…WiFi was a bit difficult but that is because of Linux. Setting up the standard stuff like FTP, Apache etc.. easy! Getting NodeJS to work with MRAA…..oh lord.

//Get the latest version of node from the node web site
wget http://nodejs.org/dist/v0.10.28/node-v0.10.28-linux-arm-pi.tar.gz
//extract it
tar -xzf node-v0.10.28-linux-arm-pi.tar.gz
//set the mraa path manualy if https fails
sudo npm config set registry http://registry.npmjs.org/
//install mraa
sudo npm install mraa
//wait a long time....

Driving an LED Strip with SPI

Driving Chart for the WS28XX series ICs

WS2811 ws2811 0
0.5μs H
2.0μs L1
1.2μs H
1.3μs LReset Time
Above 50μs
 WS2812B  ws2811 0
0.40μs H
0.85μs L1
0.85μs H
0.40μs LReset Time
Above 50μs

Because I would like to use the Galileo, I’m limited in not being able to use the FastLED library, as its intended for AVR.  One approach is to use SPI at a very high frequency, and send whole Byte sequences to imitate a tight timing sequence for the above:

For the WS2811 1 bit is transmitted in 2.5μs. So if We set up an SPI driver to push out the 8 bit number 255 , 11111111 in binary, at 400khz

ws2911spiex1

Now as a whole pulse that’s useless to us. Because we need to pulse a HIGH and LOW in a specific pattern. To do this, we can mimic the signal by increasing the SPI frequency and sending in BYTES with specific patterns. For example If we double the frequency to 800Khz we can now send in 2 bytes in the same time frame. So if we send in a 255 and a 0:

ws2911spiex2

We get the above. Which is almost to a point where we can start making up masks. In the above example each BYTE, that’s 8 bits, takes 1.25μs to transmit, and looks like a continuous HIGH signal for that amount of time. This means that each BIT takes 1.25μs/8 = 0.15625μs to transmit…

ws2911spiex3

To get a correctly timed pulse for the WS2811 we will need to adjust a few things. 1st we need to find out a nice round number for each Bit to sent out at.  We need to be able to add multiple bits transmition time together to get exactly 1.2μs and 1.3μs. As well as 0.5μs and 2μs. For example…

Time Required for 1 Bit to Transmit = 0.1μs

Time required for 1Byte = 0.8μs

At 1,250,000Hz a single Byte takes 0.8μs to transmit and a Single bit takes 0.1μs to transmit. So…

ws2911spiex4

Above we transmitted 4Bytes over SPI [255,240,0,0] to get a Logic 1

ws2911spiex5And here we transmitted 4Bytes over SPI [248,0,0,0] to get Logic 0

What this means is that we have to transmit 4 Bytes for each BIT in a standard Byte of representation Data. If I have to control 1 LED i need 3 bytes to control Red, Green and Blue. That means I need:

3bytes x 8bits x 4spi-block-bytes = 96Bytes per LED!!!! With my current suit layout that has 288 RGB LEDs, I need 864 Bytes of control data. With the Above protocol, ill need 27,648 Bytes per FRAME….Now what I’m getting at here is that Using SPI to control these drivers is probably not a great idea. It will take 22.1184 milliseconds per frame which is at best around 5 frames per second.

My other concern is that the Galileo probably wont allow such tight control over the SPI frequency. I will be able to set it at 1mhz and 2mhz but not anywhere in between with any kind of certainty. I spent some time on my oscilloscope last night to see if the SPI frequency actually changes in between MHz but saw no difference unless the change was significant .

Here is the same diagrams but using the WS2812B timing, which is the same as the WS2811 but using the double data rate:

Set SPI to 2,500,000Hz Use 4SPI Bytes per LED BYTE:

To send  Logic 1 you send [255,255,128,0]

ws2812sendhighTo send Logic 0 you send [255,0,0,0]

ws2812sendlow

I can confirm that the 144LED strips uses fast mode… This was sent ot me directly from WorldSemi

“The 144LED Strip uses the WS2812B chipset(built-in IC), and HIGH speed mode”

Their Web page states they use the WS2811 chip but they also say that they use High Speed  mode in prepackaged systems… Using High Speed mode I can get maybe 10 frames per second with the same number of LEDs.

Here is some NodeJS code I wrote that will grab an array of Bytes and create a Buffer() of bytes with the appropriate bit pattern to be pushed out to the SPI bus.

var ledBytes = 1*3;
var ledBar = new Array(ledBytes);
var aBuffer = new Buffer(0);
var counter = 0;

init();
runMain();

function init()
{
 //clear the led array
 clearSuit();
}

function runMain()
{
 var testBuffer = WS2811b_SPI();
 
 for(counter=0; counter<testBuffer.length; counter++)
 {
 console.log("Index "+counter+"->"+testBuffer[counter]);
 }
 
}

function WS2811b_SPI()
{
 var spiBuffer = new Buffer(ledBytes*8*4);
 var currentByteSPIBlock = new Buffer(8*4);
 var spiBufferIndex = 0;
 
 for(counter=0; counter<ledBytes; counter++)
 {
 currentByteSPIBlock = createSPIBlockFromByte(ledBar[counter]);
 currentByteSPIBlock.copy(spiBuffer,spiBufferIndex,0,currentByteSPIBlock.length);
 spiBufferIndex+=currentByteSPIBlock.length;
 }
 return spiBuffer;
}

function createSPIBlockFromByte(dataToPush)
{
 var mask=1, bitResult=0, cnt=0, bufferIndex=0; 
 var tempBuffer = new Buffer(4*8);
 var spiBlock = new Buffer(4);
 
 mask = mask << 7; 
 for(cnt=0; cnt<8; cnt++) 
 { 
 bitResult = dataToPush & mask; 
 bitResult = bitResult >> (7-cnt); 
 spiBlock = createSPIBit(bitResult);
 spiBlock.copy(tempBuffer,bufferIndex,0,spiBlock.length);
 bufferIndex+=spiBlock.length;
 mask = mask >> 1; 
 } 
 return tempBuffer;
 
}

function createSPIBit(value)
{
 var spiBitBlock = new Buffer(4);
 
 if(value==1)
 {
 spiBitBlock[0] = 255;
 spiBitBlock[1] = 255;
 spiBitBlock[2] = 128;
 spiBitBlock[3] = 0;
 }
 else
 {
 spiBitBlock[0] = 255;
 spiBitBlock[1] = 0;
 spiBitBlock[2] = 0;
 spiBitBlock[3] = 0;
 }
 return spiBitBlock;
}

function clearSuit()
{
 for(counter=0; counter<ledBytes; counter++)
 {
 ledBar[counter] = 0;
 }
}