0

I've put together quite a nice little ePaper display clock with the Raspberryp Pi Zero W running Buster. I'm using the Waveshare 6" kit (display and controller board).

Has anyone here had any experience with the "Waveshare" ePaper displays and the code that runs them?

The problem I'm having is that the dispaly only 4 seconds after I've sent the command to update the display - the actual screen update, between the old display and the new one, is less than half a second.

I know that there is a lot of unnessesary code in the program that updates the display. The problem that I have is that I think it's written in C++ and I do not know C++ (or C, or C#) and therefore do not know how to update that code (so that it will still work).

Ideally I want to get it to the point that it will send the bitmap image to the display and have the display update with, at most, a 1 second delay. (I want my clock to be acturate to within a second).

It uses a program called IT8951 and you need to build it yourself.

Here's the IT8951.h file:

#ifndef _IT8951_H_
#define _IT8951_H_

#include <bcm2835.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "miniGUI.h"

#define CS              8
#define HRDY            24
#define RESET           17
#define VCOM            1500 //e.g. -1.53 = 1530 = 0x5FA

//prototype of structure
//structure prototype 1
typedef struct IT8951LdImgInfo
{
    uint16_t usEndianType; //little or Big Endian
    uint16_t usPixelFormat; //bpp
    uint16_t usRotate; //Rotate mode
    uint32_t ulStartFBAddr; //Start address of source Frame buffer
    uint32_t ulImgBufBaseAddr;//Base address of target image buffer

}IT8951LdImgInfo;

//structure prototype 2
typedef struct IT8951AreaImgInfo
{
    uint16_t usX;
    uint16_t usY;
    uint16_t usWidth;
    uint16_t usHeight;
}IT8951AreaImgInfo;

typedef struct
{
    uint16_t usPanelW;
    uint16_t usPanelH;
    uint16_t usImgBufAddrL;
    uint16_t usImgBufAddrH;
    uint16_t usFWVersion[8];    //16 Bytes String
    uint16_t usLUTVersion[8];   //16 Bytes String
}IT8951DevInfo;

//Built in I80 Command Code
#define IT8951_TCON_SYS_RUN      0x0001
#define IT8951_TCON_STANDBY      0x0002
#define IT8951_TCON_SLEEP        0x0003
#define IT8951_TCON_REG_RD       0x0010
#define IT8951_TCON_REG_WR       0x0011
#define IT8951_TCON_MEM_BST_RD_T 0x0012
#define IT8951_TCON_MEM_BST_RD_S 0x0013
#define IT8951_TCON_MEM_BST_WR   0x0014
#define IT8951_TCON_MEM_BST_END  0x0015
#define IT8951_TCON_LD_IMG       0x0020
#define IT8951_TCON_LD_IMG_AREA  0x0021
#define IT8951_TCON_LD_IMG_END   0x0022

//I80 User defined command code
#define USDEF_I80_CMD_DPY_AREA     0x0034
#define USDEF_I80_CMD_GET_DEV_INFO 0x0302
#define USDEF_I80_CMD_DPY_BUF_AREA 0x0037
#define USDEF_I80_CMD_VCOM         0x0039

//Panel
#define IT8951_PANEL_WIDTH   1024 //it Get Device information
#define IT8951_PANEL_HEIGHT   758

//Rotate mode
#define IT8951_ROTATE_0     0
#define IT8951_ROTATE_90    1
#define IT8951_ROTATE_180   2
#define IT8951_ROTATE_270   3

//Pixel mode , BPP - Bit per Pixel
#define IT8951_2BPP   0
#define IT8951_3BPP   1
#define IT8951_4BPP   2
#define IT8951_8BPP   3

//Waveform Mode
#define IT8951_MODE_0   0
#define IT8951_MODE_1   1
#define IT8951_MODE_2   2
#define IT8951_MODE_3   3
#define IT8951_MODE_4   4
//Endian Type
#define IT8951_LDIMG_L_ENDIAN   0
#define IT8951_LDIMG_B_ENDIAN   1
//Auto LUT
#define IT8951_DIS_AUTO_LUT   0
#define IT8951_EN_AUTO_LUT    1
//LUT Engine Status
#define IT8951_ALL_LUTE_BUSY 0xFFFF

//-----------------------------------------------------------------------
// IT8951 TCon Registers defines
//-----------------------------------------------------------------------
//Register Base Address
#define DISPLAY_REG_BASE 0x1000               //Register RW access for I80 only
//Base Address of Basic LUT Registers
#define LUT0EWHR  (DISPLAY_REG_BASE + 0x00)   //LUT0 Engine Width Height Reg
#define LUT0XYR   (DISPLAY_REG_BASE + 0x40)   //LUT0 XY Reg
#define LUT0BADDR (DISPLAY_REG_BASE + 0x80)   //LUT0 Base Address Reg
#define LUT0MFN   (DISPLAY_REG_BASE + 0xC0)   //LUT0 Mode and Frame number Reg
#define LUT01AF   (DISPLAY_REG_BASE + 0x114)  //LUT0 and LUT1 Active Flag Reg
//Update Parameter Setting Register
#define UP0SR (DISPLAY_REG_BASE + 0x134)      //Update Parameter0 Setting Reg

