refactor and cleanup drivers

This commit is contained in:
Shuanglei Tao
2025-10-14 22:51:44 +08:00
parent 3ce8200c11
commit bef12de419
8 changed files with 159 additions and 249 deletions

View File

@@ -22,7 +22,15 @@
#include "nrf_gpio.h"
#include "EPD_config.h"
#define BIT(n) (1UL << (n))
typedef enum
{
EPD_DRIVER_IC_UC8176 = 1,
EPD_DRIVER_IC_SSD1619 = 2,
EPD_DRIVER_IC_JD79668 = 3,
EPD_DRIVER_IC_UC8159 = 4,
EPD_DRIVER_IC_UC8179 = 5,
EPD_DRIVER_IC_SSD1677 = 6,
} epd_driver_ic_t;
/**@brief EPD driver structure.
*
@@ -30,6 +38,8 @@
*/
typedef struct
{
epd_driver_ic_t ic; /**< EPD driver IC type */
void (*init)(); /**< Initialize the e-Paper register */
void (*clear)(bool refresh); /**< Clear screen */
void (*write_image)(uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h); /**< write image */

View File

@@ -1,201 +0,0 @@
/**
* Based on GDEM042F52 driver from Good Display
* https://www.good-display.com/product/564.html
*/
#include "EPD_driver.h"
#include "nrf_log.h"
// Driver command list.
#define CMD_PSR 0x00 // Panel Setting Register
#define CMD_PWR 0x01 // Power Setting Register
#define CMD_POF 0x02 // Power OFF Command
#define CMD_PFS 0x03 // Power OFF Sequence Setting
#define CMD_PON 0x04 // Power ON Command
#define CMD_BTST 0x06 // Booster Soft Start Command
#define CMD_DSLP 0x07 // Deep sleep Command
#define CMD_DTM 0x10 // Display Start Transmission Register
#define CMD_DSP 0x11 // Data Stop Command
#define CMD_DRF 0x12 // Display Refresh Command
#define CMD_AUTO 0x17 // Auto Sequence
#define CMD_PLL 0x30 // PLL control Register
#define CMD_TSC 0x40 // Temperature Sensor Command
#define CMD_TSE 0x41 // Temperature Sensor Calibration Register
#define CMD_TSW 0x42 // Temperature Sensor Write Register
#define CMD_TSR 0x43 // Temperature Sensor Read Register
#define CMD_CDI 0x50 // VCOM and DATA interval setting Register
#define CMD_LPD 0x51 // Lower Power Detection Register
#define CMD_TRES 0x61 // Resolution setting
#define CMD_GSST 0x65 // Gate/Source Start Setting Register
#define CMD_REV 0x70 // REVISION Register
#define CMD_AMV 0x80 // Auto Measure VCOM Register
#define CMD_VV 0x81 // VCOM Value Register
#define CMD_VDCS 0x82 // VCOM_DC Setting Register
#define CMD_PTL 0x83 // Partial Window Register
#define CMD_PGM 0x90 // Program Mode
#define CMD_APG 0x91 // Active Program
#define CMD_RMTP 0x92 // Read MTP Data
#define CMD_PGM_CFG 0xA2 // MTP Program Config Register
#define CMD_CCSET 0xE0 // Cascade Setting
#define CMD_PWS 0xE3 // Power Saving Register
#define CMD_LVSEL 0xE4 // LVD Voltage Select Register
static void JD79xx_WaitBusy(uint16_t timeout)
{
EPD_WaitBusy(LOW, timeout);
}
static void JD79xx_PowerOn(void)
{
EPD_WriteCmd(CMD_PON);
JD79xx_WaitBusy(200);
}
static void JD79xx_PowerOff(void)
{
EPD_WriteCmd(CMD_POF);
JD79xx_WaitBusy(200);
}
int8_t JD79xx_Read_Temp(void)
{
EPD_WriteCmd(CMD_TSC);
JD79xx_WaitBusy(100);
return (int8_t)EPD_ReadByte();
}
static void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
EPD_Write(CMD_PTL,
x / 256, x % 256,
(x + w - 1) / 256, (x + w - 1) % 256,
y / 256, y % 256,
(y + h - 1) / 256, (y + h - 1) % 256,
0x01);
}
// Full update: 20s
void JD79xx_Init()
{
epd_model_t *EPD = epd_get();
EPD_Reset(HIGH, 50);
EPD_Write(0x4D, 0x78);
EPD_Write(CMD_PSR, 0x0F, 0x29);
EPD_Write(CMD_BTST, 0x0D, 0x12, 0x24, 0x25, 0x12, 0x29, 0x10);
EPD_Write(CMD_PLL, 0x08);
EPD_Write(CMD_CDI, 0x37);
EPD_Write(CMD_TRES,
EPD->width / 256, EPD->width % 256,
EPD->height / 256, EPD->height % 256);
EPD_Write(0xAE, 0xCF);
EPD_Write(0xB0, 0x13);
EPD_Write(0xBD, 0x07);
EPD_Write(0xBE, 0xFE);
EPD_Write(0xE9, 0x01);
JD79xx_PowerOn();
}
// Fast update: 12s
void JD79xx_Init_Fast()
{
epd_model_t *EPD = epd_get();
EPD_Reset(HIGH, 50);
EPD_Write(0x4D, 0x78);
EPD_Write(CMD_PSR, 0x0F, 0x29);
EPD_Write(CMD_PWR, 0x07, 0x00);
EPD_Write(CMD_PFS, 0x10, 0x54, 0x44);
EPD_Write(CMD_BTST, 0x0F, 0x0A, 0x2F, 0x25, 0x22, 0x2E, 0x21);
EPD_Write(CMD_CDI, 0x37);
EPD_Write(CMD_TRES,
EPD->width / 256, EPD->width % 256,
EPD->height / 256, EPD->height % 256);
EPD_Write(CMD_PWS, 0x22);
EPD_Write(0xB6, 0x6F);
EPD_Write(0xB4, 0xD0);
EPD_Write(0xE9, 0x01);
EPD_Write(CMD_PLL, 0x08);
JD79xx_PowerOn();
EPD_Write(CMD_CCSET, 0x02);
EPD_Write(0xE6, 0x5A);
EPD_Write(0xA5, 0x00);
JD79xx_WaitBusy(200);
}
static void JD79xx_Refresh(void)
{
NRF_LOG_DEBUG("[EPD]: refresh begin\n");
epd_model_t *EPD = epd_get();
_setPartialRamArea(0, 0, EPD->width, EPD->height);
EPD_Write(CMD_DRF, 0x00);
JD79xx_WaitBusy(30000);
NRF_LOG_DEBUG("[EPD]: refresh end\n");
}
void JD79xx_Clear(bool refresh)
{
epd_model_t *EPD = epd_get();
uint32_t ram_bytes = ((EPD->width + 3) / 4) * EPD->height;
EPD_FillRAM(CMD_DTM, 0x55, ram_bytes);
if (refresh)
JD79xx_Refresh();
}
void JD79xx_Write_Image(uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
epd_model_t *EPD = epd_get();
uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
x -= x % 8; // byte boundary
w = wb * 8; // byte boundary
if (x + w > EPD->width || y + h > EPD->height)
return;
_setPartialRamArea(x, y, w, h);
EPD_WriteCmd(CMD_DTM);
for (uint16_t i = 0; i < h * 2; i++) // 2 bits per pixel
{
for (uint16_t j = 0; j < w / 8; j++)
EPD_WriteByte(black ? black[j + i * wb] : 0x55);
}
}
void JD79xx_Write_Ram(uint8_t cfg, uint8_t *data, uint8_t len)
{
bool begin = (cfg >> 4) == 0x00;
if (begin)
EPD_WriteCmd(CMD_DTM);
EPD_WriteData(data, len);
}
void JD79xx_Sleep(void)
{
JD79xx_PowerOff();
delay(100);
EPD_Write(CMD_DSLP, 0xA5); // deep sleep
}
static epd_driver_t epd_drv_JD79668 = {
.init = JD79xx_Init,
.clear = JD79xx_Clear,
.write_image = JD79xx_Write_Image,
.write_ram = JD79xx_Write_Ram,
.refresh = JD79xx_Refresh,
.sleep = JD79xx_Sleep,
.read_temp = JD79xx_Read_Temp,
};
// JD79668 400x300 Black/White/Red/Yellow
const epd_model_t epd_jd79668_420 = {
.id = EPD_JD79668_420_BWRY,
.color = BWRY,
.drv = &epd_drv_JD79668,
.width = 400,
.height = 300,
};

View File

@@ -82,7 +82,7 @@ static void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
epd_model_t *EPD = epd_get();
EPD_Write(CMD_ENTRY_MODE, 0x03); // set ram entry mode: x increase, y increase
if (EPD->id == EPD_SSD1677_750_HD_BW || EPD->id == EPD_SSD1677_750_HD_BWR) {
if (EPD->drv->ic == EPD_DRIVER_IC_SSD1677) {
EPD_Write(CMD_RAM_XPOS,
x % 256, x / 256,
(x + w - 1) % 256,
@@ -212,6 +212,18 @@ void SSD16xx_Sleep(void)
}
static epd_driver_t epd_drv_ssd1619 = {
.ic = EPD_DRIVER_IC_SSD1619,
.init = SSD16xx_Init,
.clear = SSD16xx_Clear,
.write_image = SSD16xx_Write_Image,
.write_ram = SSD16xx_Write_Ram,
.refresh = SSD16xx_Refresh,
.sleep = SSD16xx_Sleep,
.read_temp = SSD16xx_Read_Temp,
};
static epd_driver_t epd_drv_ssd1677 = {
.ic = EPD_DRIVER_IC_SSD1677,
.init = SSD16xx_Init,
.clear = SSD16xx_Clear,
.write_image = SSD16xx_Write_Image,
@@ -243,7 +255,7 @@ const epd_model_t epd_ssd1619_420_bw = {
const epd_model_t epd_ssd1677_750_bwr = {
.id = EPD_SSD1677_750_HD_BWR,
.color = BWR,
.drv = &epd_drv_ssd1619,
.drv = &epd_drv_ssd1677,
.width = 880,
.height = 528,
};
@@ -252,7 +264,7 @@ const epd_model_t epd_ssd1677_750_bwr = {
const epd_model_t epd_ssd1677_750_bw = {
.id = EPD_SSD1677_750_HD_BW,
.color = BW,
.drv = &epd_drv_ssd1619,
.drv = &epd_drv_ssd1677,
.width = 880,
.height = 528,
};

View File

@@ -52,13 +52,13 @@ static void UC81xx_WaitBusy(uint16_t timeout)
static void UC81xx_PowerOn(void)
{
EPD_WriteCmd(CMD_PON);
UC81xx_WaitBusy(100);
UC81xx_WaitBusy(200);
}
static void UC81xx_PowerOff(void)
{
EPD_WriteCmd(CMD_POF);
UC81xx_WaitBusy(100);
UC81xx_WaitBusy(200);
}
// Read temperature from driver chip
@@ -69,30 +69,47 @@ int8_t UC81xx_Read_Temp(void)
return (int8_t)EPD_ReadByte();
}
static void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
epd_model_t *EPD = epd_get();
if (EPD->drv->ic == EPD_DRIVER_IC_JD79668) {
EPD_Write(0x83, // partial window
x / 256, x % 256,
(x + w - 1) / 256, (x + w - 1) % 256,
y / 256, y % 256,
(y + h - 1) / 256, (y + h - 1) % 256,
0x01);
} else {
uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
uint16_t ye = y + h - 1;
x &= 0xFFF8; // byte boundary
EPD_Write(CMD_PTL, // partial window
x / 256, x % 256,
xe / 256, xe % 256,
y / 256, y % 256,
ye / 256, ye % 256,
0x00);
}
}
void UC81xx_Refresh(void)
{
NRF_LOG_DEBUG("[EPD]: refresh begin\n");
UC81xx_PowerOn();
epd_model_t *EPD = epd_get();
NRF_LOG_DEBUG("[EPD]: refresh begin\n");
if (EPD->drv->ic != EPD_DRIVER_IC_JD79668)
UC81xx_PowerOn();
_setPartialRamArea(0, 0, EPD->width, EPD->height);
NRF_LOG_DEBUG("[EPD]: temperature: %d\n", UC81xx_Read_Temp());
EPD_WriteCmd(CMD_DRF);
delay(100);
UC81xx_WaitBusy(30000);
UC81xx_PowerOff();
NRF_LOG_DEBUG("[EPD]: refresh end\n");
}
static void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
uint16_t ye = y + h - 1;
x &= 0xFFF8; // byte boundary
EPD_Write(CMD_PTL, // partial window
x / 256, x % 256,
xe / 256, xe % 256,
y / 256, y % 256,
ye / 256, ye % 256,
0x00);
if (EPD->drv->ic != EPD_DRIVER_IC_JD79668)
UC81xx_PowerOff();
NRF_LOG_DEBUG("[EPD]: refresh end\n");
}
void UC81xx_Dump_OTP(void)
@@ -146,6 +163,30 @@ void UC8159_Init()
EPD->height & 0xff);
}
void JD79668_Init()
{
epd_model_t *EPD = epd_get();
EPD_Reset(HIGH, 50);
EPD_Write(0x4D, 0x78);
EPD_Write(CMD_PSR, 0x0F, 0x29);
EPD_Write(CMD_BTST, 0x0D, 0x12, 0x24, 0x25, 0x12, 0x29, 0x10);
EPD_Write(CMD_PLL, 0x08);
EPD_Write(CMD_CDI, 0x37);
EPD_Write(CMD_TRES,
EPD->width / 256, EPD->width % 256,
EPD->height / 256, EPD->height % 256);
EPD_Write(0xAE, 0xCF);
EPD_Write(0xB0, 0x13);
EPD_Write(0xBD, 0x07);
EPD_Write(0xBE, 0xFE);
EPD_Write(0xE9, 0x01);
UC81xx_PowerOn();
}
void UC81xx_Clear(bool refresh)
{
epd_model_t *EPD = epd_get();
@@ -176,6 +217,17 @@ void UC8159_Clear(bool refresh)
UC81xx_Refresh();
}
void JD79668_Clear(bool refresh)
{
epd_model_t *EPD = epd_get();
uint32_t ram_bytes = ((EPD->width + 3) / 4) * EPD->height;
EPD_FillRAM(CMD_DTM1, 0x55, ram_bytes);
if (refresh)
UC81xx_Refresh();
}
void UC81xx_Write_Image(uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
epd_model_t *EPD = epd_get();
@@ -255,7 +307,25 @@ void UC8159_Write_Image(uint8_t *black, uint8_t *color, uint16_t x, uint16_t y,
EPD_WriteCmd(CMD_PTOUT); // partial out
}
void UC81xx_Wite_Ram(uint8_t cfg, uint8_t *data, uint8_t len)
void JD79668_Write_Image(uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
epd_model_t *EPD = epd_get();
uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
x -= x % 8; // byte boundary
w = wb * 8; // byte boundary
if (x + w > EPD->width || y + h > EPD->height)
return;
_setPartialRamArea(x, y, w, h);
EPD_WriteCmd(CMD_DTM1);
for (uint16_t i = 0; i < h * 2; i++) // 2 bits per pixel
{
for (uint16_t j = 0; j < w / 8; j++)
EPD_WriteByte(black ? black[j + i * wb] : 0x55);
}
}
void UC81xx_Write_Ram(uint8_t cfg, uint8_t *data, uint8_t len)
{
bool begin = (cfg >> 4) == 0x00;
bool black = (cfg & 0x0F) == 0x0F;
@@ -269,8 +339,8 @@ void UC81xx_Wite_Ram(uint8_t cfg, uint8_t *data, uint8_t len)
EPD_WriteData(data, len);
}
// only black pixels are handled
void UC8159_Wite_Ram(uint8_t cfg, uint8_t *data, uint8_t len)
// Write native data to ram, format should be 2pp or above
void UC81xx_Write_Ram_Native(uint8_t cfg, uint8_t *data, uint8_t len)
{
bool begin = (cfg >> 4) == 0x00;
bool black = (cfg & 0x0F) == 0x0F;
@@ -281,37 +351,60 @@ void UC8159_Wite_Ram(uint8_t cfg, uint8_t *data, uint8_t len)
void UC81xx_Sleep(void)
{
UC81xx_PowerOff();
delay(100);
EPD_Write(CMD_DSLP, 0xA5);
}
// Declare driver and models
static epd_driver_t epd_drv_uc81xx = {
static epd_driver_t epd_drv_uc8176 = {
.ic = EPD_DRIVER_IC_UC8176,
.init = UC81xx_Init,
.clear = UC81xx_Clear,
.write_image = UC81xx_Write_Image,
.write_ram = UC81xx_Wite_Ram,
.write_ram = UC81xx_Write_Ram,
.refresh = UC81xx_Refresh,
.sleep = UC81xx_Sleep,
.read_temp = UC81xx_Read_Temp,
};
static epd_driver_t epd_drv_uc8159 = {
.ic = EPD_DRIVER_IC_UC8159,
.init = UC8159_Init,
.clear = UC8159_Clear,
.write_image = UC8159_Write_Image,
.write_ram = UC8159_Wite_Ram,
.write_ram = UC81xx_Write_Ram_Native,
.refresh = UC81xx_Refresh,
.sleep = UC81xx_Sleep,
.read_temp = UC81xx_Read_Temp,
};
static epd_driver_t epd_drv_uc8179 = {
.ic = EPD_DRIVER_IC_UC8179,
.init = UC81xx_Init,
.clear = UC81xx_Clear,
.write_image = UC81xx_Write_Image,
.write_ram = UC81xx_Write_Ram,
.refresh = UC81xx_Refresh,
.sleep = UC81xx_Sleep,
.read_temp = UC81xx_Read_Temp,
};
static epd_driver_t epd_drv_jd79668 = {
.ic = EPD_DRIVER_IC_JD79668,
.init = JD79668_Init,
.clear = JD79668_Clear,
.write_image = JD79668_Write_Image,
.write_ram = UC81xx_Write_Ram_Native,
.refresh = UC81xx_Refresh,
.sleep = UC81xx_Sleep,
.read_temp = UC81xx_Read_Temp,
};
// UC8176 400x300 Black/White
const epd_model_t epd_uc8176_420_bw = {
.id = EPD_UC8176_420_BW,
.color = BW,
.drv = &epd_drv_uc81xx,
.drv = &epd_drv_uc8176,
.width = 400,
.height = 300,
};
@@ -320,7 +413,7 @@ const epd_model_t epd_uc8176_420_bw = {
const epd_model_t epd_uc8176_420_bwr = {
.id = EPD_UC8176_420_BWR,
.color = BWR,
.drv = &epd_drv_uc81xx,
.drv = &epd_drv_uc8176,
.width = 400,
.height = 300,
};
@@ -347,7 +440,7 @@ const epd_model_t epd_uc8159_750_bwr = {
const epd_model_t epd_uc8179_750_bw = {
.id = EPD_UC8179_750_BW,
.color = BW,
.drv = &epd_drv_uc81xx,
.drv = &epd_drv_uc8179,
.width = 800,
.height = 480,
};
@@ -356,8 +449,16 @@ const epd_model_t epd_uc8179_750_bw = {
const epd_model_t epd_uc8179_750_bwr = {
.id = EPD_UC8179_750_BWR,
.color = BWR,
.drv = &epd_drv_uc81xx,
.drv = &epd_drv_uc8179,
.width = 800,
.height = 480,
};
// JD79668 400x300 Black/White/Red/Yellow
const epd_model_t epd_jd79668_420 = {
.id = EPD_JD79668_420_BWRY,
.color = BWRY,
.drv = &epd_drv_jd79668,
.width = 400,
.height = 300,
};

View File

@@ -424,11 +424,6 @@
<FileType>1</FileType>
<FilePath>..\EPD\SSD16xx.c</FilePath>
</File>
<File>
<FileName>JD79xx.c</FileName>
<FileType>1</FileType>
<FilePath>..\EPD\JD79xx.c</FilePath>
</File>
</Files>
</Group>
<Group>
@@ -1186,11 +1181,6 @@
<FileType>1</FileType>
<FilePath>..\EPD\SSD16xx.c</FilePath>
</File>
<File>
<FileName>JD79xx.c</FileName>
<FileType>1</FileType>
<FilePath>..\EPD\JD79xx.c</FilePath>
</File>
</Files>
</Group>
<Group>

View File

@@ -46,7 +46,6 @@ SRC_FILES += \
$(PROJ_DIR)/EPD/EPD_service.c \
$(PROJ_DIR)/EPD/UC81xx.c \
$(PROJ_DIR)/EPD/SSD16xx.c \
$(PROJ_DIR)/EPD/JD79xx.c \
$(PROJ_DIR)/GUI/GUI.c \
$(PROJ_DIR)/GUI/Lunar.c \
$(PROJ_DIR)/GUI/fonts.c \

View File

@@ -70,7 +70,6 @@ SRC_FILES += \
$(PROJ_DIR)/EPD/EPD_service.c \
$(PROJ_DIR)/EPD/UC81xx.c \
$(PROJ_DIR)/EPD/SSD16xx.c \
$(PROJ_DIR)/EPD/JD79xx.c \
$(PROJ_DIR)/GUI/GUI.c \
$(PROJ_DIR)/GUI/Lunar.c \
$(PROJ_DIR)/GUI/fonts.c \

View File

@@ -24,8 +24,8 @@
<select id="epddriver">
<option value="01" data-color="blackWhiteColor" data-size="4.2_400_300">4.2寸 (黑白, UC8176)</option>
<option value="03" data-color="threeColor" data-size="4.2_400_300">4.2寸 (三色, UC8176)</option>
<option value="04" data-color="blackWhiteColor" data-size="4.2_400_300">4.2寸 (黑白, SSD16xx)</option>
<option value="02" data-color="threeColor" data-size="4.2_400_300">4.2寸 (三色, SSD16xx)</option>
<option value="04" data-color="blackWhiteColor" data-size="4.2_400_300">4.2寸 (黑白, SSD1619)</option>
<option value="02" data-color="threeColor" data-size="4.2_400_300">4.2寸 (三色, SSD1619)</option>
<option value="05" data-color="fourColor" data-size="4.2_400_300">4.2寸 (四色, JD79668)</option>
<option value="06" data-color="blackWhiteColor" data-size="7.5_800_480">7.5寸 (黑白, UC8179)</option>
<option value="07" data-color="threeColor" data-size="7.5_800_480">7.5寸 (三色, UC8179)</option>