GxEPD2_PP : Particle Display Library for SPI E-Paper Displays

GxEPD2_PP is the GxEPD2 Arduino Library ported to Particle Photon

It supports SPI e-paper displays from Dalian Good Display and the display boards from Waveshare that use these display panels.

This topic is intended for asking questions, reporting problems and issues, and hopefully telling your successful use of these displays.

Support and information can also be found in the Arduino Forum Display topics:

https://forum.arduino.cc/index.php?topic=487007.0

https://forum.arduino.cc/index.php?topic=436411.0

The library is published for Particle and its repository is on GitHub:

5 Likes

I want to learn how to draw some bitmap images that I put in an 'images.h' file

(the end goal is to send the image to the particle via a trigger but for now I'm just trying to learn the GxEPD2_PP syntax)

So far I have added this 'images.h' file:

#if defined(ESP8266) || defined(ESP32)
#include <pgmspace.h>
#else
#include <avr/pgmspace.h>
#endif

const unsigned char gImage_youTubeImage[11400] PROGMEM= { /* 0X00,0X01,0X2C,0X01,0X2C,0X01, */
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
....
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,};

and written the following

#include <GxEPD2_PP.h>
#include <Adafruit_GFX_RK.h>
#define ENABLE_GxEPD2_GFX 0
#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <FreeMonoBold9pt7b.h>
#include <GxEPD2_BW.h>
#include <GxEPD2_3C.h>

#if defined(PARTICLE)
GxEPD2_3C<GxEPD2_750c, GxEPD2_750c::HEIGHT / 4 > display(GxEPD2_750c(/*CS=D5*/ SS, /*DC=*/ A1, /*RST=*/ A0, /*BUSY=*/ D4));
#endif

#include "images.h"

void setup()
{
  delay(1000);
  display.init(115200);
  display.drawImage(gImage_youTubeImage, 0, 0, 300, 300, false, false, true);
}

void loop()
{
}

But it just throws this error at me:

call of overloaded 'drawImage(const unsigned char [11400], int, int, int, int, int, int, int)' is ambiguous

:alien: G6EJD answered to me

Your image is a not an integer result, so 300 wide / 8 then x 300 deep = 11250 bytes that first conversion to bytes = 37.5, try changing that to an integer result. Why are you using 11400?

Perhaps try a small image first so you can see what the image format is.

The image comes from a tutorial made by Kevin Darrah - so have no idea why it is 11400 and not 11250. My plan is to convert images via jimp (JavaScript Image Manipulation Program), but I haven't got this far yet. So just grabbed what I could find.

He said he had to do some modification of the lib in order to make it work with his trigBoard
He has uploaded the modified version here EPaperBoard - Kevin Darrah Wiki
(link in the bottom of the page)

He uses a method called .drawBitmap and not .drawImage - guessing that his method .drawBitmap do some preprocessing before calling .drawImage

I'm a little uncertain about what I should do in order to print my own image onto the screen?

Hi Norfeldt,

I confirm that I also get this error, if I take a bitmap from the library with your example.
The reason is not yet clear, I will try to find out.
I don’t know why this error does not show up with the 200x200 bitmap in the library example.
So far I have only done rudimentary tests on Particle, because I struggled with the Particle development tools.

You can start playing by using the basic display class instead of the template class with buffered graphics, like in this example: https://github.com/ZinggJM/PxEPD2/tree/master/examples/test1.

@ZinggJM That was a quick reply. Thank you SO much for taking the time to try and help me out. I’m sorry to hear that the Particle development tools are giving you so much trouble.

The error ‘call of overloaded’ and data type:
‘const unsigned char’

suggests a type mismatch between the call and the library, checking the library, shows:

const uint8_t* bitmap

Which gives rise to the error.

The image is a simple bitmap so I don’t know where 1400 comes from, is make it 300/8*300=11250

uint8_t is defined as unsigned char on all compilers I know. But there seem to be differences in the signature matching of different compilers. Maybe some use textual matching for resolution between overloaded methods.
On Arduino IDE I had seen no problems.

I rather consider to change the example bitmaps to uint8_t than changing the methods to unsigned char, as unsigned char might be uint16_t in future?, whereas uint8_t is clearly a unsigned 8 bit value.

When you get an error message like this it's always good to have a close look to (and also post) the following note message which usually provide some guesses of the compiler which overload may be used instead.

2 Likes

I think this is an error of the compiler; these methods are not ambiguous:

norfeldt.ino: In function 'void setup()':
norfeldt.ino:25:72: error: call of overloaded 'drawImage(const unsigned char [15000], int, int, int, int, int, int, int)' is ambiguous
In file included from norfeldt.ino:10:0:
lib/GxEPD2_PP/src/GxEPD2_BW.h:358:10: note: candidate: void GxEPD2_BW<GxEPD2_Type, page_height>::drawImage(const uint8_t*, int16_t, int16_t, int16_t, int16_t, bool, bool, bool) [with GxEPD2_Type = GxEPD2_750; short unsigned int page_height = 192u; uint8_t = unsigned char; int16_t = short int]
     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)
          ^
