Added GDEW042T2.

This commit is contained in:
imi415 2021-11-05 02:28:27 +08:00
parent 6cf59afebd
commit e08d953fcb
Signed by: imi415
GPG Key ID: 17F01E106F9F5E0A
9 changed files with 486 additions and 7 deletions

View File

@ -4,7 +4,8 @@ project(epd-spi)
set(EPD_SOURCES
"src/epd_common.c"
"src/epd_wfh0420cz35.c"
"src/epd_panel_wfh0420cz35.c"
"src/epd_panel_gdew042t2.c"
)
set(EPD_INCLUDES

View File

@ -3,6 +3,7 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
typedef enum { EPD_OK = 0, EPD_FAIL } epd_ret_t;
@ -21,7 +22,4 @@ typedef struct {
uint32_t y_end;
} epd_coord_t;
#define EPD_ASSERT(x) if(!(x)) for(;;) { /* ABORT. */}
#define EPD_ERROR_CHECK(x) if(x != EPD_OK) return EPD_FAIL
#endif

View File

@ -0,0 +1,26 @@
#ifndef EPD_GDEW042T2_H
#define EPD_GDEW042T2_H
#include "epd_common.h"
/**
* @brief This display module has UC8176 controller IC,
* with BW partial or 4 grayscale LUT.
*
*/
typedef enum {
EPD_GDEW042T2_MODE_GS = 0U, /* Grayscale mode */
EPD_GDEW042T2_MODE_BW = 1U, /* B/W mode */
EPD_GDEW042T2_MODE_BW_PART = 2U, /* B/W mode with partial flush */
} epd_gdew042t2_mode_t;
typedef struct {
void *user_data;
epd_gdew042t2_mode_t mode;
epd_cb_t cb;
} epd_gdew042t2_t;
epd_ret_t epd_gdew042t2_upload(epd_gdew042t2_t *epd, epd_coord_t *coord, uint8_t *data1, uint8_t *data2);
#endif

View File

@ -0,0 +1,185 @@
#ifndef EPD_GDEW042T2_LUT_H
#define EPD_GDEW042T2_LUT_H
#include <stdint.h>
/**
* @brief Note for LUTs:
* LUTs are stored in arrays at the following order:
* VCOM WW BW WB BB WW(??),
* VCOM LUT has 44 bytes, while others has 42 bytes.
*
*/
typedef struct {
uint8_t VCOM[44];
uint8_t WW[42];
uint8_t BW[42];
uint8_t WB[42];
uint8_t BB[42];
} gdew042t2_lut_t;
// LUT waveforms
static gdew042t2_lut_t gdew042t2_lut[3] = {
{
// Grayscale
.VCOM =
{
0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, //
0x60, 0x14, 0x14, 0x00, 0x00, 0x01, //
0x00, 0x14, 0x00, 0x00, 0x00, 0x01, //
0x00, 0x13, 0x0A, 0x01, 0x00, 0x01, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
},
.WW =
{
0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, //
0x90, 0x14, 0x14, 0x00, 0x00, 0x01, //
0x10, 0x14, 0x0A, 0x00, 0x00, 0x01, //
0xA0, 0x13, 0x01, 0x00, 0x00, 0x01, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
},
.BW =
{
0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, //
0x90, 0x14, 0x14, 0x00, 0x00, 0x01, //
0x00, 0x14, 0x0A, 0x00, 0x00, 0x01, //
0x99, 0x0C, 0x01, 0x03, 0x04, 0x01, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
},
.WB =
{
0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, //
0x90, 0x14, 0x14, 0x00, 0x00, 0x01, //
0x00, 0x14, 0x0A, 0x00, 0x00, 0x01, //
0x99, 0x0B, 0x04, 0x04, 0x01, 0x01, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
},
.BB =
{
0x80, 0x0A, 0x00, 0x00, 0x00, 0x01, //
0x90, 0x14, 0x14, 0x00, 0x00, 0x01, //
0x20, 0x14, 0x0A, 0x00, 0x00, 0x01, //
0x50, 0x13, 0x01, 0x00, 0x00, 0x01, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
},
},
{
// BW
.VCOM =
{
0x00, 0x17, 0x00, 0x00, 0x00, 0x02, //
0x00, 0x17, 0x17, 0x00, 0x00, 0x02, //
0x00, 0x0A, 0x01, 0x00, 0x00, 0x01, //
0x00, 0x0E, 0x0E, 0x00, 0x00, 0x02, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
},
.WW =
{
0x40, 0x17, 0x00, 0x00, 0x00, 0x02, //
0x90, 0x17, 0x17, 0x00, 0x00, 0x02, //
0x40, 0x0A, 0x01, 0x00, 0x00, 0x01, //
0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
},
.BW =
{
0x40, 0x17, 0x00, 0x00, 0x00, 0x02, //
0x90, 0x17, 0x17, 0x00, 0x00, 0x02, //
0x40, 0x0A, 0x01, 0x00, 0x00, 0x01, //
0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
},
.WB =
{
0x80, 0x17, 0x00, 0x00, 0x00, 0x02, //
0x90, 0x17, 0x17, 0x00, 0x00, 0x02, //
0x80, 0x0A, 0x01, 0x00, 0x00, 0x01, //
0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
},
.BB =
{
0x80, 0x17, 0x00, 0x00, 0x00, 0x02, //
0x90, 0x17, 0x17, 0x00, 0x00, 0x02, //
0x80, 0x0A, 0x01, 0x00, 0x00, 0x01, //
0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
},
},
{
// BW Partial
.VCOM =
{
0x00, 0x19, 0x01, 0x00, 0x00, 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, //
},
.WW =
{
0x00, 0x19, 0x01, 0x00, 0x00, 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, //
},
.BW =
{
0x80, 0x19, 0x01, 0x00, 0x00, 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, //
},
.WB =
{
0x40, 0x19, 0x01, 0x00, 0x00, 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, //
},
.BB =
{
0x00, 0x19, 0x01, 0x00, 0x00, 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, //
},
},
};
#endif

View File

@ -3,6 +3,11 @@
#include "epd_common.h"
/**
* @brief This display module has UC8176 controller IC, with BWR LUT stored in OTP.
*
*/
typedef struct {
void *user_data;
epd_cb_t cb;

View File

@ -3,6 +3,9 @@
#include "epd_common.h"
#define EPD_ASSERT(x) if(!(x)) for(;;) { /* ABORT. */}
#define EPD_ERROR_CHECK(x) if(x != EPD_OK) return EPD_FAIL
epd_ret_t epd_common_execute_sequence(epd_cb_t *cb, void *user_data, uint8_t *seq, uint32_t seq_len);
#endif

View File

@ -1,4 +1,4 @@
#include "epd_common.h"
#include "epd_private.h"
/**
* @brief Execute command sequence.

220
src/epd_panel_gdew042t2.c Normal file
View File

@ -0,0 +1,220 @@
#include "epd_panel_gdew042t2.h"
#include "epd_panel_gdew042t2_lut.h"
#include "epd_private.h"
#define DTM1 0x10
#define DTM2 0x13
static uint8_t epd_gdew042t2_init_sequence_bw[] = {
0x04, 0x01, 0x03, 0x00, 0x2B, 0x2B, // PWR setting
0x03, 0x06, 0x17, 0x17, 0x17, // Boost
};
static uint8_t epd_gdew042t2_init_sequence_gs[] = {
0x05, 0x01, 0x03, 0x00, 0x2B, 0x2B, 0x13, // PWR setting
0x03, 0x06, 0x17, 0x17, 0x17, // Boost
};
static uint8_t epd_gdew042t2_init_sequence_bw_2[] = {
0x02, 0x00, 0xBF, 0x0D, // Panel settings
0x01, 0x30, 0x3C, // PLL
0x04, 0x61, 0x01, 0x90, 0x01, 0x2C, // Resolution
0x01, 0x82, 0x28, // VCOM DC
0x01, 0x50, 0x97, // VCOM/Data Interval
};
static uint8_t epd_gdew042t2_init_sequence_gs_2[] = {
0x01, 0x00, 0x3F, // Panel settings
0x01, 0x30, 0x3C, // PLL
0x04, 0x61, 0x01, 0x90, 0x01, 0x2C, // Resolution
0x01, 0x82, 0x12, // VCOM DC
0x01, 0x50, 0x97, // VCOM/Data Interval
};
static epd_ret_t epd_gdew042t2_write_lut(epd_gdew042t2_t *epd) {
uint8_t tx_buf[45];
tx_buf[0] = 0x20; // Write VCOM LUT
memcpy(&tx_buf[1], gdew042t2_lut[epd->mode].VCOM, 44);
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 45));
tx_buf[0] = 0x21; // Write WW LUT
memcpy(&tx_buf[1], gdew042t2_lut[epd->mode].WW, 42);
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 42));
tx_buf[0] = 0x22; // Write BW LUT
memcpy(&tx_buf[1], gdew042t2_lut[epd->mode].BW, 42);
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 42));
tx_buf[0] = 0x23; // Write WB LUT
memcpy(&tx_buf[1], gdew042t2_lut[epd->mode].WB, 42);
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 42));
tx_buf[0] = 0x24; // Write BB LUT
memcpy(&tx_buf[1], gdew042t2_lut[epd->mode].BB, 42);
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 42));
if (epd->mode == EPD_GDEW042T2_MODE_GS) {
tx_buf[0] = 0x25; // Write mysterious WW2 LUT
memcpy(&tx_buf[1], gdew042t2_lut[epd->mode].WW, 42);
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 42));
}
return EPD_OK;
}
static epd_ret_t epd_gdew042t2_init(epd_gdew042t2_t *epd) {
EPD_ASSERT(epd);
EPD_ASSERT(epd->cb.reset_cb);
EPD_ASSERT(epd->cb.write_command_cb);
EPD_ASSERT(epd->cb.poll_busy_cb);
EPD_ERROR_CHECK(epd->cb.reset_cb(epd->user_data));
// Pre power-on settings
if (epd->mode != EPD_GDEW042T2_MODE_GS) {
EPD_ERROR_CHECK(epd_common_execute_sequence(&epd->cb, epd->user_data, epd_gdew042t2_init_sequence_bw,
sizeof(epd_gdew042t2_init_sequence_bw)));
} else {
EPD_ERROR_CHECK(epd_common_execute_sequence(&epd->cb, epd->user_data, epd_gdew042t2_init_sequence_gs,
sizeof(epd_gdew042t2_init_sequence_gs)));
}
// Issue power on command
uint8_t tx_buf[2] = {0x04, 0x00};
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 0x01));
EPD_ERROR_CHECK(epd->cb.poll_busy_cb(epd->user_data));
// Post power-on settings
if (epd->mode != EPD_GDEW042T2_MODE_GS) {
EPD_ERROR_CHECK(epd_common_execute_sequence(&epd->cb, epd->user_data, epd_gdew042t2_init_sequence_bw_2,
sizeof(epd_gdew042t2_init_sequence_bw_2)));
} else {
EPD_ERROR_CHECK(epd_common_execute_sequence(&epd->cb, epd->user_data, epd_gdew042t2_init_sequence_gs_2,
sizeof(epd_gdew042t2_init_sequence_gs_2)));
}
return EPD_OK;
}
/**
* @brief Enable partial mode for UC8176 IC
* and set partial mode window.
*
* @param epd pointer to epd_gdew042t2_t
* @param coord pointer to epd_coord_t
* @return epd_ret_t EPD_OK for success, EPD_FAIL for error.
*/
static epd_ret_t epd_gdew042t2_partial(epd_gdew042t2_t *epd, epd_coord_t *coord) {
EPD_ASSERT(epd);
EPD_ASSERT(epd->cb.write_command_cb);
// Partial In
uint8_t tx_buf[10] = {0x91, 0x00};
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 1));
// Partial window
tx_buf[0] = 0x90;
tx_buf[1] = (coord->x_start >> 8U) & 0x01U;
tx_buf[2] = coord->x_start & 0xF8U; // Bank number, last 3 LSBs must be zero.
tx_buf[3] = (coord->x_end >> 8U) & 0x01U;
tx_buf[4] = coord->x_end & 0xF8U; // Same as above.
tx_buf[5] = (coord->y_start >> 8U) & 0x01U;
tx_buf[6] = coord->y_start & 0xFFU;
tx_buf[7] = (coord->y_end >> 8U) & 0x01U;
tx_buf[8] = coord->y_end & 0xFFU;
tx_buf[9] = 0x01; // Only scan partial area.
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 10));
return EPD_OK;
}
/**
* @brief Issue UC8176 DTM1 or DTM2 command, with payload data and stop command.
*
* @param epd pointer to epd_gdew042t2_t
* @param dtm_num DTM1 or DTM2
* @param data payload pixel data
* @param len payload data length, calculated as bytes
* @return epd_ret_t EPD_OK for success, EPD_FAIL for error.
*/
static epd_ret_t epd_gdew042t2_dtm(epd_gdew042t2_t *epd, uint8_t dtm_num, uint8_t *data, uint32_t len) {
EPD_ASSERT(epd);
EPD_ASSERT(epd->cb.write_command_cb);
uint8_t tx_buf[2] = {dtm_num};
// Issue DTM1 or DTM2 command
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 0x01));
// Send data
EPD_ERROR_CHECK(epd->cb.write_data_cb(epd->user_data, data, len));
// Issue DSP command.
tx_buf[0] = 0x11;
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 0x01));
return EPD_OK;
}
/**
* @brief Issue display update command and enter deep-sleep mode.
* Deep-sleep mode can only exits with a hardware reset.
* @param epd pointer to epd_gdew042t2_t
* @return epd_ret_t EPD_OK for success, EPD_FAIL for error.
*/
static epd_ret_t epd_gdew042t2_update_and_sleep(epd_gdew042t2_t *epd) {
EPD_ASSERT(epd);
EPD_ASSERT(epd->cb.write_command_cb);
EPD_ASSERT(epd->cb.delay_cb);
// Issue DRF command
uint8_t tx_buf[2] = {0x12, 0x00};
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 0x01));
// Delay 100ms and wait for busy
EPD_ERROR_CHECK(epd->cb.delay_cb(epd->user_data, 100));
EPD_ERROR_CHECK(epd->cb.poll_busy_cb(epd->user_data));
// Issue POF command
tx_buf[0] = 0x02;
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 0x01));
EPD_ERROR_CHECK(epd->cb.poll_busy_cb(epd->user_data));
// Issue DSLP command
tx_buf[0] = 0x07;
tx_buf[1] = 0xA5;
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 0x02));
return EPD_OK;
}
/**
* @brief Initialize display, upload frame buffer and refresh.
* Then goes to deep-sleep mode to conserve power.
* This is the only function needs to be called by the user.
*
* @param epd pointer to epd_gdew042t2_t
* @param coord pointer to epd_coord_t, x_start or x_end MUST be wrapped to 8 pixel boundaries.
* @param data1 bw data or old data array
* @param data2 bw data or new data array
* @return epd_ret_t EPD_OK for success, EPD_FAIL for error.
*/
epd_ret_t epd_gdew042t2_upload(epd_gdew042t2_t *epd, epd_coord_t *coord, uint8_t *data1, uint8_t *data2) {
EPD_ERROR_CHECK(epd_gdew042t2_init(epd));
EPD_ERROR_CHECK(epd_gdew042t2_write_lut(epd));
EPD_ERROR_CHECK(epd_gdew042t2_partial(epd, coord));
uint8_t bank_start = coord->x_start / 8; // Wrap to bank
uint8_t bank_end = coord->x_end / 8; // Wrap to bank
uint32_t tx_len = (bank_end - bank_start + 1) * (coord->y_end - coord->y_start + 1);
if (epd->mode != EPD_GDEW042T2_MODE_BW) {
EPD_ERROR_CHECK(epd_gdew042t2_dtm(epd, DTM1, data1, tx_len));
}
EPD_ERROR_CHECK(epd_gdew042t2_dtm(epd, DTM2, data2, tx_len));
EPD_ERROR_CHECK(epd_gdew042t2_update_and_sleep(epd));
return EPD_OK;
}

