I've been developing code to send data to 16 strips of WS2812B pixels and I have it working.
The code requires transposing bits in the main pixel array that is in row-major order to instead be column major order.
This is done using the following:Since the data being sent to PIO through DMA is 16 bits, I would have expected the LSM bit to be in the 2nd byte in the 16 bit block and the 8th bit be the 1st byte, but it is actually the opposite.
Example: lets say first pixel row contains all 1's and the remaining 15 rows contain all 0's.
Then what the 16 bits sent to PIO would be 0b0000000 000000001
Thus what I would expect should be in dst should be 0b00000000 000000001 where the 1 is in the 2nd byte of the array pointed to by dst and the first byte be all 0's: 0b00000000 00000001 0b00000000 00000001
But it seems the first dst byte needs to contain the low order bits of the 16 bit word:
0b00000001 00000000 0b0000001 00000000
I have some concept of endian, but since the bits are sent serially through OSR in PIO, I would think the bits would have to be in exact sequential order, and not byte swapped.
Can anyone explain this?
If I were to expand to 32 bits sent to PIO, how would each byte in dst be represented for the 32 bit word?
The code requires transposing bits in the main pixel array that is in row-major order to instead be column major order.
This is done using the following:
Code:
void Adafruit_NeoPXL16GFX::stage(void) { uint8_t bytesPerLED = (wOffset == rOffset) ? 3 : 4; uint32_t pixelsPerRow = numLEDs / 16, bytesPerRow = pixelsPerRow * bytesPerLED, i;#if defined(ARDUINO_ARCH_RP2040) memset(dmaBuf[dbuf_index], 0, numLEDs * bytesPerLED); for (uint8_t b = 0; b < 8; b++) { // For each output pin 0-7 uint16_t mask = bitmask[b]; if (mask) { // Enabled? uint8_t *src = &pixels[b * bytesPerRow]; // Start of row data uint8_t *dst = dmaBuf[dbuf_index]; for (i = 0; i < bytesPerRow; i++) { // Each byte in row... // Brightness scaling doesn't require shift down, // we'll just pluck from bits 15-8... uint8_t value = ((*src++ * brightness)>>8); if (value & 0x80) dst[0] |= mask; if (value & 0x40) dst[2] |= mask; if (value & 0x20) dst[4] |= mask; if (value & 0x10) dst[6] |= mask; if (value & 0x08) dst[8] |= mask; if (value & 0x04) dst[10] |= mask; if (value & 0x02) dst[12] |= mask; if (value & 0x01) dst[14] |= mask; dst+=16; } } } for (uint8_t b = 8; b < 16; b++) { // For each output pin 8-15 uint16_t mask = (bitmask[b]>>8); if (mask) { // Enabled? uint8_t *src = &pixels[b * bytesPerRow]; // Start of row data uint8_t *dst = dmaBuf[dbuf_index]; for (i = 0; i < bytesPerRow; i++) { // Each byte in row... // Brightness scaling doesn't require shift down, // we'll just pluck from bits 15-8... uint8_t value = ((*src++ * brightness)>>8); if (value & 0x80) dst[1] |= mask; if (value & 0x40) dst[3] |= mask; if (value & 0x20) dst[5] |= mask; if (value & 0x10) dst[7] |= mask; if (value & 0x08) dst[9] |= mask; if (value & 0x04) dst[11] |= mask; if (value & 0x02) dst[13] |= mask; if (value & 0x01) dst[15] |= mask; dst+=16; } } }#endif // end ARDUINO_ARCH_RP2040 staged = true;}
Example: lets say first pixel row contains all 1's and the remaining 15 rows contain all 0's.
Then what the 16 bits sent to PIO would be 0b0000000 000000001
Thus what I would expect should be in dst should be 0b00000000 000000001 where the 1 is in the 2nd byte of the array pointed to by dst and the first byte be all 0's: 0b00000000 00000001 0b00000000 00000001
But it seems the first dst byte needs to contain the low order bits of the 16 bit word:
0b00000001 00000000 0b0000001 00000000
I have some concept of endian, but since the bits are sent serially through OSR in PIO, I would think the bits would have to be in exact sequential order, and not byte swapped.
Can anyone explain this?
If I were to expand to 32 bits sent to PIO, how would each byte in dst be represented for the 32 bit word?
Statistics: Posted by DanMan32 — Sun Jan 07, 2024 3:21 am