Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Chris_S_Intel
Employee
1,670 Views

NeoPixel Working on Edison, but SPI Locking Up

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

         

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.

     

5 Replies
Sergio_A_Intel
Employee
53 Views

Hi,

Have you already seen these discussions on Neo Pixel?

?

Sergio

Chris_S_Intel
Employee
53 Views

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.

Sergio_A_Intel
Employee
53 Views

We'd like to try and reproduce your case. Can you share your full code and any additional testing information?

Sergio

Chris_S_Intel
Employee
53 Views

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

}

Sergio_A_Intel
Employee
53 Views

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

Reply