[Breaking API change!] added direction and partial RAM operations.

This commit is contained in:
imi415 2021-01-17 20:25:09 +08:00
parent 4d9faf27b7
commit 4c31481910
Signed by: imi415
GPG Key ID: 17F01E106F9F5E0A
3 changed files with 63 additions and 30 deletions

View File

@ -55,9 +55,12 @@ depg0213_ret_t _epd_write_data_cb(void *handle, uint8_t *data, uint16_t len) {
## Notes: ## Notes:
Pixels of this panel is organized in the similar way as SSD1306, but has 212 columns and 13 pages. * Pixels of this panel is organized in the similar way as SSD1306, but has 212 columns and 13 pages.
Therefore, when `HORIZONTAL` or `HORIZONTAL_INVERSE` modes are selected, the frame needs to be Therefore, when `HORIZONTAL` or `HORIZONTAL_INVERSE` modes are selected, the frame needs to be
transferred as pages. However, this controller chip has the function which can change the transferred as pages. However, this controller chip has the function which can change the
self-increment direction of the internal pointer, so `VERTICAL` modes are not affected anyway. self-increment direction of the internal pointer, so `VERTICAL` modes are not affected anyway.
![A figure explaining the layout of the panel](assets/panel_organization.png) * In `REVERSE` modes, the scanning direction of pixels in one byte are also inversed, therefore,
Shift operation needs to be different for both `HORIZONTAL_REVERSE` and `VERTICAL_REVERSE` directions.
![A figure explaining the layout of the panel](assets/panel_organization.png)

View File

@ -98,9 +98,6 @@ depg0213_ret_t depg0213_epd_init(depg0213_epd_t *epd) {
DEPG0213_ERROR_CHECK(_depg0213_hardware_reset(epd)); DEPG0213_ERROR_CHECK(_depg0213_hardware_reset(epd));
DEPG0213_ERROR_CHECK(_depg0213_software_reset(epd)); DEPG0213_ERROR_CHECK(_depg0213_software_reset(epd));
// Setup default direction
DEPG0213_ERROR_CHECK(depg0213_epd_direction(epd, DEPG0213_VERTICAL));
// Send initialization chants // Send initialization chants
DEPG0213_ERROR_CHECK(_depg0213_init_seq(epd)); DEPG0213_ERROR_CHECK(_depg0213_init_seq(epd));
@ -125,47 +122,54 @@ depg0213_ret_t depg0213_epd_update(depg0213_epd_t *epd) {
return DEPG0213_OK; return DEPG0213_OK;
} }
depg0213_ret_t depg0213_epd_load(depg0213_epd_t *epd, uint8_t *bw_image, uint8_t *red_image) { 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) { if(epd->deep_sleep) {
DEPG0213_ERROR_CHECK(depg0213_epd_init(epd)); DEPG0213_ERROR_CHECK(depg0213_epd_init(epd));
} }
uint8_t command[5] = { 0x4E, 0x0C, 0x4F, 0xD3, 0x00 }; 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) { switch(epd->direction) {
case DEPG0213_VERTICAL_INVERSE: case DEPG0213_VERTICAL_INVERSE:
// X->0x00 // X->0x00
command[1] = 0x00; command[1] = x_start / 8;
// Y->0x00 // Y->0x00
command[3] = 0x00; command[3] = y_start;
break; break;
case DEPG0213_HORIZONTAL: case DEPG0213_HORIZONTAL: // X-Y inversed
// X->0x00 // X->0x00
command[1] = 0x00; command[1] = y_start / 8;
// NO CHANGE FOR Y AXIS // Y->0xD3
command[3] = 0xD3 - x_start;
break; break;
case DEPG0213_HORIZONTAL_INVERSE: case DEPG0213_HORIZONTAL_INVERSE: // X-Y inversed
// NO CHANGE FOR X AXIS // X->0x0C
command[1] = 0x0C - y_start / 8;
// Y-> 0x00 // Y-> 0x00
command[3] = 0x00; command[3] = x_start;
break; break;
case DEPG0213_VERTICAL: case DEPG0213_VERTICAL:
default: default:
break; 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, 0x02));
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, &command[2], 0x03)); DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, &command[2], 0x03));
uint8_t wr_command = 0x24; uint8_t wr_command = 0x24;
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, &wr_command, 0x01)); 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, 2756)); // 104 / 8 * 212 DEPG0213_ERROR_CHECK(epd->cb.write_data_cb(epd->user_data, bw_image, transfer_bytes));
wr_command = 0x26; wr_command = 0x26;
DEPG0213_ERROR_CHECK(epd->cb.write_cmd_cb(epd->user_data, &wr_command, 0x01)); 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, 2756)); // 104 / 8 * 212 DEPG0213_ERROR_CHECK(epd->cb.write_data_cb(epd->user_data, red_image, transfer_bytes));
return DEPG0213_OK; return DEPG0213_OK;
} }
@ -181,46 +185,69 @@ depg0213_ret_t depg0213_epd_deepsleep(depg0213_epd_t *epd) {
return DEPG0213_OK; return DEPG0213_OK;
} }
depg0213_ret_t depg0213_epd_direction(depg0213_epd_t *epd, depg0213_direction_t direction) { 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) { if(epd->deep_sleep) {
DEPG0213_ERROR_CHECK(depg0213_epd_init(epd)); 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(x_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- // Default mode: VERTICAL, X: 0x0C->0x00, Y: 0xD3->0x00, AM-|Y-|X-
uint8_t cmd_ram_x_address[] = { 0x44, 0x0C, 0x00 }; // CMD, START, END 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, 0x00, 0x00, 0x00 }; // CMD, START_L, START_H, END_L, END_H 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+ uint8_t cmd_data_entry[] = { 0x11, 0x00 }; // CMD, SCAN_X->DESC, SCAN_Y->DESC, AM->0 [2:0]=AM|Y+|X+
switch(direction) { switch(direction) {
case DEPG0213_VERTICAL_INVERSE: case DEPG0213_VERTICAL_INVERSE:
// START: 0x00, END: 0x0C // START: 0x00, END: 0x0C
cmd_ram_x_address[1] = 0x00; cmd_ram_x_address[1] = x_start / 8;
cmd_ram_x_address[2] = 0x0C; cmd_ram_x_address[2] = x_end / 8;
// START: 0x00, END: 0xD3 // START: 0x00, END: 0xD3
cmd_ram_y_address[1] = 0x00; cmd_ram_y_address[1] = y_start;
cmd_ram_y_address[3] = 0xD3; cmd_ram_y_address[3] = y_end;
// AM-|Y+|X+ // AM-|Y+|X+
cmd_data_entry[1] = 0x03; cmd_data_entry[1] = 0x03;
break; break;
case DEPG0213_HORIZONTAL: case DEPG0213_HORIZONTAL:
// START: 0x00, END: 0x0C // START: 0x00, END: 0x0C
cmd_ram_x_address[1] = 0x00; cmd_ram_x_address[1] = y_start / 8;
cmd_ram_x_address[2] = 0x0C; cmd_ram_x_address[2] = y_end / 8;
// NO CHANGE FOR Y AXIS // NO CHANGE FOR Y AXIS
cmd_ram_y_address[1] = 0xD3 - x_start;
cmd_ram_y_address[3] = 0xD3 - x_end;
// AM+|Y-|X+ // AM+|Y-|X+
cmd_data_entry[1] = 0x05; cmd_data_entry[1] = 0x05;
break; break;
case DEPG0213_HORIZONTAL_INVERSE: case DEPG0213_HORIZONTAL_INVERSE:
// NO CHANGE FOR X AXIS // 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 // START: 0x00, END: 0xD3
cmd_ram_y_address[1] = 0x00; cmd_ram_y_address[1] = x_start;
cmd_ram_y_address[3] = 0xD3; cmd_ram_y_address[3] = x_end;
// AM+|Y+|X- // AM+|Y+|X-
cmd_data_entry[1] = 0x06; cmd_data_entry[1] = 0x06;

View File

@ -2,6 +2,7 @@
#define __depg0213_EPD_H #define __depg0213_EPD_H
#include <stdint.h> #include <stdint.h>
#include <stddef.h>
#define DEPG0213_PANEL_SELECTION depg0213_dke_init_sequence #define DEPG0213_PANEL_SELECTION depg0213_dke_init_sequence
@ -46,8 +47,10 @@ typedef struct {
depg0213_ret_t depg0213_epd_init(depg0213_epd_t *epd); depg0213_ret_t depg0213_epd_init(depg0213_epd_t *epd);
depg0213_ret_t depg0213_epd_update(depg0213_epd_t *epd); depg0213_ret_t depg0213_epd_update(depg0213_epd_t *epd);
depg0213_ret_t depg0213_epd_load(depg0213_epd_t *epd, uint8_t *bw_image, uint8_t *red_image); 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);
depg0213_ret_t depg0213_epd_deepsleep(depg0213_epd_t *epd); depg0213_ret_t depg0213_epd_deepsleep(depg0213_epd_t *epd);
depg0213_ret_t depg0213_epd_direction(depg0213_epd_t *epd, depg0213_direction_t direction); 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);
#endif #endif