#define UP1SR     (DISPLAY_REG_BASE + 0x138)  //Update Parameter1 Setting Reg
#define LUT0ABFRV (DISPLAY_REG_BASE + 0x13C)  //LUT0 Alpha blend and Fill rectangle Value
#define UPBBADDR  (DISPLAY_REG_BASE + 0x17C)  //Update Buffer Base Address
#define LUT0IMXY  (DISPLAY_REG_BASE + 0x180)  //LUT0 Image buffer X/Y offset Reg
#define LUTAFSR   (DISPLAY_REG_BASE + 0x224)  //LUT Status Reg (status of All LUT Engines)

#define BGVR      (DISPLAY_REG_BASE + 0x250)  //Bitmap (1bpp) image color table
//-------System Registers----------------
#define SYS_REG_BASE 0x0000

//Address of System Registers
#define I80CPCR (SYS_REG_BASE + 0x04)
//-------Memory Converter Registers----------------
#define MCSR_BASE_ADDR 0x0200
#define MCSR (MCSR_BASE_ADDR  + 0x0000)
#define LISAR (MCSR_BASE_ADDR + 0x0008)

uint8_t IT8951_Init(void);
void IT8951_Cancel(void);
void IT8951DisplayExample(void);
void IT8951DisplayExample2(void);
void IT8951Display1bppExample2(void);
void IT8951DisplayExample3(void);
void IT8951_GUI_Example(void);
void IT8951_BMP_Example(uint32_t x, uint32_t y,char *path);

uint16_t IT8951ReadReg(uint16_t usRegAddr);
void IT8951SetImgBufBaseAddr(uint32_t ulImgBufAddr);
void LCDWaitForReady(void);
void GetIT8951SystemInfo(void* pBuf);
void gpio_i80_16b_cmd_out(uint16_t usCmd);
void GPIO_Configuration_Out(void);
void GPIO_Configuration_In(void);

void IT8951DisplayClear(void);

//uint16_t IT8951ReadReg(uint16_t usRegAddr);
void IT8951WriteReg(uint16_t usRegAddr,uint16_t usValue);

uint16_t IT8951GetVCOM(void);
void IT8951SetVCOM(uint16_t vcom);

#endif

I think I can take out (or comment out):

void IT8951DisplayExample(void);
void IT8951DisplayExample2(void);
void IT8951Display1bppExample2(void);
void IT8951DisplayExample3(void);
void IT8951_GUI_Example(void);
void IT8951_BMP_Example(uint32_t x, uint32_t y,char *path);

and maybe even a lot more.

Although, I'm not 100% sure. What I think is that the lines in this file call the actual code from the IT8951.c file (which is quite a bit larger). Ideally, I'd like to take all the unnessesary code out of the .c file so that it doesn't get run, or even read, which may be slowing the whole process down.

0
0

If anyone ins insterested, I've worked around the problem. I generate the image a minute in advance, then sleep the script for n-seconds until 4-seconds to the next minute and then send the update to the display. That way the screen update happens at around the same time.

Here's the code that I'm using to achieve this:

    # IF WE'VE JUST REBOOTED
    if [[ $READY = 0 ]]; # $READY IS SET ELSEWHERE /tmp/ TO 0 ON REBOOT
    then
        # AS WE'VE RUN SOME CODE SINCE REBOOTING, SET THE READY FLAG TO 1
        echo "1" > /opt/cl0ck/status.rdy
        # DRAW THE GRAPH TO BE SENT TO DISPLAY
        MINUTENOW # THIS FUNCTION JUST SENTS SOME VARIABLES FOR THE TIME TO BE DRAWN AS THE CURRENT TIME
        DIGITAL # THIS FUNCTION ACTUALLY DRAWS UP THE IMAGE TO BE SENT TO THE DISPLAY
    else # THIS IS WHAT HAPPENS IF WE HAVEN'T JUST REBOOTED
        # SET THE TIME TO THE NEXT MINUTE
        MINUTEPLUS # SETS THE SAME VARIABLES AS IN THE "MINUTENOW FUNCTION, BUT ONE MINUTE IN THE FUTURE"
        # GET THE IMAGE READY
        DIGITAL # THIS FUNCTION ACTUALLY DRAWS UP THE IMAGE TO BE SENT TO THE DISPLAY
        # GET TIME RIGHT NOW IN EPOCH
        NOWTIME=$(date +%s)
        # THEN GET THE TIME AT THE START OF THE NEXT MINUTE IN EPOCH
        NEXTMINUTE=$(date -d $(date -d '1 minute' +%H:%M) +%s)
        # THEN SUBTRACT 4 SECONDS
        FOURBEFORE=$((($NEXTMINUTE - 4)))
        # TIME UNTIL THEN
        WAITFOR=$((($FOURBEFORE - $NOWTIME)))
        # THEN WAIT UNTIL THEN
        sleep ${WAITFOR}
    fi
UPDATE #THIS FUNCTION ACTAULLY SENDS THE IMAGE TO BE DISPLAYED ON THE ePAPER DISPLAY

The reason that I have to calculate the time needed to sleep each time is that every 5th minute I curl the weather forecast from a weather service provider and then do a whole bunch of stuff with it. That means that once every 5 minutes, the script time will be (up to 20, but as low as 3 seconds) longer than the other 4 depending on the status of the net.

1
  • I'm not going to mark this answer as correct as I would really like to get that 4 seconds down to 1 or even less. However, it is a workaround. So if someone wants to use the code - they're welcome to it.
    – Jim
    Feb 21 '21 at 22:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.