lib/GxEPD2_PP/src/GxEPD2_BW.h:362:10: note: candidate: void GxEPD2_BW<GxEPD2_Type, page_height>::drawImage(const uint8_t*, const uint8_t*, int16_t, int16_t, int16_t, int16_t, bool, bool, bool) [with GxEPD2_Type = GxEPD2_750; short unsigned int page_height = 192u; uint8_t = unsigned char; int16_t = short int]
     void drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false)
          ^

Maybe I should call the second method drawColorImage for colourful Particles. I like colourful breathing!

Hmm, I think they are.
Since casting has to take place due to the numeric parameters and the lack of a direct correlation the differences (or lack thereof - due to the default parameters) between the two candidates don’t really favour one over the other.
You and I know the compiler could take either - we’d just flip a coin or go with gut feeling, but since the compiler neither uses coins nor has the guts to guess, it’s defering to the programmer :wink:

Default parameters also make it complicated to judge, are you just omitting a parameter or would you rather want the overload with the shorter full parameter list.

I believe the error is due to the array size being cast in the call const unsigned char [15000] versus the expectation of a pointer to an array. I haven’t tested this assumption.

Also, I wouldn’t set the size of the array in the original definition and let the compiler do that instead!

In my humble opinion the first method is an exact match. And the second takes two pointers and doen’t match at all.

BTW, the same methods are in the basic 3-color display classes and cause no problems. But I know that some compilers have problems with template classes and signature matching.
I use Arduino IDE with different packages with different compilers, but have not encountered this issue.

My bet is on the default parameters. Make all of them compulsory and the ambiguity will go.

What about the second candidate with the last parameter omitted?

The difference between const unsigned char[] and const unsigned char* is irrelevant, so can’t be taken to judge.

I do not understand that sentence. The sized array is in the interpretation by the compiler.

Just for background information: I am totally new to Particle, 3 year Arduino novice, but have over 30 years C++ experience.

I think what @peekay123 tried to suggest was instead of writing

const unsigned char gImage_youTubeImage[11400] PROGMEM= { 0x00,0x01,0x2C,0x01,0x2C,0x01,0x00
....
0x00};

You'd just write it like this

const unsigned char gImage_youTubeImage[] PROGMEM= {  0x00,0x01,0x2C,0x01,0x2C,0x01,0x00
....
0x00};

The amout of provided values will set the array size.


:blush: I overlooked the asterisk on the second parameter of the second candidate :blush:
And once set my perception that way, no matter how ofter I looked at it, it still hid from my attention :see_no_evil:

@ZinggJM, without seeing the original call I assumed that the array size was being passed. Personally, I always pass arrays explicitly by reference or via pointer.

The constant in the brackets is produced by the conversion tool for picture to C-array.
Or in the bitmaps for my example from the original demo source from Good Display or Waveshare.

As suggested by @ScruffR and @peekay123 I tried to change it to

