Help with "GxEPD2_154_D67". It is a 1.54 inch unit, black and white

Hello.

I need advice.

I am making a battery powered application. I draw a battery bitmap, into which I want to then draw "the battery core", to indicate battery level.

The issue is that after drawing the icon, drawing a line erases the icon. Why is this happening?

Hello,

the display used is "GxEPD2_154_D67". It is a 1.54 inch unit, black and white. Has a level translator and is run in 4-wire mode.

Says Designed By: MH-ET LIVE

@ZinggJM ,
Spilt as requested.

1 Like

Help us help you.

1 Like

Hello.

I am using Seeeduino XIAO, it is a SAMD based board. The code line bellow never displays:

display.drawImage(MobileFullBatteryicon90deg->data, box_x, box_y, box_w, box_h, false, false, false);

This is the code:

// GxEPD2_MinimumExample.ino by Jean-Marc Zingg

// purpose is e.g. to determine minimum code and ram use by this library

// see GxEPD2_wiring_examples.h of GxEPD2_Example for wiring suggestions and examples
// if you use a different wiring, you need to adapt the constructor parameters!

// uncomment next line to use class GFX of library GFX_Root instead of Adafruit_GFX, to use less code and ram
//#include <GFX.h>

#include <GxEPD2_BW.h> // including both doesn't use more code or ram
#include <GxEPD2_3C.h> // including both doesn't use more code or ram

// select the display class and display driver class in the following file (new style):
#include "GxEPD2_display_selection_new_style.h"


#include "Mobile-Full-Battery-icon-90deg.h"


#define RESET_SCT 0
#define NSS_SCR 3
#define D_C 6
#define BUSY -1 //2

#define MOSI 10
#define MISO 9
#define SCK 8

#define USE_DISPLAY 1

// alternately you can copy the constructor from GxEPD2_display_selection.h or GxEPD2_display_selection_added.h of GxEPD2_Example to here
// e.g. for Wemos D1 mini:
GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> display(GxEPD2_154_D67(/*CS=D8*/ NSS_SCR, /*DC=D3*/ D_C, /*RST=D4*/ RESET_SCT, /*BUSY=D2*/ BUSY)); // GDEH0154D67

void setup()
{
  display.init();
  display.setRotation(3);
}

void loop() {
  updateDisplay();
  delay(10000);
};



void updateDisplay(){

  display.firstPage();
  do
  {

    display.fillRect(0 /*box_x*/, 72 /*box_y*/, 200 /*box_w*/, 127 /*box_h*/, GxEPD_WHITE);  //GxEPD_WHITE //GxEPD_BLACK
    display.fillRect(0 /*box_x*/, 72 /*box_y*/, 200 /*box_w*/, 2 /*box_h*/, GxEPD_BLACK);  //GxEPD_WHITE //GxEPD_BLACK

  }
  while (display.nextPage());


  drawBatteryDrainedIcon();

  //this rectangle is never drawn/displayed
  display.fillRect(200 - 30 /*box_x*/, 10 /*box_y*/, 20 /*box_w*/, 10 /*box_h*/, GxEPD_BLACK);  //GxEPD_WHITE //GxEPD_BLACK

  display.hibernate();  //bad graphics
}



void drawBatteryDrainedIcon(void){

  uint16_t box_x = 0;
  uint16_t box_y = 0;
  uint16_t box_w = MobileFullBatteryicon90deg->width;
  uint16_t box_h = MobileFullBatteryicon90deg->height;

  display.drawImage(MobileFullBatteryicon90deg->data, box_x, box_y, box_w, box_h, false, false, false);

}

This is in the Mobile-Full-Battery-icon-90deg.h, holds the icon bitmap:

/*******************************************************************************
* name: Mobile-Full-Battery-icon-90deg
*
* preset name: Monochrome
* data block size: 8 bit(s), uint8_t
* RLE compression enabled: no
* conversion type: Monochrome, Diffuse Dither 128
* split to rows: yes
* bits per pixel: 1
*
* preprocess:
*  main scan direction: top_to_bottom
*  line scan direction: forward
*  inverse: no
*******************************************************************************/


 typedef struct {
     const uint8_t *data;
     uint16_t width;
     uint16_t height;
     uint8_t dataSize;
     } tImage2;

#include <stdint.h>



static const uint8_t image_data_MobileFullBatteryicon90deg[128] = {

    0xff, 0x00, 0x00, 0xff, 
    0xfe, 0x00, 0x00, 0x7f, 
...too long...
    0xff, 0xf0, 0x0f, 0xff
};
const tImage2 MobileFullBatteryicon90deg[] = { image_data_MobileFullBatteryicon90deg, 32, 32,
    8 };

@aiggya, I still don't consider this as a clear description.

You either need to put this in a page loop, or call display.display() to update to screen.

You may get more if you state your issue clearly. You also need to tell the voltage supplied to the MHT board, and the position of the selector switch.
Does your display work with GxEPD2_Example, or does it show issues? What inking do you see on the flex connector of the panel?

Hello,

thanks for responding.

If I put "display.display();" after the rectangle, then my icon is erased, as if it was never drawn.

void updateDisplay(){

  display.firstPage();
  do
  {

    display.fillRect(0 /*box_x*/, 72 /*box_y*/, 200 /*box_w*/, 127 /*box_h*/, GxEPD_WHITE);  //GxEPD_WHITE //GxEPD_BLACK
    display.fillRect(0 /*box_x*/, 72 /*box_y*/, 200 /*box_w*/, 2 /*box_h*/, GxEPD_BLACK);  //GxEPD_WHITE //GxEPD_BLACK

  }
  while (display.nextPage());

 //in this case the icon is not displayed
  drawBatteryDrainedIcon();

  
  display.fillRect(200 - 30 /*box_x*/, 10 /*box_y*/, 20 /*box_w*/, 10 /*box_h*/, GxEPD_BLACK);  //GxEPD_WHITE //GxEPD_BLACK
  display.display();

  display.hibernate();  //bad graphics
}

If I move it in the page loop, the icon overwrites it, so there is no batery charge indication:

void updateDisplay(){

  display.firstPage();
  do
  {

    display.fillRect(0 /*box_x*/, 72 /*box_y*/, 200 /*box_w*/, 127 /*box_h*/, GxEPD_WHITE);  //GxEPD_WHITE //GxEPD_BLACK
    display.fillRect(0 /*box_x*/, 72 /*box_y*/, 200 /*box_w*/, 2 /*box_h*/, GxEPD_BLACK);  //GxEPD_WHITE //GxEPD_BLACK
    //moved
    display.fillRect(200 - 30 /*box_x*/, 10 /*box_y*/, 20 /*box_w*/, 10 /*box_h*/, GxEPD_BLACK);  //GxEPD_WHITE //GxEPD_BLACK
  }
  while (display.nextPage());


  drawBatteryDrainedIcon();

  
  
  //display.display();

  display.hibernate();  //bad graphics
}

What I want to achieve is show battery state, but the idea is to use one "empty battery icon" and then fill it with a rectangle to indicate state of charge.

image

Voltage supplied is 3.3V, so display works, I just can't seem to understand how to use your library.

The inking is:

HNK-E0154A07-A1
Dote: 2017-02-28
SYX 2114

I verified GxEPD2_Example works as expected.

@aiggya, have you ever read the README.md of my library?

    // write to controller memory, with screen refresh; x and w should be multiple of 8
    void drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false)
    {
      epd2.drawImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
    }

GxEPD2_BW.h line 510.

It should be obvious, that it will be replaced by the content of the graphics buffer on next full screen update.
You could use partial window update to update part of a "background" image, but this is not the ideal solution to what you want to achieve.

You should use a drawBitmap method to "draw" you picture to the graphics buffer.
See in Adafruit_GFX.h e.g. line 84..91:

  void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w,
                  int16_t h, uint16_t color);
  void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w,
                  int16_t h, uint16_t color, uint16_t bg);
  void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h,
                  uint16_t color);
  void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h,
                  uint16_t color, uint16_t bg);

See also e.g. GxEPD2_Example.ino line 975

#ifdef _GxBitmaps104x212_H_
void drawBitmaps104x212()
{
#if !defined(__AVR)
  const unsigned char* bitmaps[] =
  {
    WS_Bitmap104x212, Bitmap104x212_1, Bitmap104x212_2, Bitmap104x212_3
  };
#else
  const unsigned char* bitmaps[] =
  {
    WS_Bitmap104x212, Bitmap104x212_1, Bitmap104x212_2, Bitmap104x212_3
  };
#endif
  if ((display.epd2.WIDTH == 104) && (display.epd2.HEIGHT == 212) && !display.epd2.hasColor)
  {
    for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++)
    {
      display.firstPage();
      do
      {
        display.fillScreen(GxEPD_WHITE);
        display.drawBitmap(0, 0, bitmaps[i], 104, 212, GxEPD_BLACK);
      }
      while (display.nextPage());
      delay(2000);
    }
  }
}
#endif

For your combined result, you should place all commands for buffered drawing in the same page loop.

