Compile errors with Neopixel library and Dotstar library on Raspberry Pi


#21

The datasheet I linked above show how the backup data is supposed to be used, but since there are two ways to do it, you’d need to check which one the strip is using.
But in general I’d say you won’t need the BIN contact at all, it’s only there for daisy chaining strips.


#22

OK @ScruffR , here we are again, earlier than expected!
My 1 meter strip of APA102 pixels arrived today:

I have connected them to the (hardwire) SPI pins A3/A5:

Then I uploaded your simplified sketch (above) but nothing is happening…
When I upload the sample sketch available with the “Adafruit Dotstar” library, it shows a lighttrain of 10 dots changing from RED to GREEN and BLUE continuously. So, the strip is OK and so are my connections…

As I would like to use these dots for my “status panel”, driven from an RPi, I would prefer to use your approach…

Any idea what I could try?

:hand::older_man:


#23

I’ll look into it.


Update:
Looking at the code in this post
You never set needRefresh to true and hence the strip will never be actually updated.

Here you can find the intent of the two flags needRefresh and canRefresh

BTW, with 1m of that strip you should also change the settings at the top of your sketch correctly
Instead of

#define LEDCOUNT 300
uint32_t pxBuffer[LEDCOUNT];
// actually for the APA102 protocol you need some extra bytes for leadin/leadout
//uint32_t pxBuffer[1 + LEDCOUNT + LEDCOUNT/16 + 1]; // element 0 (leadin) ... LEDs ... 1 leadout clock per 2 LEDs (ceil)

you need

const int LEDCOUNT = 144;
uint32_t pxBuffer[1 + LEDCOUNT + LEDCOUNT/16 + 1]; // element 0 (leadin) ... LEDs ... 1 leadout clock per 2 LEDs (ceil)

#24

I wished I could follow you, but I am not experienced enough to fully understand all steps in this sketch. I’m trying…

The sketch I started from (above) was copied from your post: LINK

With your remarks, I edited it as below but now only the first led turns magenta and it stays…:

/* Replace these lines by lines below it
#define LEDCOUNT 144
uint32_t pxBuffer[LEDCOUNT];
// actually for the APA102 protocol you need some extra bytes for leadin/leadout
//uint32_t pxBuffer[1 + LEDCOUNT + LEDCOUNT/16 + 1]; // element 0 (leadin) ... LEDs ... 1 leadout clock per 2 LEDs (ceil)
*/

const int LEDCOUNT = 144;
uint32_t pxBuffer[1 + LEDCOUNT + LEDCOUNT/16 + 1]; // element 0 (leadin) ... LEDs ... 1 leadout clock per 2 LEDs (ceil)


// bool needRefresh; // Use for dynamic pattern...
bool needRefresh = true; // Use for static pattern: Make it true again when you want to refresh another pattern.
volatile bool canRefresh = true;




void setup()
{
  SPI.begin();
  SPI.setClockSpeed(8, MHZ);
  //SPI.setDataMode(0);
  SPI.setBitOrder(MSBFIRST);
}




uint32_t setAPA102Color(int px, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness = 31)
{
  uint32_t color = 0;
  
  // due to big endianness in reverse order 
  color |= (brightness <<   0) | 0xE0;  //top 3 bits must be 111
  color |= (r          <<   8);
  color |= (g          <<  16);
  color |= (b          <<  24);

  pxBuffer[px] = color;

  return color;
}




void refreshDone()
{
  canRefresh = true;
}





void loop()
{
  // setup your pixels
  setAPA102Color(8, 30, 100, 40, 31);  // = Approx. "Set LED #8 colour to 15% RED, 50% GREEN and 20% RED, max brightness"
  setAPA102Color(67, 40, 0, 0, 31);    // = Approx. "Set LED #67 colour to 20% RED, max brightness"
  setAPA102Color(88, 40, 0, 140, 31);  // = Approx. "Set LED #88 colour to 20% RED and 70% BLUE, max brightness"
  
  needRefresh = true; // Test!
  
  if (needRefresh && canRefresh)
  {
    canRefresh = needRefresh = false;
    SPI.transfer(pxBuffer, NULL, sizeof(pxBuffer), refreshDone);
  }

  delay(2000); // Slow down loop...
}

:thinking:


#25

You can initialise needRefresh to be true on startup like this

bool needRefresh = true;

Currently it’s by default false.

But that would only help if you had a static pattern you want to display.
Whenever you intend to change the pattern, you need to set needRefresh = true again after you are finished updating the content of the buffer.

