esp32-epaper-display icon indicating copy to clipboard operation
esp32-epaper-display copied to clipboard

Support EPD7in5_V2

Open antonatosn opened this issue 4 years ago • 28 comments

Hi,

Please could you also support the new panels 7.5 V2 Black / White https://www.waveshare.com/7.5inch-e-Paper-HAT.htm

Thanks

antonatosn avatar May 02 '20 14:05 antonatosn

Yes, but in the future.

I'm planning on abstracting the EPD to support more displays. I have a EPD2in7 i'll implement first, then i'll ring you up to test your display if you're okay with that.

ugomeda avatar May 02 '20 17:05 ugomeda

Do you know the differences on the driver between v1 and v2. May I can help in development

antonatosn avatar May 02 '20 17:05 antonatosn

The changes are quite small, it shouldn't be that difficult. Take a look at their repos here :

  • https://github.com/waveshare/e-Paper/tree/master/Arduino/epd7in5_V2 (your version)
  • https://github.com/waveshare/e-Paper/tree/master/Arduino/epd7in5 (the current version)

I took their code and change it a bit to put it in https://github.com/ugomeda/esp32-epaper-display/blob/master/epaper-esp32/src/epd.c

  • EPD_7in5__init() is int Epd::Init(void)
  • EPD_WaitUntilIdle is void Epd::WaitUntilIdle(void)
  • etc

The pins are the same, you should only have to change the commands sent to the display.

Example :

  EPD_SendCommand(0x01, "\x37\x00", 2);     //POWER_SETTING
  EPD_SendCommand(0x00, "\xCF\x08", 2);     //PANEL_SETTING
  EPD_SendCommand(0x06, "\xC7\xCC\x28", 3); //BOOSTER_SOFT_START
  EPD_SendCommand(0x4, NULL, 0);            //POWER_ON
  EPD_WaitUntilIdle();

Should be replaced by

  EPD_SendCommand(0x01, "\x07\x07\x3f\x3f", 2);
  EPD_SendCommand(0x04, NULL, 0);
  EPD_WaitUntilIdle();

Which is a translation of this code in Waveshare's implementation

    SendCommand(0x01); 
    SendData(0x07);
    SendData(0x07);
    SendData(0x3f);
    SendData(0x3f);

    SendCommand(0x04);
    DelayMs(100);
    WaitUntilIdle();

If you get it working, please share the code :)

ugomeda avatar May 02 '20 17:05 ugomeda

I have change the resolution to 800x480 on both server and ESP. but now the lodepng_decode throws an error 83 memory allocation failed on server also I have convert the image to grey-scale for test

antonatosn avatar May 02 '20 20:05 antonatosn

I already had this problem, waveshare's ESP32 doesn't seem to have the 4MB additional memory and it fails. I developped a workaround at some point by loading the image into chunks, but it was very hacky. I fixed it by using a proper 2-bit image.

Loading the 2 colors 800x480 image in-memory only takes 2x800x480 bits, 94kB. This should fit easily into the 512 kB RAM of the ESP32. I'll try to find where i'm wasting so much memory tomorrow.

ugomeda avatar May 02 '20 21:05 ugomeda

In the meantime, if you want to implement the color display, you can send a smaller image, ie a 800x240px image. It should display the top of the image, and random garbage after.

ugomeda avatar May 02 '20 21:05 ugomeda

Ok, I manage to convert it to B/W and use 1 bit of depth. and It worked. But when I tried to send the image to the screen, esp got kernel panic

