Problem with parallel GPIO pins and NeoPixels
Posted: Sun Jan 28, 2018 6:11 pm
Hi, I cut a 5m 300 LED strip into 10 strips of 30 LEDs each, and attached each strip to one of the GPIO pins 5,16,17,18,19,23,25,26,2,4.
Then I added a setpin(pin) function to the NeoPixel library, and programmed the strips in an outer loop, setting the pin, and an inner loop, for the 30 LED. This works nicely. Then I got the idea to bitbang all 10 pins in parallel. The (somewhat stripped down) code for this follows:
where rowLen is 30*4 for 30 Leds, 4 bytes/pixel for RGBW.
The idea is to set all pins high first, then clear all pins where the corresponding pixel bit is 0 after T0
This code shows very strange behaviour. If I set all 300 pixels to the same color, it works ok.
If I just set one line, e.g. to pure red, with values from 1 to 255, it shows the line, but in all possible
colours, depending on the value, e.g. blue with some white, and also neighboring lines have sometimes some Leds
set as well, often around column 21.
I tried a lot with the numbers for the CYCLES*-variables, or setting PULLUP or PULLDOWN together with OUTPUT,
but no effect. I notice some effect when I configure less than 10 lines. To me it looks a bit like crosstalk between the lines.
The power supply is 5v/20A, the ESP powered by USB, and ESP ground connected to power ground at a middle line,
All VCC and ground pins of the strips are connected together on the input side of the strips, the pins on the other side are
open.
I checked the code over and over again, dumping all the values, inspecting the pinRegLow values, for many hours,
and slowly reach the conclusion that it must be an electrical or timing problem.
I have not seen a GPIO initialzation taken place, but in the NeoEspBitBangMethodBase constructor pinMode(pin, OUTPUT) is called for all pins. Please remember, that everything works fine, if I set all pixels to the same value, i.e. pinRegLow is 0 or pinRegHigh.
Suggestions are very welcome!
Thank you, Michael
Then I added a setpin(pin) function to the NeoPixel library, and programmed the strips in an outer loop, setting the pin, and an inner loop, for the 30 LED. This works nicely. Then I got the idea to bitbang all 10 pins in parallel. The (somewhat stripped down) code for this follows:
Code: Select all
void ICACHE_RAM_ATTR bitbang_send_pixels_800(uint8_t* pixels, uint16_t rowLen, uint16_t numPins, uint8_t* pins)
{
uint32_t pinRegisters[numPins];
uint8_t mask;
uint8_t subpix;
uint32_t cyclesStart;
uint8_t *endp = pixels + rowLen; // end of first row
uint32_t bv;
uint32_t pinRegHigh = 0;
for (uint16_t px = 0; px < numPins; px++) {
bv = _BV(pins[px]);
pinRegisters[px] = bv;
pinRegHigh |= bv;
}
// trigger immediately
cyclesStart = _getCycleCount() - CYCLES_800;
do
{
for (mask = 0x80; mask != 0; mask >>= 1) {
uint8_t *pixp = pixels;
uint32_t pinRegLow = 0;
for (uint16_t px = 0; px < numPins; px++) {
subpix = *pixp;
pixp += rowLen;
if ((subpix & mask) == 0)
pinRegLow |= pinRegisters[px];
}
uint32_t cyclesNext = cyclesStart;
do {
cyclesStart = _getCycleCount();
} while ((cyclesStart - cyclesNext) < CYCLES_800); // 300
GPIO.out_w1ts = pinRegHigh;
do {
cyclesNext = _getCycleCount();
} while ((cyclesNext - cyclesStart) < CYCLES_800_T0H); // 96
GPIO.out_w1tc = pinRegLow;
do {
cyclesNext = _getCycleCount()
} while ((cyclesNext - cyclesStart) < CYCLES_800_T1H); // 192
GPIO.out_w1tc = pinRegHigh;
}
pixels++;
} while (pixels < endp);
}
The idea is to set all pins high first, then clear all pins where the corresponding pixel bit is 0 after T0
This code shows very strange behaviour. If I set all 300 pixels to the same color, it works ok.
If I just set one line, e.g. to pure red, with values from 1 to 255, it shows the line, but in all possible
colours, depending on the value, e.g. blue with some white, and also neighboring lines have sometimes some Leds
set as well, often around column 21.
I tried a lot with the numbers for the CYCLES*-variables, or setting PULLUP or PULLDOWN together with OUTPUT,
but no effect. I notice some effect when I configure less than 10 lines. To me it looks a bit like crosstalk between the lines.
The power supply is 5v/20A, the ESP powered by USB, and ESP ground connected to power ground at a middle line,
All VCC and ground pins of the strips are connected together on the input side of the strips, the pins on the other side are
open.
I checked the code over and over again, dumping all the values, inspecting the pinRegLow values, for many hours,
and slowly reach the conclusion that it must be an electrical or timing problem.
I have not seen a GPIO initialzation taken place, but in the NeoEspBitBangMethodBase constructor pinMode(pin, OUTPUT) is called for all pins. Please remember, that everything works fine, if I set all pixels to the same value, i.e. pinRegLow is 0 or pinRegHigh.
Suggestions are very welcome!
Thank you, Michael