- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
Using SPI, developed custom protocol using mraa TX commands only (spi->transfer) to communicate/address NeoPixel strip. My program loops through basic blinking light show (Strip = 7 NeoPixels), however at random intervals between 10-15s the application will hang. This occurs whether the NeoPixel strip is connected or not.
Some NeoPixel and Edison Protocol Background (Not sure relevant to issue, but reference for others trying to use NeoPixel)
- NeoPixel has strict HIGH-LOW timing requirements to transmit 24b/pixel (R=8bits-Neo, G=8bits-Neo, B=8bits-Neo).
- 0 bit = T0H = 0.4us, T0L = 0.85us (+/-150ns); 1 bit = TIH = 0.8us, TIL = 0.45us (+/-150ns)
- SPI->transfer requires u_int8_t* buffer.
- Encode using 3 SPI color bits equal 1 NeoPixel color bit. Therefore, every SPI color requires 3 bytes (R=24bits-SPI, G=24bits-SPI, B=24bits-SPI)
- At SPI = 2.5MHz, each bit interval equals 400us and given NeoPixel timing specification above.
- | 1 | 0 | 0 | = 0 NeoPixel bit (T0H = 400us, T0L = 800us) - within spec tolerance
- | 1 | 1 | 0 | = 1 bit (TIH = 800us, TIL = 400us) - within spec tolerance
- At SPI = 2.5MHz, each bit interval equals 400us and given NeoPixel timing specification above.
NeoPixel Specification: https://learn.adafruit.com/downloads/pdf/adafruit-neopixel-uberguide.pdf https://learn.adafruit.com/downloads/pdf/adafruit-neopixel-uberguide.pdf
Code
u_int8_t* lightshow_on_Neo[]; //Size = 21, Seven NeoPixels * 3 (R=8bits-Neo, G=8bits-Neo, B=8bits-Neo)
u_int8_t* lightshow_off_Neo[]; //All Zero, Size = 21, Seven NeoPixels * 3 (R=0, G=0, B=0)
u_int8_t* lightshow_on_SPI[]; //Size = lightshow_on_Neo* 3 (3 SPI color bits equal 1 NeoPixel color bit)
u_int8_t* lightshow_off_SPI[]; //All Zero, Size = lightshow_off_Neo* 3 (3 SPI color bits equal 1 NeoPixel color bit)
mraa::Spi* spi;
spi = new mraa::Spi(0);
spi->frequency(2500000);
PopulateLightShow_On(); //fill lightshow_on_Neo with RGB colors to display
PopulateLightShow_Off(); //fill lightshow_off_Neo with 0s
ConvertNeo_to_SPI(lightshow_on_Neo, &lightshow_on_SPI[0]); //convert to SPI format given NeoPixel timings
ConvertNeo_to_SPI(lightshow_off_Neo, &lightshow_off_SPI[0]); //convert to SPI format given NeoPixel timings
for (;;) {
spi->transfer(lightshow_on_SPI, NULL, sizeof(lightshow_on_SPI));
usleep(100000);
spi->transfer(lightshow_off_SPI, NULL, sizeof(lightshow_off_SPI));
}
Comments:
- After 10-15s the application will hang and unable to kill (e.g. htop, ps, kill) without resetting Edison.
- Tried with spi->write, but same result.
- Tried with different usleep values between On and Off, but same result.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
Hi,
Have you already seen these discussions on Neo Pixel?
?
Sergio
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
Hi Sergio, I looked at both links and unfortunately did not help with issue. The links are trying to use GPIO which thread concludes as not being fast enough or NeoPixel timings too tight. I think there is way to workaround with SPI and some simple byte encoding tricks.
The issue occurs whether NeoPixel is connected or not, so reason believe this is either SPI issue or the way I have SPI configured. I attached diagram of my circuit as well as simple code. Can you review to see if connecting and configuring correctly (only using Tx, no Rx). I also attached video (via Gyfcat) showing working state and failing state.....again failures are random, but generally happen after 3-4th attempt (single loop) or 10-15s if run loop continuously. Randomly fails using both SPI->Transfer and SPI->Write.
http://gfycat.com/AmusedHeartyAzurewingedmagpie http://gfycat.com/AmusedHeartyAzurewingedmagpie
Thanks.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
We'd like to try and reproduce your case. Can you share your full code and any additional testing information?
Sergio
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
Copied code below, please let me know if need anything else or questions. This assumes a NeoPixel array of 7 elements.
After executing, just enter number of RGB loops. Should work with 1 or 2 loops, but after few attempts or entering 5, 10, 20 as number of loops should FAIL every time. Thanks.
# include "mraa.hpp"
# include
using namespace std;
void ColorNeoPixelConversion(int* _input_buffer, u_int8_t _size, u_int8_t* _output_buffer);
void DecimaltoBinaryNeoPixel(u_int8_t _input_value, u_int8_t* _output_gbr);
void RunProgram(int);
int main() {
int loop;
std::cout << std::endl << "Enter Number of RGB Loops: ";
std::cin >> loop;
for (int j = 0; j < loop; j++) {
RunProgram(0); //Cycle through LED - Green
RunProgram(1); //Cycle through LED - Red
RunProgram(2); //Cycle through LED - Blue
RunProgram(3); //Cycle through LED - OFF
}
return 0;
}
void RunProgram(int _var)
{
int colorshow[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
//RGB placeholder for 7 Pixels = RGB (3 * 7 = 21);
uint8_t outputshow[63];
//Neopixel placeholder for 7 Pixels, 1 RGB pixel -> 3 NeoPixels
mraa::Spi* spi; //Initialize SPI
spi = new mraa::Spi(0);
spi->frequency(2500000); //Set SPI Frequency = 2.5MHz
for (int color = 0; color < 7; color++) {
for (int i = 0; i < 21; i++) { //Clear all LED RGB values to zero
colorshow[i] = 0;
}
if (_var < 3) {
colorshow[(color*3) + _var] = 64; //Increment next LED R or G or B index.
}
for (int neopixel = 0; neopixel < 7; neopixel++) {
std::cout << "Start_ConvertRGBtoNeo = " << neopixel << std::endl;
ColorNeoPixelConversion(colorshow, 7, &outputshow[0]);
std::cout << "End_ConvertRGBtoNeo = " << neopixel << std::endl;
}
std::cout << "Start_SPI_Transfer = " << color << std::endl;
spi->transfer(outputshow, NULL, sizeof(outputshow));
std::cout << "End_SPI_Transfer = " << color << std::endl;
usleep(60000);
}
delete spi;
}
void ColorNeoPixelConversion(int* _input_buffer, u_int8_t _size, u_int8_t* _output_buffer)
{
int dec_index = 0;
uint8_t neo_index = 0;
int dec_byte = 0;
uint8_t neo_byte[3];
// | G1 R1 B1 | G2 R2 B2 | G3 R3 B3 | G4 R4 B4 | G5 R5 B5 |
for (int i = 0; i < _size; i++) { //number of neopixels (9 neo bytes per color)
for (int j = 0; j < 3; j++) { //number of bytes per neopixel
dec_index = (i*3) + j;
dec_byte = _input_buffer[dec_index];
DecimaltoBinaryNeoPixel(dec_byte, &neo_byte[0]);
neo_index = (i*9) + (j*3);
_output_buffer[neo_index + 0] = neo_byte[0];
_output_buffer[neo_index + 1] = neo_byte[1];
_output_buffer[neo_index + 2] = neo_byte[2];
}
}
}
void DecimaltoBinaryNeoPixel(u_int8_t _input_value, u_int8_t* _output_gbr)
{
uint8_t bin_operator[] = {128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1};
_output_gbr[0] = 0; _output_gbr[1] = 0; _output_gbr[2] = 0;
uint8_t decbyte_index = 0;
uint8_t neobyte_index = 0;
// 7 6 5 4 3 2 1 0
// 100 100 10 | 0 100 100 1 | 00 100 100
for (int k = 0; k < 3; k++) { //decimal 7, 6, 5
if (_input_value & bin_operator[decbyte_index]) {
_output_gbr[0] |= bin_operator[neobyte_index+0];
_output_gbr[0] |= bin_operator[neobyte_index+1];
}
else {
_output_gbr[0] |= bin_operator[neobyte_index+0]; //Bit 8 (decimal 5) is always zero.
}
decbyte_index += 1;
neobyte_index += 3;
}
//decbyte = 3, neobyte_index = 9
for (int k = 0; k < 2; k++) { //decimal 5, 4, 3, 2
if (_input_value & bin_operator[decbyte_index]) {
_output_gbr[1] |= bin_operator[neobyte_index+0];
_output_gbr[1] |= bin_operator[neobyte_index+1];
}
else {
_output_gbr[1] |= bin_operator[neobyte_index];
}
decbyte_index += 1;
neobyte_index += 3;
}
_output_gbr[1] |= bin_operator[neobyte_index]; //Bit 15 (decimal 2) is always one.
neobyte_index += 1;
//decbyte = 5, neobyte_index = 16
if (_input_value & bin_operator[decbyte_index]) { //decimal 2, 1, 0
_output_gbr[2] |= bin_operator[neobyte_index+0];
}
decbyte_index += 1;
neobyte_index += 2;
//decbyte = 6, neobyte_index = 18
for (int k = 0; k < 2; k++) {
if (_input_value & bin_operator[decbyte_index]) {
_output_gbr[2] |= bin_operator[neobyte_index+0];
_output_gbr[2] |= bin_operator[neobyte_index+1];
}
else {
_output_gbr[2] |= bin_operator[neobyte_index];
}
decbyte_index += 1;
neobyte_index += 3;
}
//decbyte = 8, neobyte_index = 24
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
After performing some tests we ran into the same issues as you. The SPI driver has known issues with performance in current release; that is the reason why some SPI devices do not work properly with the Edison board.
Sergio

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page