But you need to leave canRefresh alone, since that is in fact set by the refreshDone function after the transfer from the buffer to the strip is done.

So you need to revert back to

  if (needRefresh && canRefresh)
  {
    canRefresh = 
    needRefresh = false;
    SPI.transfer(pxBuffer, NULL, sizeof(pxBuffer), refreshDone);
  }

Otherwise you’d over and over start the transfer potentially even before it’s actually finished.
That’s the whole point of canRefresh to prevent that from happening.

BTW, unlike the comment, canRefresh wasn’t “incomplete” or “blank”, but this is just a lazy way to set multiple variables to the same value and could be written like that (which might be clearer to understand)

  canRefresh = needRefresh = false;

This would verbally mean: "Assign false to needRefresh and assign that in turn to canRefresh" (assignment execution in right to left order).


#26

I edited the sketch (and replaced the one in my previous post) reverted to the “lazy” lines :wink: and now there is an extra ‘refresh’ line in the loop():

  needRefresh = true;

Result: Now only the first led turns magenta and it stays like that…


#27

For me the sketch works as intended but you can try this which allows you to set each individual LED via a Particle.function()

const int LEDCOUNT = 144;
uint32_t pxBuffer[1 + LEDCOUNT + LEDCOUNT/16 + 1]; // element 0 (leadin) ... LEDs ... 1 leadout clock per 2 LEDs (ceil)

bool needRefresh = true;
volatile bool canRefresh = true;

int      setLEDs(const char* arg); // format "pixel,r,g,b[,brightness]"
void     refreshDone();
uint32_t setAPA102Color(int px, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness = 31);

void setup()
{
  Particle.function("setLED", setLEDs);
  setLEDs("all off");
  
  SPI.begin();
  SPI.setClockSpeed(8, MHZ);
  //SPI.setDataMode(0);
  SPI.setBitOrder(MSBFIRST);
}

void loop()
{
  if (needRefresh && canRefresh)
  {
    canRefresh = 
    needRefresh = false;
    SPI.transfer(pxBuffer, NULL, sizeof(pxBuffer), refreshDone);
  }
}

int setLEDs(const char* arg)
{
  int px  = 0;          // default all LEDs
  int px_ = LEDCOUNT;   // 
  int br  = 31;         // full brightness
  int r   = 0;          // but now colour
  int g   = 0;          //
  int b   = 0;          //
    
  if (sscanf(arg, "%d,%d,%d,%d,%d", &px, &r, &g, &b, &br) >= 4)
  {
    
    if (px > 0)         // set LED with number px
      px_ = px + 1;
    else if (px < 0)    // set LEDs 1 .. px
    {
      px_ = abs(px);
      px = 0;
    }
  }

  for (; px < px_; px++)
    setAPA102Color(px, r, g, b, br);

  needRefresh = true;

  return px;
}

void refreshDone()
{
  canRefresh = true;
}

uint32_t setAPA102Color(int px, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness)
{
  uint32_t color = 0;
  
  // due to big endianness in revers order 
  color |= (brightness <<   0) | 0xE0;  //top 3 bits must be 111
  color |= (b          <<   8);
  color |= (g          <<  16);
  color |= (r          <<  24);

  pxBuffer[px] = color;

  return color;
}

With arguments

  • 10,255,0,128,31 would set pixel #10 to 100% red, 0% green, 50% blue, 100% brightness
  • -20,128,128,0,15 would set pixels #1#20 to 50% red, 50% green, 0% blue, 50% brightness
  • 0,0,0,255 would set all LEDs to 0% red, 0% green, 100% blue and default to 100% brightness
  • any other parameter that doesn’t follow above standard will switch all LEDs off

Notice, while the colour components range 0 … 255 the brighness only allows values ranging 0 … 31.


#28

WOW! :heart_eyes:

This is exactly what I need @ScruffR !
I can use it also with a normal function and it works like a charm!!!

Thanks for this great sketch, I will try to use it straight away with the RPi!
Only, I am not sure if I can connect the strip the same way like the Photon…
The Rpi is not 5V tolerant…
So, I should protect the SPI ports, right?

:wave::older_man:


#29

There are variations of course (zener diodes, level converters etc…) but this is the simple protection method I 'd like to use for ALL RPI GPIOs:

28

Any comments somebody?


#30