const unsigned char gImage_youTubeImage[] PROGMEM= { /* 0X00,0X01,0X2C,0X01,0X2C,0X01, */
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,

But the wierd thing is that error still says:

gxepd.ino:33:76: call of overloaded 'drawImage(const unsigned char [11400], int, int, int, int, int, int, int)' is ambiguous

and the RAW says

rocessing  gxepd.ino
Checking library GxEPD2_PP...
Checking library Adafruit_GFX_RK...
Installing library Adafruit_GFX_RK 1.3.5 to lib/Adafruit_GFX_RK ...
Installing library GxEPD2_PP 1.0.6 to lib/GxEPD2_PP ...
Library Adafruit_GFX_RK 1.3.5 installed.
Library GxEPD2_PP 1.0.6 installed.
make -C ../modules/photon/user-part all
make[1]: Entering directory '/firmware/modules/photon/user-part'
make -C ../../../user 
make[2]: Entering directory '/firmware/user'
Building c file: lib/Adafruit_GFX_RK/src/glcdfont.c
Invoking: ARM GCC C Compiler
mkdir -p ../build/target/user/platform-6-mAdafruit_GFX_RK/src/
arm-none-eabi-gcc -DSTM32_DEVICE -DSTM32F2XX -DPLATFORM_THREADING=1 -DPLATFORM_ID=6 -DPLATFORM_NAME=photon -DUSBD_VID_SPARK=0x2B04 -DUSBD_PID_DFU=0xD006 -DUSBD_PID_CDC=0xC006 -DSPARK_PLATFORM -g3 -gdwarf-2 -Os -mcpu=cortex-m3 -mthumb -DINCLUDE_PLATFORM=1 -DPRODUCT_ID=6 -DPRODUCT_FIRMWARE_VERSION=65535 -DUSE_STDPERIPH_DRIVER -DDFU_BUILD_ENABLE -DSYSTEM_VERSION_STRING=0.7.0 -DRELEASE_BUILD -I./inc -I../wiring/inc -I../system/inc -I../services/inc -I../communication/src -I../hal/inc -I../hal/shared -I../hal/src/photon -I../hal/src/stm32f2xx -I../hal/src/stm32 -I../hal/src/photon/api -I../hal/src/photon/include -I../hal/src/photon/wiced/security/BESL/host/WICED/ -I../hal/src/photon/wiced/security/BESL/include -I../hal/src/photon/wiced/security/BESL -I../hal/src/photon/wiced/security/BESL/crypto -I../hal/src/photon/wiced/WWD/include/ -I../hal/src/photon/wiced/platform/include/ -I../hal/src/photon/wiced/platform/GCC/ -I../hal/src/photon/wiced/security/BESL/supplicant/ -I../hal/src/photon/libraries/crypto -I../platform/shared/inc -I../platform/MCU/STM32F2xx/STM32_USB_Host_Driver/inc -I../platform/MCU/STM32F2xx/STM32_StdPeriph_Driver/inc -I../platform/MCU/STM32F2xx/STM32_USB_OTG_Driver/inc -I../platform/MCU/STM32F2xx/STM32_USB_Device_Driver/inc -I../platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc -I../platform/MCU/shared/STM32/inc -I../platform/MCU/STM32F2xx/CMSIS/Include -I../platform/MCU/STM32F2xx/CMSIS/Device/ST/Include -I../dynalib/inc -Isrc -I./libraries -Ilib/GxEPD2_PP/src -Ilib/Adafruit_GFX_RK/src -I. -MD -MP -MF ../build/target/user/platform-6-mAdafruit_GFX_RK/src/glcdfont.o.d -ffunction-sections -fdata-sections -Wall -Wno-switch -Wno-error=deprecated-declarations -fmessage-length=0 -fno-strict-aliasing -DSPARK=1 -DPARTICLE=1 -Wundef -DSTART_DFU_FLASHER_SERIAL_SPEED=14400 -DSTART_YMODEM_FLASHER_SERIAL_SPEED=28800 -DBOOTLOADER_SDK_3_3_0_PARTICLE -DPARTICLE_DCT_COMPATIBILITY -DSPARK_PLATFORM_NET=BCM9WCDUSI09 -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc  -DLOG_INCLUDE_SOURCE_INFO=1 -DPARTICLE_USER_MODULE -DUSER_FIRMWARE_IMAGE_SIZE=0x20000 -DUSER_FIRMWARE_IMAGE_LOCATION=0x80A0000 -DMODULAR_FIRMWARE=1 -DMODULE_VERSION=5 -DMODULE_FUNCTION=5 -DMODULE_INDEX=1 -DMODULE_DEPENDENCY=4,2,207 -DMODULE_DEPENDENCY2=0,0,0 -D_WINSOCK_H -D_GNU_SOURCE -DLOG_MODULE_CATEGORY="\"app\""  -Wno-pointer-sign -std=gnu99 -c -o ../build/target/user/platform-6-mAdafruit_GFX_RK/src/glcdfont.o lib/Adafruit_GFX_RK/src/glcdfont.c

Building cpp file: src/gxepd.cpp
Invoking: ARM GCC CPP Compiler
mkdir -p ../build/target/user/platform-6-msrc/
arm-none-eabi-gcc -DSTM32_DEVICE -DSTM32F2XX -DPLATFORM_THREADING=1 -DPLATFORM_ID=6 -DPLATFORM_NAME=photon -DUSBD_VID_SPARK=0x2B04 -DUSBD_PID_DFU=0xD006 -DUSBD_PID_CDC=0xC006 -DSPARK_PLATFORM -g3 -gdwarf-2 -Os -mcpu=cortex-m3 -mthumb -DINCLUDE_PLATFORM=1 -DPRODUCT_ID=6 -DPRODUCT_FIRMWARE_VERSION=65535 -DUSE_STDPERIPH_DRIVER -DDFU_BUILD_ENABLE -DSYSTEM_VERSION_STRING=0.7.0 -DRELEASE_BUILD -I./inc -I../wiring/inc -I../system/inc -I../services/inc -I../communication/src -I../hal/inc -I../hal/shared -I../hal/src/photon -I../hal/src/stm32f2xx -I../hal/src/stm32 -I../hal/src/photon/api -I../hal/src/photon/include -I../hal/src/photon/wiced/security/BESL/host/WICED/ -I../hal/src/photon/wiced/security/BESL/include -I../hal/src/photon/wiced/security/BESL -I../hal/src/photon/wiced/security/BESL/crypto -I../hal/src/photon/wiced/WWD/include/ -I../hal/src/photon/wiced/platform/include/ -I../hal/src/photon/wiced/platform/GCC/ -I../hal/src/photon/wiced/security/BESL/supplicant/ -I../hal/src/photon/libraries/crypto -I../platform/shared/inc -I../platform/MCU/STM32F2xx/STM32_USB_Host_Driver/inc -I../platform/MCU/STM32F2xx/STM32_StdPeriph_Driver/inc -I../platform/MCU/STM32F2xx/STM32_USB_OTG_Driver/inc -I../platform/MCU/STM32F2xx/STM32_USB_Device_Driver/inc -I../platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc -I../platform/MCU/shared/STM32/inc -I../platform/MCU/STM32F2xx/CMSIS/Include -I../platform/MCU/STM32F2xx/CMSIS/Device/ST/Include -I../dynalib/inc -Isrc -I./libraries -Ilib/GxEPD2_PP/src -Ilib/Adafruit_GFX_RK/src -I. -MD -MP -MF ../build/target/user/platform-6-msrc/gxepd.o.d -ffunction-sections -fdata-sections -Wall -Wno-switch -Wno-error=deprecated-declarations -fmessage-length=0 -fno-strict-aliasing -DSPARK=1 -DPARTICLE=1 -Wundef -DSTART_DFU_FLASHER_SERIAL_SPEED=14400 -DSTART_YMODEM_FLASHER_SERIAL_SPEED=28800 -DBOOTLOADER_SDK_3_3_0_PARTICLE -DPARTICLE_DCT_COMPATIBILITY -DSPARK_PLATFORM_NET=BCM9WCDUSI09 -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc  -DLOG_INCLUDE_SOURCE_INFO=1 -DPARTICLE_USER_MODULE -DUSER_FIRMWARE_IMAGE_SIZE=0x20000 -DUSER_FIRMWARE_IMAGE_LOCATION=0x80A0000 -DMODULAR_FIRMWARE=1 -DMODULE_VERSION=5 -DMODULE_FUNCTION=5 -DMODULE_INDEX=1 -DMODULE_DEPENDENCY=4,2,207 -DMODULE_DEPENDENCY2=0,0,0 -D_WINSOCK_H -D_GNU_SOURCE -DLOG_MODULE_CATEGORY="\"app\""  -fno-exceptions -fno-rtti -fcheck-new -std=gnu++11 -c -o ../build/target/user/platform-6-msrc/gxepd.o src/gxepd.cpp
In file included from lib/Adafruit_GFX_RK/src/Adafruit_GFX_RK.h:4:0,
                 from src/gxepd.cpp:2:
lib/Adafruit_GFX_RK/src/Adafruit_GFX.h:4:5: warning: "ARDUINO" is not defined [-Wundef]
 #if ARDUINO >= 100
     ^
gxepd.ino: In function 'void setup()':
gxepd.ino:33:76: error: call of overloaded 'drawImage(const unsigned char [11400], int, int, int, int, int, int, int)' is ambiguous
In file included from gxepd.ino:21:0:
lib/GxEPD2_PP/src/GxEPD2_3C.h:329:10: note: candidate: void GxEPD2_3C<GxEPD2_Type, page_height>::drawImage(const uint8_t*, int16_t, int16_t, int16_t, int16_t, bool, bool, bool) [with GxEPD2_Type = GxEPD2_750c; short unsigned int page_height = 96u; uint8_t = unsigned char; int16_t = short int]
     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)
          ^
