Skip to content

fix 9-bit spi data corruption by padding no-op#763

Open
Eggrror404 wants to merge 1 commit intomoononournation:masterfrom
Eggrror404:master
Open

fix 9-bit spi data corruption by padding no-op#763
Eggrror404 wants to merge 1 commit intomoononournation:masterfrom
Eggrror404:master

Conversation

@Eggrror404
Copy link

closes #754

As described in the issue, this is the fix that appends zeros into the buffer to prevent breakage.

The implementation in writeRepeat() is more complicated because (1) there may be leftover data to flush and we can't pad zeros there and (2) half-pixels are transferred between transactions. And the difference between ESP32 boards makes the implementation even look more complicated.

But I tested it with continuous fillScreen() calls and it seemed to work fine. I'm getting ~80 fps on my ESP32C3 board, it should be pretty solid.

- ensured buffer is byte-aligned by padding no-op commands before
flushing
- in writeRepeat loop, made sure all data is properly sent in bytes
  - done by (1) padding existing buffer data with requested ones, (2)
    flushing the existing data, then (3) sending out packed up buffer
    repeatedly
@moononournation
Copy link
Owner

make it simple, is it can do the job if set buffer to zero while init and after flush?

@Eggrror404
Copy link
Author

make it simple, is it can do the job if set buffer to zero while init and after flush?

I believe it has to be a no-op command (9 zeros at once), not just setting the buffer to zero.
Because otherwise the zeros would be taken as part of other commands, thus breaking things.
So the same issue as the current one.

for example, to send a SLPOUT command, flush, then a COLMOD command:

      SLPOUT      |   (flush)   |     COLMOD      |
 0 0 0 0 1 0 0 0 1 . . . . . . . 0 0 0 1 1 1 0 1 0
----------------+---------------+---------------+----
    byte 0      |    byte 1     | (new) byte 0  |   byte 1

If we leave the 7 empty slots (.) in the second byte of the old buffer, no matter what data we fill in, it'd take the first 2 bits of the second command with it and interpret it as a 9-bit command.

    command 0     |     command 1   |    command 2    |
      SLPOUT      |   fill-in   |     COLMOD      |
 0 0 0 0 1 0 0 0 1 . . . . . . . 0 0 0 1 1 1 0 1 0 . .

This is what happens currently, to my understanding. So I'm deliberately appending no-op commands until byte borders to ensure that doesn't happen, and it seemed to work.

@moononournation
Copy link
Owner

How can I test it works?
What is the use case of the original issue?
Then this pull request can fix it?

@Eggrror404
Copy link
Author

How can I test it works?

To test this, you'll need a display that uses 3-wire SPI interface.
And you can test by the Hello World example.

void setup(void)
{
  Serial.begin(115200);
  // Serial.setDebugOutput(true);
  // while(!Serial);
  Serial.println("Arduino_GFX Hello World example");

  // Init Display
  if (!gfx->begin())
  {
    Serial.println("gfx->begin() failed!");
  }
  gfx->fillScreen(RGB565_BLACK);

  gfx->setCursor(10, 10);
  gfx->setTextColor(RGB565_RED);
  gfx->println("Hello World!");

  delay(5000); // 5 seconds
}

Without this PR, the display can't initialize at all and my display simply stays white (only backlight turns on).
Even though the library does successfully send off the bits, the message is messed up by flushes in the middle and byte-packing behavior of ESP32 boards.

And with my patches, the display is correctly painted black and wrote "Hello World".

What is the use case of the original issue? Then this pull request can fix it?

The original issue is caused by the exact reason I wrote in the last message. This PR does fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants