5 Replies Latest reply on Dec 4, 2015 7:34 AM by Intel_Alvarado

    NeoPixel Working on Edison, but SPI Locking Up

    flux2002

      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

       

      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.
        • 1. Re: NeoPixel Working on Edison, but SPI Locking Up
          Intel_Alvarado

          Hi,

           

          Have you already seen these discussions on Neo Pixel?

          Re: Edison/Neopixel, memory mapped gpio speed

          WS2812 (NeoPixel) support? ?

           

          Sergio

          • 2. Re: NeoPixel Working on Edison, but SPI Locking Up
            flux2002

            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

             

            Thanks.

            Edison_NeoPixel_SPI_Setup.jpgCode_SPI_Transfer_Crash.jpg

            • 3. Re: NeoPixel Working on Edison, but SPI Locking Up
              Intel_Alvarado

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

               

              Sergio

              • 4. Re: NeoPixel Working on Edison, but SPI Locking Up
                flux2002

                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 <iostream>

                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

                }

                • 5. Re: NeoPixel Working on Edison, but SPI Locking Up
                  Intel_Alvarado

                  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