lib/GxEPD2_PP/src/GxEPD2_3C.h:333:10: note: candidate: void GxEPD2_3C<GxEPD2_Type, page_height>::drawImage(const uint8_t*, const uint8_t*, int16_t, int16_t, int16_t, int16_t, bool, bool, bool) [with GxEPD2_Type = GxEPD2_750c; short unsigned int page_height = 96u; uint8_t = unsigned char; int16_t = short int]
     void drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false)
          ^
In file included from gxepd.ino:21:0:
lib/GxEPD2_PP/src/GxEPD2_3C.h: In instantiation of 'void GxEPD2_3C<GxEPD2_Type, page_height>::drawPixel(int16_t, int16_t, uint16_t) [with GxEPD2_Type = GxEPD2_750c; short unsigned int page_height = 96u; int16_t = short int; uint16_t = short unsigned int]':
gxepd.ino:38:1:   required from here
lib/GxEPD2_PP/src/GxEPD2_3C.h:101:7: warning: operation on '((GxEPD2_3C<GxEPD2_750c, 96u>*)this)->GxEPD2_3C<GxEPD2_750c, 96u>::_color_buffer[((int)i)]' may be undefined [-Wsequence-point]
       _color_buffer[i] = _color_buffer[i] = (_color_buffer[i] | (1 << (7 - x % 8)));
       ^
