About SPI optimization - martinberlin/cale-idf GitHub Wiki

How it's usually done on every GxEPD model

Independently on the Epaper module, what happens in update() method, is somehow similar:

  • The _wakeup() private method is called. In most epaper controller models send a Power on at the beginning (0x04 CMD) and then it sends some LUT initialization tables (usually 4 between 42 and 44 bytes each as SPI CMD+ DATA)
  • A command to signalize we start sending the buffer is sent (CMD 0x13) Pixel buffer is sent {0 to end of sizeof(_buffer)}. It's read from the generated GFX _buffer byte by byte and send using IO.data(byte)
  • A command is called that signalizes our display slave that it needs to refresh (Usually 0x012)
  • Refresh takes place and the new pixels are rendered in the epaper

IO.data(byte) turns the CS Gpio Low-> transmits -> CS high again

List of Good display epaper IC drivers

The obvious optimization points

Toggling Chip Select on every byte sent as data is over-engineered. Even if takes nano-seconds to turn a GPIO low and high after each transmission, when we are sending a full buffer for a big epaper, this will greatly affect performance. It's very clear that it's not an efficient way to do it.

As an example, the Wave12I48 display has 1304*984 pixels. So in total, they are 1 million 283 thousand pixels. Measuring how much many bytes we send over SPI toogling the CS pin is simple:

1283136/8 = 160392 bytes

So we are switching CS GPIO 160 thousand times, low->transmit->high, to send our pixel buffer. That calls for some optimization right?

Instead of doing this, we can just use another data function:

EpdSpi::data(const uint8_t *data, int len) {}

And just send a complete line via SPI, toggling CS pin, only once on every Y row. That could be done on single SPI slave displays. But also in Wave12I48 is much more efficient to send the whole line to each of the epaper than it would be to send per byte. According to the SPI documentation up to 4Kb of data can be sent per SPI in each transmission of data. That indicates it might be still room for more optimization.

Since we have a complex grid structure in this epaper, it's enough to reduce the Gpio CS toggling at least 80 times (80*8 640) for each epaper controller in the grid of 4, sending a full X line per display. But for other single SPI displays it's our intention to optimize this as much as possible, to the SPI limits, provided it's still a stable implementation.

In the programming world there is a phrase that says that "Premature optimization is the root of all evil". But this was not premature, it was obvious optimization. Optimizing too much specially in smaller epapers where the buffer is small won't make a noticiable difference, but in this big ones, it does and it can be done. So it will be applied everywhere it's doable on every single new model Class.

Check Wave12I48 stats section to see the optimization gain.

Another interesting reads about SPI optimization

Official ESP-IDF documentation

https://github.com/krzychb/esp-epaper-29-ws