View File

@ -1,4 +1,4 @@
#include "epd_wfh0420cz35.h"
#include "epd_panel_wfh0420cz35.h"
#include "epd_private.h"
@ -9,6 +9,13 @@ static uint8_t epd_wfh0420_init_sequence[] = {
0x03, 0x06, 0x17, 0x17, 0x17,
};
/**
* @brief This function initialize the driver IC and
* enable internal power supplies.
*
* @param epd pointer to epd_wfh0420_t
* @return epd_ret_t EPD_OK for success, EPD_FAIL for error.
*/
static epd_ret_t epd_wfh0420_init(epd_wfh0420_t *epd) {
EPD_ASSERT(epd);
EPD_ASSERT(epd->cb.reset_cb);
@ -34,6 +41,14 @@ static epd_ret_t epd_wfh0420_init(epd_wfh0420_t *epd) {
return EPD_OK;
}
/**
* @brief Enable partial mode for UC8176 IC
* and set partial mode window.
*
* @param epd pointer to epd_wfh0420_t
* @param coord pointer to epd_coord_t
* @return epd_ret_t EPD_OK for success, EPD_FAIL for error.
*/
static epd_ret_t epd_wfh0420_partial(epd_wfh0420_t *epd, epd_coord_t *coord) {
EPD_ASSERT(epd);
EPD_ASSERT(epd->cb.write_command_cb);
@ -52,12 +67,21 @@ static epd_ret_t epd_wfh0420_partial(epd_wfh0420_t *epd, epd_coord_t *coord) {
tx_buf[6] = coord->y_start & 0xFFU;
tx_buf[7] = (coord->y_end >> 8U) & 0x01U;
tx_buf[8] = coord->y_end & 0xFFU;
tx_buf[9] = 0x01; // Only scan partial area.
tx_buf[9] = 0x01; // Only scan partial area.
EPD_ERROR_CHECK(epd->cb.write_command_cb(epd->user_data, tx_buf, 10));
return EPD_OK;
}
/**
* @brief Issue UC8176 DTM1 or DTM2 command, with payload data and stop command.
*
* @param epd pointer to epd_wfh0420_t
* @param dtm_num DTM1 or DTM2
* @param data payload pixel data
* @param len payload data length, calculated as bytes
* @return epd_ret_t EPD_OK for success, EPD_FAIL for error.
*/
static epd_ret_t epd_wfh0420_dtm(epd_wfh0420_t *epd, uint8_t dtm_num, uint8_t *data, uint32_t len) {
EPD_ASSERT(epd);
EPD_ASSERT(epd->cb.write_command_cb);
@ -75,6 +99,12 @@ static epd_ret_t epd_wfh0420_dtm(epd_wfh0420_t *epd, uint8_t dtm_num, uint8_t *d
return EPD_OK;
}
/**
* @brief Issue display update command and enter deep-sleep mode.
* Deep-sleep mode can only exits with a hardware reset.
* @param epd pointer to epd_wfh0420_t
* @return epd_ret_t EPD_OK for success, EPD_FAIL for error.
*/
static epd_ret_t epd_wfh0420_update_and_sleep(epd_wfh0420_t *epd) {
EPD_ASSERT(epd);
EPD_ASSERT(epd->cb.write_command_cb);
@ -101,6 +131,17 @@ static epd_ret_t epd_wfh0420_update_and_sleep(epd_wfh0420_t *epd) {
return EPD_OK;
}
/**
* @brief Initialize display, upload frame buffer and refresh.
* Then goes to deep-sleep mode to conserve power.
* This is the only function needs to be called by the user.
*
* @param epd pointer to epd_wfh0420_t
* @param coord pointer to epd_coord_t, x_start or x_end MUST be wrapped to 8 pixel boundaries.
* @param red_data red pixel data array, bit 0 for red, bit 1 for white
* @param bw_data black pixel data array, bit 0 for black, bit 1 for white
* @return epd_ret_t EPD_OK for success, EPD_FAIL for error.
*/
epd_ret_t epd_wfh0420_upload(epd_wfh0420_t *epd, epd_coord_t *coord, uint8_t *red_data, uint8_t *bw_data) {
EPD_ERROR_CHECK(epd_wfh0420_init(epd));
EPD_ERROR_CHECK(epd_wfh0420_partial(epd, coord));