../build/module.mk:267: recipe for target '../build/target/user/platform-6-msrc/gxepd.o' failed
make[2]: Leaving directory '/firmware/user'
make[2]: *** [../build/target/user/platform-6-msrc/gxepd.o] Error 1
../../../build/recurse.mk:11: recipe for target 'user' failed
make[1]: Leaving directory '/firmware/modules/photon/user-part'
../build/recurse.mk:11: recipe for target 'modules/photon/user-part' failed
make[1]: *** [user] Error 2
make: *** [modules/photon/user-part] Error 2

If anybody wish to try out compiling the code it can be found here https://go.particle.io/shared_apps/5c156343cfed663a3100246b

Perhaps this should be the image I should be printing to the screen:

The compiler needs a little help! This example compiles:

// This #include statement was automatically added by the Particle IDE.
#include <GxEPD2_PP.h>

#include <GxEPD2_PP.h>
#include <Adafruit_GFX_RK.h>
#define ENABLE_GxEPD2_GFX 1
#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <FreeMonoBold9pt7b.h>
#include <GxEPD2_BW.h>
#include <GxEPD2_3C.h>

#if defined(PARTICLE)
GxEPD2_3C<GxEPD2_750c, GxEPD2_750c::HEIGHT / 4 > display(GxEPD2_750c(/*CS=D5*/ SS, /*DC=*/ A1, /*RST=*/ A0, /*BUSY=*/ D4));
//GxEPD2_BW < GxEPD2_750, GxEPD2_750::HEIGHT / 2 > display(GxEPD2_750(/*CS=D5*/ SS, /*DC=*/ A1, /*RST=*/ A0, /*BUSY=*/ D4));
#endif

//#include "images.h"
#include "bitmaps/Bitmaps400x300.h"

void setup()
{
  delay(1000);
  display.init(115200);
  display.drawImage(Bitmap400x300_1, 0, 0, 400, 300, bool(false), false, true);
}

void loop()
{
}

was wrong, true and false are of type int, not bool.

In my opinion the compiler still is wrong about ambiguity, as the second method doesn't match at all.

I have not yet decided if I change the library to cope with this compiler deficiency. Changing bool to int may be the best option.

While it might appear this way, appearance or opinion doesn't count - facts do.

With a numeric literal 0 you are falling into the implicit NULL pointer conversion trap.
NULL is just a fancy (more explicitly stating you mean a pointer) way of writing 0, but for the compiler it's exactly the same thing.
So if you look again at

display.drawImage(Bitmap400x300_1, 0, 0, 400, 300, false, false, true);

but apply the point above (and the fact that bool is internally represented as int), you could also see it as

display.drawImage(Bitmap400x300_1, NULL, 0, 400, 300, 0, 0, 1);

Now the second overload matches just as well (with the 9th parameter being defaulted).

To prove my point:
While this is ambiguous for above point

display.drawImage(Bitmap400x300_1, 0, 0, 400, 300, false, false, true);

this isn't for the same reason

display.drawImage(Bitmap400x300_1, 1, 0, 400, 300, false, false, true);
1 Like