Problem when using Neopixels and PDM mic on RP2040

setup:

  • rp2040 connect
  • using GPIO pins and multicore feature (compiling with Arduino-Pico)
  • 8 neopixel strips with each 20 pixels

test goal:

  • use mic level to control amount of leds that light up

issue:
works fine when using less than 8 strips, more or equal to 8 NeoPixels declared and the board starts behaving abnormally.

my hypothesis:
memory problem but I have no way to prove it! Variables seem to only take 25% of available memory.

code:

#include <Adafruit_NeoPixel.h>
#define NUM_LED 20
#include <PDM.h>



  Adafruit_NeoPixel grid[] = {
  Adafruit_NeoPixel(NUM_LED, 15, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUM_LED, 16, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUM_LED, 17, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUM_LED, 18, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUM_LED, 19, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUM_LED, 20, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUM_LED, 21, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUM_LED, 28, NEO_GRB + NEO_KHZ800),

};

#define NUMSTRIPS (sizeof(grid)/sizeof(grid[0])) 

static const char channels = 1;
static const int frequency = 16000;
short sampleBuffer[64];
volatile int samplesRead;

int devider =900;
  



void setup() {
  PDM.onReceive(onPDMdata);
  if (!PDM.begin(channels, frequency)) {
    while (1);
  }
}



void setup1() {
  for(int i=0; i<NUMSTRIPS; i++)
  {
    grid[i].begin();
    grid[i].show();
  }
}


uint32_t lumens=0;
void loop() {
  if (samplesRead) {
    for (int i = 0; i < samplesRead; i++) {
      lumens = abs(sampleBuffer[i]/(2*devider));
      rp2040.fifo.push(lumens);
    }
    samplesRead = 0;
  }



}


uint32_t in_lumens = 0;
bool no_freeze = false;
void loop1() {

  no_freeze = rp2040.fifo.pop_nb(&in_lumens);

  if (no_freeze) {
    for(int i=0; i<NUMSTRIPS; i++)
    {
      grid[i].clear();
      grid[i].fill( grid[0].Color(12, 6, 10),0,1+ in_lumens);
      grid[i].show(); 
    }
  }
  else {
    while (1) {
      // if we're here it's not a good sign
      for(int i=0; i<NUMSTRIPS; i++) {grid[i].clear();grid[i].show();}
      delay(1000);
      for(int i=0; i<NUMSTRIPS; i++) {grid[i].fill( grid[0].Color(12, 1, 1),0,20);grid[i].show();}
      delay(1000);
      no_freeze = rp2040.fifo.pop_nb(&in_lumens);
      if (no_freeze) break;
      }
    } 
}


void onPDMdata() {
  int bytesAvailable = PDM.available();
  PDM.read(sampleBuffer, bytesAvailable);
  samplesRead = bytesAvailable / 2;
}

The current adafruit neopixel library uses the rp2040's "PIO" subsystem to drive the neopixels. One PIO state machine for each strip. There are 8 PIO State machines on the chip, so the library is limited to supporting 8 neopixel strips.

Older versions of the library (say, 1.8.2) reinitialized a single PIO for each strip, and shouldn't have the limitation.

Each Neopixel strip can contain more than thousand leds, so I wondered why do you needs 8 separate strips, if you using only 20 leds in each?

You can easily organize all your LEDs as one single strip at all.

Actually I designed my project to work with the library NEO_PXL8 and later found out this only works with 8 consecutive pins which are not available in arduino rp-2040 connect. So now it's too late to change that everything is soldered and sealed. I have to live with it until I do a full remake. I have no time for that now, I need it working soon so I decided to focus on the code instead, and this issue is blocking me.

This is a good hint. However it doesn't explain why PDM doesn't work at exactly 8 neopixels. So when I declare 8, the chip works and leds light up, but no pdm is being read. I then just tested with more than 8 and saw the board crashing and no longer visible as com port. Had to do a hard reset. But I will try an older version later and see if it helps.

Perhaps because PDM also needs PIO subsystem to work. So because only 8 PIOs available, to manage PDM work you can use no more than 7 strips.

Makes sense, thank you, I'll update when I test it.

unfortunately this did not work. version 1.8.2 won't work at all, the library starts supporting rp2040 from 1.10.2 as I found online, and that one doesn't help either, i still can't initialize more than 8 strips.

Then I think it's time to return to my question - do you need all 8 strips? In my opinion, 8 strips of 20 diodes and 4 strips of 40 each - are the same.
Of course, if you have already assembled the circuit, changing the connections will cause some inconvenience. But at the moment I don't see any other way you can finish the project.

yes I accepted that fact haha. I'm just testing with 7 strips now. As a fast solution I might quickly soldier the 7th strip to the 8th and use the last one with 40. Long term I will for sure question my choice of board and overall design. Hopefully the issue gets fixed by adafruit, I saw @westfw has posted the question in Github.

Changing only one strip to 40, and leaving the rest 20 is inefficient in the program sense
It seems to me that it would be more correct to change the design of the program and work with 4 strips of 40 diodes each ... and there is no need to wait for any corrections from adafruit ...

In general, people assemble such DIY on one single tape ...

And unless you srsly pressed for time, 1 strip of 160.

Work out the details in software.

I haven't, but the FastLED library lets a person configure conceptual strips as portions of the one real strip, all details handled.

So it depends on what kind of fun you like to have. Figure out the code for youself, or figure out how that feature of the library can be exploited.

a7

the real reason I chose 8 seperate strips and specefically the pxl8 library is fps, I intend to use the light while shooting a video and framerate is really critical. In the next iteration I think I won't change that, I would rather migrate to a board that supports the neo_pxl8 library.

So you srsly pressed for time!

And already doing the same kinda maths for addressing.

Nice library, filed under I learnt something today.

a7

What fps range do you plan to achieve in your device?
One strip of 160 leds can be updated in about of 200 fps - is it not enough to you?

as much as possible, it has to work with slow motion shots, above 120 to have flexibitity when dealing with camera Synchronisation.

it is not an answer.

120-240

With using 4 strips with 40 leds each your theoretical maximum fps will be about 500-700
It's only a matter of the efficiency of your code

I was getting 30-50 fps on a project with 8000 leds. To speed up, they were divided into 11 channels. There really was a question of speed...

fair enough. I mean I can't help but want more and more fps haha but that has dropped as a priority by quite a few steps.