Hello ZinggJM.

Thanks for support, sadly I am still seeing two issues:

  • the bitmaps appear to be color inverted

EDIT: The rotation error was a bug in my code.

Honestly I did not read in detail the read.me, I just quickly scanned through. Previously had this done with the old GxEPD library, but with Seeduino XIAO the library has issues, so I decided to try out GxEPD2, which works, but has some different implementations, which is why I keep failing. That is not reading the docs in detail and not studying the code is why I keep failing.

It has been a long day, I can't continue today, will get back to you, but again, thanks for support and the library.

Left is new code (inverted color, but nicely overlayed rectangle over battery icon), right is old code, so how it is supposed to look like, lacking the state of charge:

The digits are drawn with line commands and filled rectangles, you can ignore them, as you can ignore temperature icon.

Modified code:

void updateDisplay(){


  display.firstPage();
  do
  {
    display.fillScreen(GxEPD_WHITE);
    display.fillRect(0 /*box_x*/, 72 /*box_y*/, 200 /*box_w*/, 127 /*box_h*/, GxEPD_WHITE);  //GxEPD_WHITE //GxEPD_BLACK
    display.fillRect(0 /*box_x*/, 72 /*box_y*/, 200 /*box_w*/, 2 /*box_h*/, GxEPD_BLACK);  //GxEPD_WHITE //GxEPD_BLACK
    displayNumber(temperature);  //-24.5°C
    //drawTemperatureIcon();
    drawBatteryDrainedIcon();

    //display.fillRect(200 - 30 /*box_x*/, 10 /*box_y*/, 20 /*box_w*/, 10 /*box_h*/, GxEPD_BLACK);  //GxEPD_WHITE //GxEPD_BLACK
    display.fillRect(0 /*box_x*/, 10 /*box_y*/, 20 /*box_w*/, 10 /*box_h*/, GxEPD_BLACK);  //GxEPD_WHITE //GxEPD_BLACK

  }
  while (display.nextPage());
  

  display.hibernate();  //bad graphics

}
void drawBatteryDrainedIcon(void){

  

  uint16_t box_x = 0;
  uint16_t box_y = 0;
  uint16_t box_w = MobileFullBatteryicon90deg->width;
  uint16_t box_h = MobileFullBatteryicon90deg->height;




  #if 1
  display.drawBitmap(box_x, box_y, MobileFullBatteryicon90deg->data, box_w, box_h, GxEPD_BLACK);
  #else
  display.drawImage(MobileFullBatteryicon90deg->data, box_x, box_y, box_w, box_h, false, false, false);
  #endif

  
  
}

@aiggya, yes, some more reading would be beneficial.

If you look through GxEPD2_Example.ino, you would see many uses of drawInvertedBitmap.

You can achieve the same by specifying foreground and background in

Hello.

I will first thank you for your patience, I tried now with drawInvertedBitmap, and works as expected.

I did noticed the function in #9 post:

void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w,
                  int16_t h, uint16_t color, uint16_t bg);

and tried right away yesterday, but for me there was no change. I tried it again today as the last few days I was very busy (and tired) but the behavior was the same. Probably I am combining again old code with new code and of course I still did not read or study the code, just letting you know, that the code bellow did not work for me:

display.drawBitmap(box_x, box_y, MobileFullBatteryicon90deg->data, box_w, box_h, GxEPD_BLACK, GxEPD_WHITE);

But the mod with drawInvertedBitmap works as advertised:

Thanks for support and for tolerance, I am normally much more proactive in searching for solutions.

@aiggya, I don't believe your observation is true, but have no time to check.

/**************************************************************************/
/*!
   @brief      Draw a PROGMEM-resident 1-bit image at the specified (x,y)
   position, using the specified foreground (for set bits) and background (unset
   bits) colors.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with monochrome bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
    @param    color 16-bit 5-6-5 Color to draw pixels with
    @param    bg 16-bit 5-6-5 Color to draw background with
*/
/**************************************************************************/
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
                              int16_t w, int16_t h, uint16_t color,
                              uint16_t bg) {

  int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
  uint8_t b = 0;

  startWrite();
  for (int16_t j = 0; j < h; j++, y++) {
    for (int16_t i = 0; i < w; i++) {
      if (i & 7)
        b <<= 1;
      else
        b = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
      writePixel(x + i, y, (b & 0x80) ? color : bg);
    }
  }
  endWrite();
}

Swap foreground and background colors if bitmap is inverted!

Hello.

I have swapped foreground and background colors and it then works. So seems this is the difference, as the same icon was used in both libraries.

Thanks again and best regards!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.