0;32mI (2734) EPD: Received new PNG of size 6654␛[0m ␛[0;32mI (2754) EPD: Sending image␛[0m Guru Meditation Error: Core 1 panic'ed (LoadStoreError). Exception was unhandled. Core 1 register dump: PC : 0x400d1fc4 PS : 0x00060630 A0 : 0x800d2110 A1 : 0x3ffc78f0
A2 : 0x3ffe436c A3 : 0x00000320 A4 : 0x000001e0 A5 : 0x0001bc94
A6 : 0x00000001 A7 : 0x00000005 A8 : 0x40000000 A9 : 0x3ffc7917
A10 : 0x00000000 A11 : 0x00000028 A12 : 0x00000027 A13 : 0x00000000
A14 : 0x00000000 A15 : 0x00000000 SAR : 0x00000011 EXCCAUSE: 0x00000003
EXCVADDR: 0x40000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffffe

ELF file SHA256: cbcd4695c23db55df46f0af9d15a600fabee5c44e25d967637d9e0ca1451bfa8

Backtrace: 0x400d1fc1:0x3ffc78f0 0x400d210d:0x3ffc7950 0x400d1b1d:0x3ffc7a00 0x400d1bcc:0x3ffc7aa0 0x400904d9:0x3ffc7ae0

Rebooting... ets Jun 8 2016 00:22:57

antonatosn avatar May 02 '20 21:05 antonatosn

Looks like you're trying to access memory which was not allocated. Probably because the PNG was loaded using 1-bit depth, but you're trying to read 2-bit depth images in the EPD code.

In epd.c :

  // 2-bit image, each byte contains 4 pixels
  for (uint32_t i = 0; i < width * height / 4; i++)
  {
    ...

Adapt the code after to read the proper indexes in the buffer.

ugomeda avatar May 02 '20 22:05 ugomeda

could you explain a bit how you map the image ? It looks a bit complicate to me the EPD_loadImage

antonatosn avatar May 02 '20 22:05 antonatosn

Yes, it's not straightforward since i have to translate from a 2-bit image to some weird 4-bit image. There is also a buffer to avoid sending the data pixel by pixel.

I'll try to explain as i write the code examples.

So, you're trying to draw a 1-bit image (= 8 pixels per byte) onto your 4-bit display. You'll have to go through the array (width x height) / (8 * 1-bit) times :

  for (uint32_t i = 0; i < width * height / 8; i++)
  {

Then, extract each bit ((image[i] & (0x01 << X)) >> X) and map it to the value the EPD expects (PIX_MAPPING[...]) :

    uint8_t pix_1 = PIX_MAPPING[(image[i] & (0x01 << 7)) >> 7];
    uint8_t pix_2 = PIX_MAPPING[(image[i] & (0x01 << 6)) >> 6];
    uint8_t pix_3 = PIX_MAPPING[(image[i] & (0x01 << 5)) >> 5];
    uint8_t pix_4 = PIX_MAPPING[(image[i] & (0x01 << 4)) >> 4];
    uint8_t pix_5 = PIX_MAPPING[(image[i] & (0x01 << 3)) >> 3];
    uint8_t pix_6 = PIX_MAPPING[(image[i] & (0x01 << 2)) >> 2];
    uint8_t pix_7 = PIX_MAPPING[(image[i] & (0x01 << 1)) >> 1];
    uint8_t pix_8 = PIX_MAPPING[(image[i] & (0x03 << 0)) >> 0];

Looking at https://github.com/waveshare/e-Paper/blob/master/Arduino/epd7in5_V2/imagedata.cpp, it seems like the values are 0x00 and 0x03 for black/white, so no need to change the WHITE, BLACK or PIX_MAPPING constants.

You then have to put the new 4-bit values into the buffer :

    buffer[buffer_pos++] = pix_1 << 4 | pix_2;
    buffer[buffer_pos++] = pix_3 << 4 | pix_4;
    buffer[buffer_pos++] = pix_5 << 4 | pix_6;
    buffer[buffer_pos++] = pix_7 << 4 | pix_8;

So this might be able to load the image into the display memory :

void EPD_loadImage(const uint8_t *image, const unsigned int width, const unsigned int height)
{
  char buffer[BUFFER_SIZE];
  int buffer_pos = 0;

  // 2-bit image, each byte contains 8 pixels
  for (uint32_t i = 0; i < width * height / 8; i++)
  {
    // each byte = 2 pixels
    uint8_t pix_1 = PIX_MAPPING[(image[i] & (0x01 << 7)) >> 7];
    uint8_t pix_2 = PIX_MAPPING[(image[i] & (0x01 << 6)) >> 6];
    uint8_t pix_3 = PIX_MAPPING[(image[i] & (0x01 << 5)) >> 5];
    uint8_t pix_4 = PIX_MAPPING[(image[i] & (0x01 << 4)) >> 4];
    uint8_t pix_5 = PIX_MAPPING[(image[i] & (0x01 << 3)) >> 3];
    uint8_t pix_6 = PIX_MAPPING[(image[i] & (0x01 << 2)) >> 2];
    uint8_t pix_7 = PIX_MAPPING[(image[i] & (0x01 << 1)) >> 1];
    uint8_t pix_8 = PIX_MAPPING[(image[i] & (0x03 << 0)) >> 0];

    buffer[buffer_pos++] = pix_1 << 4 | pix_2;
    buffer[buffer_pos++] = pix_3 << 4 | pix_4;
    buffer[buffer_pos++] = pix_5 << 4 | pix_6;
    buffer[buffer_pos++] = pix_7 << 4 | pix_8;

    if (buffer_pos == BUFFER_SIZE || i == width * height / 8)
    {
      EPD_SendData(buffer, buffer_pos);
      buffer_pos = 0;
    }
  }
}

I hope it helps !

ugomeda avatar May 02 '20 23:05 ugomeda

why in the last pixel you use 0x03 and on the other 0x01? uint8_t pix_7 = PIX_MAPPING[(image[i] & (0x01 << 1)) >> 1]; uint8_t pix_8 = PIX_MAPPING[(image[i] & (0x03 << 0)) >> 0];

also as i understand you get 1 pixel / bit from image (so it should be black or white (0x00 or 0xFF) and then what do you try to do???

antonatosn avatar May 03 '20 00:05 antonatosn

also I have done many trials with the code. I dont have any errors or kernel panic but it shows just random pixels

antonatosn avatar May 03 '20 00:05 antonatosn

Can you fork the project and push your modifications so i can have a look ?

ugomeda avatar May 03 '20 00:05 ugomeda

ok done https://github.com/antonatosn/esp32-epaper-display/tree/master/epaper-esp32

antonatosn avatar May 03 '20 00:05 antonatosn

Found a few things :

EPD_SendCommand(0x01, "\x07\x07\x3f\x3f", 2);

The second parameter should be 4 (the length of the string), sorry about that.


EPD_SendCommand(0x00, "0x1F", 0);

You're sending the string "0x1F", you want this :

EPD_SendCommand(0x00, "\x1F", 1);

  EPD_SendCommand(0x50, "\x10\x07", 2);
  EPD_SendCommand(0x60, "\x22", 1);             //TCON_SETTING
  EPD_SendCommand(0x15, "\x00", 1);
  //EPD_SendCommand(0x61, "\x02\x80\x01\x80", 4); //TCON_RESOLUTION
  EPD_SendCommand(0x61, "\x03\x20\x01\xE0", 4);
  //EPD_SendCommand(0x82, "\x1E", 1);             //VCM_DC_SETTING: decide by LUT file
  //EPD_SendCommand(0xE5, "\x03", 1);             //FLASH MODE

  EPD_SendCommand(0x10, NULL, 0); //DATA_START_TRANSMISSION_1

Doesn't to be updated, it should match https://github.com/waveshare/e-Paper/blob/master/Arduino/epd7in5_V2/epd7in5_V2.cpp#L61 :

    SendCommand(0x61);        	//tres
    SendData(0x03);		//source 800
    SendData(0x20);
    SendData(0x01);		//gate 480
    SendData(0xE0);

    SendCommand(0X15);
    SendData(0x00);

    SendCommand(0X50);			//VCOM AND DATA INTERVAL SETTING
    SendData(0x10);
    SendData(0x07);

    SendCommand(0X60);			//TCON SETTING
    SendData(0x22);

Also add this, which is the beginning of DisplayFrame()

    SendCommand(0x13);

ugomeda avatar May 03 '20 00:05 ugomeda

I ve made those change. Now its not flickering on startup but also doesn't show anything check on my repo i have update the code. May I missed something?

antonatosn avatar May 03 '20 01:05 antonatosn

Il take a look tomorrow !

On Sun, May 3, 2020, 3:15 AM Nikos Antonatos [email protected] wrote:

I ve made those change. Now its not flickering on startup but also doesn't show anything check on my repo i have update the code. May I missed something?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/ugomeda/esp32-epaper-display/issues/1#issuecomment-623037824, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHDT46VPM7TJWAANDAXDRDRPTAUDANCNFSM4MXW2GVA .

ugomeda avatar May 03 '20 01:05 ugomeda

I made some change and now something has started to appear. the picture is not clear but i can see the temp value and the weather icons but they are huge size. and also I am seeing vertical lines

antonatosn avatar May 03 '20 02:05 antonatosn

Can you confirm you have the color version of the EPD ? Can you send a picture ?

If you can see something, It means you're pretty close !

ugomeda avatar May 03 '20 10:05 ugomeda

A few more things to match the demo code :

  EPD_SendCommand(0x4, NULL, 0);            //POWER_ON
  EPD_WaitUntilIdle();

  //EPD_SendCommand(0x00, "0x1F", 1);                 //PANNEL SETTING
                                                    //KW-3f   KWR-2F	BWROTP 0f	BWOTP 1f
  EPD_SendCommand(0x00, NULL, 0);

Should be

  EPD_SendCommand(0x4, NULL, 0);            //POWER_ON
  vTaskDelay(100 / portTICK_PERIOD_MS);
  EPD_WaitUntilIdle();

  EPD_SendCommand(0x00, "\x1f", 1);

The logic for the WaitUntilIdle seems to send a 0x71, change the function for this :

void EPD_WaitUntilIdle()
{
  EPD_SendCommand(0x71, NULL, 0);
  while (gpio_get_level(PIN_SPI_BUSY_NUM) == 0)
  {
    vTaskDelay(100 / portTICK_PERIOD_MS);
    EPD_SendCommand(0x71, NULL, 0);
  }
}

I'm also looking at this :

void Epd::Clear(void) {
    
    SendCommand(0x10);
    for(unsigned long i=0; i<height*width; i++) {
        SendData(0x00);
    }
    SendCommand(0x13);
    for(unsigned long i=0; i<height*width; i++)	{
        SendData(0x00);
    }
    SendCommand(0x12);
    DelayMs(100);
    WaitUntilIdle();
}

This is weird, seems like it's 1-byte per pixel and there is 2 commands to write 2 images, i'll look into it.

ugomeda avatar May 03 '20 10:05 ugomeda

Ouch, so many things wrong here, you said you were using the B/W version in the first message, i thought you had the color version...

Let me see what changes...

ugomeda avatar May 03 '20 10:05 ugomeda

Actually, the code is all for the B/W version, amazing !

So, more things comming from https://www.waveshare.com/wiki/File:E-Paper_ESP32_Driver_Board_Code.7z

    { EPD_7in5__init , EPD_loadE, -1  , 0,         EPD_showC, "7.5 inch b"  },// u 20
    { EPD_7in5_V2_init , EPD_loadAFilp, -1  , 0,   EPD_7IN5_V2_Show, "7.5 inch V2" },// w 22

Seems line loadAFilp uses 1-bit -or 2-bit ?) images :

void EPD_loadAFilp()
{
    // Come back to the image data end
    Buff__bufInd -= 8;

    // Get the index of the image data begin
    int pos = Buff__bufInd - Buff__getWord(Buff__bufInd);

    // Enumerate all of image data bytes
    while (pos < Buff__bufInd)
    {
        // Get current byte
        int value = Buff__getByte(pos);

        // Invert byte's bits in case of '2.7' e-Paper
        if (EPD_invert) value = ~value;

        // Write the byte into e-Paper's memory
        EPD_SendData(~(byte)value);

        // Increment the current byte index on 2 characters
        pos += 2;
    }
}

Try sending the buffer directly to see what happens :

void EPD_loadImage(const uint8_t *image, const unsigned int width, const unsigned int height)
{
  char buffer[BUFFER_SIZE];
  int buffer_pos = 0;

  EPD_SendCommand(0x13, NULL, 0);

  for (uint32_t i = 0; i < width * height / 8; i++)
  {
    buffer[buffer_pos++] = image[i];

    if (buffer_pos == BUFFER_SIZE || i == width * height / 8)
    {
      EPD_SendData(buffer, buffer_pos);
      buffer_pos = 0;
    }
  }
}

ugomeda avatar May 03 '20 11:05 ugomeda

it works.. but the color is opposite (its like negative where white is black and black white) also the size of the picture is smaller

antonatosn avatar May 03 '20 13:05 antonatosn

also if I set EPD_SendCommand(0x00, "0x1F", 1); on init its not updating the panel

antonatosn avatar May 03 '20 13:05 antonatosn

Amazing !

To revert the colors, juste use buffer[buffer_pos++] = ~image[i];. For the init, use "\x1f", NOT "0x1F".

Also make sure the method EPD_shutdown matches waveshare's implementation.

ugomeda avatar May 03 '20 13:05 ugomeda

Shutdown is the same no changes need I ve try again on the init EPD_SendCommand(0x00, "0x1f", 1); but its not working. I leave it off. it works without it photo

antonatosn avatar May 03 '20 13:05 antonatosn

so the next thing is to make the image fit on screen On server I have change the image res to produce 800x480

[2020-05-03 13:48:25,953] :: INFO :: root :: {'version': 'p0t365fovq41yaimffkm078lvcwf2hho', 'image': <PIL.Image.Image image mode=1 size=800x480 at 0x7FB3F1600F28>, 'next_update': 93124.60900626}

also, another issue that i have is about locale. I change it to Greek language and the letters came as square boxes

antonatosn avatar May 03 '20 13:05 antonatosn

To fit the image on the screen : please refer to the README, you have to update the size and position of your widgets.

Locale issue : this should not happen, the fonts used are OpenSans and LiberationSans, they both implement greek letters... I will have to look into that also.

ugomeda avatar May 03 '20 14:05 ugomeda