Can the PIO perform 888 RGB to 565 RGB?

In my latest RP2040 project I'm using a little ST7789 based LCD screen, who's pixel format is 565 RGB, and I would like to run this screen as fast as possible. It's capable of 60 FPS, which requires the RP2040's fastest SPI clock of 62.5 MHz, which is possible with PIO.

My graphics algorithms running on the RP2040 are working with 888 RGB internally. Before the image can be clocked into the screen, it needs to be converted from 888 to 565 format.

This is my inner loop that performs the conversion and sends the bytes to the SPI peripheral:

``````volatile uint8_t* screen_spi = (volatile uint8_t*)&pio->txf[sm];

for (int i = 0; i < width*height; i++)
{
unsigned short r5 = *rp;
unsigned short g6 = *gp;
unsigned short b5 = *bp;
rp += 3;
gp += 3;
bp += 3;

union16_A.i16 = ((r5&0xF8)<<8) | ((g6&0xFC)<<3) | ((b5&0xF8)>>3);

*screen_spi = union16_A.i8[1];
*screen_spi = union16_A.i8[0];
}
``````

Here I am using a union to give the code access to the individual bytes of the pixel.

My problem is that the conversion process seems to be slow, and on the logic analyser, I can see gaps between consecutive bytes. This is why the code doesn't bother to check if the SPI is free to send the next byte.

Perhaps this whole process could be achieved with the DMA and PIO. This would have the added advantage that it would also free up the core that's running this loop. I haven't dug into the details of the PIO yet, so ...

My question:

Is 888 -> 565 conversion something that the PIO could feasibly achieve? The DMA would pump bytes to the PIO, which would then clock the top 5 bits of the first byte, the top 6 bits of the next byte, and the top 5 bits of the next byte, then loop. And if this is possible, is it likely that it would be able to sustain an SPI clock speed of 62.5MHz?

What kind answer am I looking for?

I would be satisfied with a Yes or No answer. If I know that it's feasible, I'll dig more into it, and try to get it working. If I know it's not feasible, then I know I needn't waste more time on it.

Even better would be a library that does this, but I haven't been able to find one so far.