For one, this is a silicon diode, so it has a forward voltage of ~0.7 V which will allow the voltage on the GPIO rise to ~4.0V before the diode actually opens and then you are back-feeding ~4.3V into the 3.3V out side of the regulator, which might not be happy with it (the Particle device’s regulators will definetly not, and since the µC sits on the same rail it won’t be either).

I can’t talk for the RPi’s regulator, but I’d at least go for a Germanium Schottky diode which will have a forward voltage of only ~0.2V


#31

That’s right @ScruffR, I hesitate also, but I read in a RPi blog that this should be fine…

Is there an IC with 8 or so bidirectional logic level shifters?


#32

Yes, there are some.
That’s one of them http://www.ti.com/lit/ds/symlink/txb0108.pdf


#33

Great tip @ScruffR, thanks!
I ordered these for $1/pce:
22
:ok_hand:


#34

Hey @ScruffR, this is really a great way to control these Dotstars.
But is there a possibility to also control the first led in a string?

When the following Particle.function() arguments are sent “1,255,0,0,31” the second led turns RED.
With “0,255,0,0,31” they ALL turn RED…

:thinking:


#35

Hmm, of course it’s possible, but when I tested I had the impression 1 did turn on the first LED.
If it doesn’t on your strips, you can always adapt the code that does the parsing.

e.g. like this

 if (sscanf(arg, "%d,%d,%d,%d,%d", &px, &r, &g, &b, &br) >= 4)
  {
    
    if (px > 0)         // set LED with number px
      px_ = px--;
    else if (px < 0)    // set LEDs 1 .. px
    {
      px_ = abs(px);
      px = 0;
    }
  }

#36

Thanks again for the tip!
On the road till sunday evening…
I’ll try as soon as I’m back in town…
:+1::sun_with_face:


#37

Hi @ScruffR, here we are again under a clear sky full of great DOTSTARs…

Starting from your above sketch, remotely controlling DOTSTARS with a Particle function, I modified it to set the colour and brightness of individual LEDs for my “status panel” (to be connected to a Raspberry Pi)

Below sketch “kinda works”, but not fully yet:
Colour and intensity of the leds is OK, but not the correct pixel Nr. is transmitted to the strip.
( See my comment in the loop() )

const int LEDCOUNT = 70;
uint32_t pxBuffer[1 + LEDCOUNT + LEDCOUNT/16 + 1];
uint32_t setAPA102Color(int px, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness = 31);



void setup()
{
  SPI.begin();
  SPI.setClockSpeed(8, MHZ);
  SPI.setBitOrder(MSBFIRST);

  for (int px = 0; px < LEDCOUNT; px++)
    pxBuffer[px] = 0x000000E0;

  setAPA102Color(-1,0,0,0,31); // Initializing the strip...



void loop()
{
// TEST: Alternate the colours for 3 LEDs to RED and BLUE...
    // ATTENTION: I expect #40,41 & 41 to respond, but instead, #0,1,2 respond... Troubleshoot!
  setAPA102Color(40,0,0,30,5); delay(1000);
  setAPA102Color(41,0,0,30,5); delay(1000);
  setAPA102Color(42,0,0,30,5); delay(1000);

  setAPA102Color(40,30,0,0,5); delay(1000);
  setAPA102Color(41,30,0,0,5); delay(1000);
  setAPA102Color(42,30,0,0,5); delay(1000);
}



uint32_t setAPA102Color(int px, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness)
{
  uint32_t color = 0;

  color |= (brightness <<   0) | 0xE0;
  color |= (b          <<   8);
  color |= (g          <<  16);
  color |= (r          <<  24);

  pxBuffer[px] = color;

  SPI.transfer(pxBuffer, NULL, sizeof(pxBuffer), NULL);

  return color;
}

Thanks for any tip which can point me in the right direction again…

BTW: Sorry for the blocking “delay()” commands again… :wink:

:older_man::+1:


#38

You need to first “initialise” the pxBuffer.
For each LED in the strip you need to pre-set the 0xE0.

This is what setLEDs() (in my original code) would do when you send a negative px number or pass invalid parameters.
So calling setLEDs("-1,0,0,0,31") in setup() should do the trick.

Or what I actually already had written in my original code …

… that wasn’t there for decorational purposes but had functional siginificance :wink:


#39

OK, thanks for your reply, but I am not using the setleds() particle function in this sketch…

I’d like to use the setAPA102Color() function directly to control each individual strip from within the loop() or from another function.


#40

Then you need to mimik its behaviour for initialisation :wink: