depg0213_epd/depg0213_epd.c

276 lines
9.2 KiB
C

#include "depg0213_epd.h"
uint8_t depg0213_dke_init_sequence[] = {
0x01, 0x74, 0x54, // Set analog block control
0x01, 0x7E, 0x3B, // Set digital block control
0x03, 0x01, 0xF9, 0x00, 0x00, // Set display size and driver output control
0x01, 0x3C, 0x01, // Set border
0x01, 0x2C, 0x5A, // Set VCOM value
0x01, 0x03, 0x17, // Gate voltage settings
0x03, 0x04, 0x41, 0xAC, 0x32, // Source voltage settings
0x01, 0x3A, 0x02, // Frame setting 1
0x01, 0x3B, 0x0D // Frame setting 2
};
uint8_t depg0213_dke_lut_full[] = {
0x80,0x60,0x40,0x00,0x00,0x00,0x00, //LUT0: BB: VS 0 ~7
0x10,0x60,0x20,0x00,0x00,0x00,0x00, //LUT1: BW: VS 0 ~7
0x80,0x60,0x40,0x00,0x00,0x00,0x00, //LUT2: WB: VS 0 ~7
0x10,0x60,0x20,0x00,0x00,0x00,0x00, //LUT3: WW: VS 0 ~7
0x00,0x00,0x00,0x00,0x00,0x00,0x00, //LUT4: VCOM: VS 0 ~7
0x03,0x03,0x00,0x00,0x02, // TP0 A~D RP0
0x09,0x09,0x00,0x00,0x02, // TP1 A~D RP1
0x03,0x03,0x00,0x00,0x02, // TP2 A~D RP2
0x00,0x00,0x00,0x00,0x00, // TP3 A~D RP3
0x00,0x00,0x00,0x00,0x00, // TP4 A~D RP4
0x00,0x00,0x00,0x00,0x00, // TP5 A~D RP5
0x00,0x00,0x00,0x00,0x00, // TP6 A~D RP6
};
uint8_t depg0213_dke_lut_part[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00, //LUT0: BB: VS 0 ~7
0x80,0x00,0x00,0x00,0x00,0x00,0x00, //LUT1: BW: VS 0 ~7
0x40,0x00,0x00,0x00,0x00,0x00,0x00, //LUT2: WB: VS 0 ~7
0x00,0x00,0x00,0x00,0x00,0x00,0x00, //LUT3: WW: VS 0 ~7
0x00,0x00,0x00,0x00,0x00,0x00,0x00, //LUT4: VCOM: VS 0 ~7
0x0A,0x00,0x00,0x00,0x00, // TP0 A~D RP0
0x00,0x00,0x00,0x00,0x00, // TP1 A~D RP1
0x00,0x00,0x00,0x00,0x00, // TP2 A~D RP2
0x00,0x00,0x00,0x00,0x00, // TP3 A~D RP3
0x00,0x00,0x00,0x00,0x00, // TP4 A~D RP4
0x00,0x00,0x00,0x00,0x00, // TP5 A~D RP5
0x00,0x00,0x00,0x00,0x00, // TP6 A~D RP6
};
depg0213_ret_t _depg0213_software_reset(depg0213_epd_t *epd) {
uint8_t sw_reset_cmd = 0x12; // SW RST
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, &sw_reset_cmd, 0x01));
DEPG0213_ERROR_CHECK(epd->cb.poll_busy_cb(epd->user_data));
return DEPG0213_OK;
}
depg0213_ret_t _depg0213_hardware_reset(depg0213_epd_t *epd) {
DEPG0213_ERROR_CHECK(epd->cb.reset_cb(epd->user_data));
DEPG0213_ERROR_CHECK(epd->cb.poll_busy_cb(epd->user_data));
epd->deep_sleep = 0;
return DEPG0213_OK;
}
depg0213_ret_t _depg0213_init_seq(depg0213_epd_t *epd) {
uint16_t i = 0;
while(i < sizeof(DEPG0213_PANEL_SELECTION)) {
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, &DEPG0213_PANEL_SELECTION[i + 1], DEPG0213_PANEL_SELECTION[i] + 1));
i += DEPG0213_PANEL_SELECTION[i] + 2;
}
return DEPG0213_OK;
}
depg0213_ret_t _depg0213_load_lut(depg0213_epd_t *epd) {
#if(!DEPG0213_LUT_OTP)
uint8_t lut_command = 0x32;
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, &lut_command, 0x01));
DEPG0213_ERROR_CHECK(epd->cb.write_data_cb(epd->user_data, DEPG0213_LUT_FULL_SELECTION, 70));
#else
uint8_t lut_command[5] = { 0x18, 0x80, 0x22, 0xB1, 0x20 };
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, lut_command, 0x02));
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, &lut_command[2], 0x02));
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, &lut_command[4], 0x01));
// The end of the sequence is load LUT from OTP memory.
DEPG0213_ERROR_CHECK(epd->cb.poll_busy_cb(epd->user_data));
#endif
return DEPG0213_OK;
}
depg0213_ret_t depg0213_epd_init(depg0213_epd_t *epd) {
// Software reset follows hardware reset
DEPG0213_ERROR_CHECK(_depg0213_hardware_reset(epd));
DEPG0213_ERROR_CHECK(_depg0213_software_reset(epd));
// Send initialization chants
DEPG0213_ERROR_CHECK(_depg0213_init_seq(epd));
// Write LUT
DEPG0213_ERROR_CHECK(_depg0213_load_lut(epd));
return DEPG0213_OK;
}
depg0213_ret_t depg0213_epd_update(depg0213_epd_t *epd) {
if(epd->deep_sleep) {
DEPG0213_ERROR_CHECK(depg0213_epd_init(epd));
}
uint8_t command[2] = { 0x22, 0xC7 };
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, command, 0x02));
command[0] = 0x20;
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, command, 0x01));
DEPG0213_ERROR_CHECK(epd->cb.poll_busy_cb(epd->user_data));
return DEPG0213_OK;
}
depg0213_ret_t depg0213_epd_load(depg0213_epd_t *epd, uint8_t *bw_image, uint8_t *red_image,
uint16_t x_start, uint16_t x_end, uint16_t y_start, uint16_t y_end) {
if(epd->deep_sleep) {
DEPG0213_ERROR_CHECK(depg0213_epd_init(epd));
}
DEPG0213_ERROR_CHECK(depg0213_epd_window(epd, epd->direction, x_start, x_end, y_start, y_end));
uint8_t command[5] = { 0x4E, 0x0C - x_start / 8, 0x4F, 0xD3 - y_start, 0x00 };
switch(epd->direction) {
case DEPG0213_VERTICAL_INVERSE:
// X->0x00
command[1] = x_start / 8;
// Y->0x00
command[3] = y_start;
break;
case DEPG0213_HORIZONTAL: // X-Y inversed
// X->0x00
command[1] = y_start / 8;
// Y->0xD3
command[3] = 0xD3 - x_start;
break;
case DEPG0213_HORIZONTAL_INVERSE: // X-Y inversed
// X->0x0C
command[1] = 0x0C - y_start / 8;
// Y-> 0x00
command[3] = x_start;
break;
case DEPG0213_VERTICAL:
default:
break;
}
uint16_t transfer_bytes = (y_end - y_start + 1) * (x_end - x_start + 1) / 8;
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, command, 0x02));
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, &command[2], 0x03));
uint8_t wr_command;
if(bw_image != NULL) {
wr_command = 0x24;
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, &wr_command, 0x01));
DEPG0213_ERROR_CHECK(epd->cb.write_data_cb(epd->user_data, bw_image, transfer_bytes));
}
if(red_image != NULL) {
wr_command = 0x26;
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, &wr_command, 0x01));
DEPG0213_ERROR_CHECK(epd->cb.write_data_cb(epd->user_data, red_image, transfer_bytes));
}
return DEPG0213_OK;
}
depg0213_ret_t depg0213_epd_deepsleep(depg0213_epd_t *epd) {
if(epd->deep_sleep) return DEPG0213_OK;
uint8_t deepsleep_command[2] = { 0x10, 0x01 };
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, deepsleep_command, 0x02));
epd->deep_sleep = 1;
return DEPG0213_OK;
}
depg0213_ret_t depg0213_epd_window(depg0213_epd_t *epd, depg0213_direction_t direction,
uint16_t x_start, uint16_t x_end, uint16_t y_start, uint16_t y_end) {
if(epd->deep_sleep) {
DEPG0213_ERROR_CHECK(depg0213_epd_init(epd));
}
// Sanity checks
if(x_end < x_start || y_end < y_start) return DEPG0213_ERROR;
if(direction == DEPG0213_VERTICAL || direction == DEPG0213_VERTICAL_INVERSE) {
if(x_end > 103 || y_end > 211) {
return DEPG0213_ERROR;
}
if(x_start % 8 != 0) return DEPG0213_ERROR;
if((x_end + 1) % 8 != 0) return DEPG0213_ERROR;
}
else {
if(x_end > 211 || y_end > 103) {
return DEPG0213_ERROR;
}
if(y_start % 8 != 0) return DEPG0213_ERROR;
if((y_end + 1) % 8 != 0) return DEPG0213_ERROR;
}
// Default mode: VERTICAL, X: 0x0C->0x00, Y: 0xD3->0x00, AM-|Y-|X-
uint8_t cmd_ram_x_address[] = { 0x44, 0x0C - x_start / 8, 0x0C - x_end / 8 }; // CMD, START, END
uint8_t cmd_ram_y_address[] = { 0x45, 0xD3 - y_start, 0x00, 0xD3 - y_end, 0x00 }; // CMD, START_L, START_H, END_L, END_H
uint8_t cmd_data_entry[] = { 0x11, 0x00 }; // CMD, SCAN_X->DESC, SCAN_Y->DESC, AM->0 [2:0]=AM|Y+|X+
switch(direction) {
case DEPG0213_VERTICAL_INVERSE:
// START: 0x00, END: 0x0C
cmd_ram_x_address[1] = x_start / 8;
cmd_ram_x_address[2] = x_end / 8;
// START: 0x00, END: 0xD3
cmd_ram_y_address[1] = y_start;
cmd_ram_y_address[3] = y_end;
// AM-|Y+|X+
cmd_data_entry[1] = 0x03;
break;
case DEPG0213_HORIZONTAL:
// START: 0x00, END: 0x0C
cmd_ram_x_address[1] = y_start / 8;
cmd_ram_x_address[2] = y_end / 8;
// NO CHANGE FOR Y AXIS
cmd_ram_y_address[1] = 0xD3 - x_start;
cmd_ram_y_address[3] = 0xD3 - x_end;
// AM+|Y-|X+
cmd_data_entry[1] = 0x05;
break;
case DEPG0213_HORIZONTAL_INVERSE:
// NO CHANGE FOR X AXIS
cmd_ram_x_address[1] = 0x0C - y_start / 8;
cmd_ram_x_address[2] = 0x0C - y_end / 8;
// START: 0x00, END: 0xD3
cmd_ram_y_address[1] = x_start;
cmd_ram_y_address[3] = x_end;
// AM+|Y+|X-
cmd_data_entry[1] = 0x06;
break;
case DEPG0213_VERTICAL:
default:
break;
}
// Write mode to screen.
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, cmd_ram_x_address, 0x03));
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, cmd_ram_y_address, 0x05));
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, cmd_data_entry, 0x02));
epd->direction = direction;
return DEPG0213_OK;
}