#include "panel/lcd_zjy096s0800.h" #include #include "epd_private.h" #define LCD_X_OFFSET 26 #define LCD_Y_OFFSET 1 static uint8_t lcd_zjy096s0800_init_seq[] = { 0x01, 0xF0, 0xC3, // Enable command part 1 0x01, 0xF0, 0x96, // Enable command part 2 0x08, 0xE8, 0x40, 0x82, 0x07, 0x18, 0x27, 0x0A, 0xB6, 0x33, // DOCA 0x01, 0xC5, 0x27, // VCOM control 0x01, 0xC2, 0xA7, // Power control 3 0x0E, 0xE0, 0xF0, 0x01, 0x06, 0x0F, 0x12, 0x1D, 0x36, 0x54, 0x44, 0x0C, 0x18, 0x16, 0x13, 0x15, // PGC 0x0E, 0xE1, 0xF0, 0x01, 0x05, 0x0A, 0x0B, 0x07, 0x32, 0x44, 0x44, 0x0C, 0x18, 0x17, 0x13, 0x16, // NGC 0x01, 0xF0, 0x3C, // Disable command part 1 0x01, 0xF0, 0x69, // Disable command part 2 }; epd_ret_t lcd_zjy096s0800_window(lcd_zjy096s0800_t *lcd, epd_coord_t *coord) { uint16_t real_x_start, real_x_end, real_y_start, real_y_end; uint16_t x_offset, y_offset; switch (lcd->config.direction) { case LCD_ZJY096S0800_DIR_90: x_offset = 0 + LCD_Y_OFFSET; y_offset = 0 + LCD_X_OFFSET; break; case LCD_ZJY096S0800_DIR_180: x_offset = 162 - LCD_X_OFFSET; y_offset = 132 - LCD_Y_OFFSET; break; case LCD_ZJY096S0800_DIR_270: x_offset = 132 - LCD_Y_OFFSET; y_offset = 162 - LCD_X_OFFSET; break; case LCD_ZJY096S0800_DIR_0: default: x_offset = 0 + LCD_X_OFFSET; y_offset = 0 + LCD_Y_OFFSET; } real_x_start = coord->x_start + x_offset; real_x_end = coord->x_end + x_offset; real_y_start = coord->y_start + y_offset; real_y_end = coord->y_end + y_offset; uint8_t tx_buf[5] = {0x2A, ((uint8_t)(real_x_start >> 0x08U) & 0xFFU), (real_x_start & 0xFFU), ((uint8_t)(real_x_end >> 0x08U) & 0xFFU), (real_x_end & 0xFFU)}; if (lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x05) != EPD_OK) { return EPD_FAIL; } tx_buf[0] = 0x2B; tx_buf[1] = ((uint8_t)(real_y_start >> 0x08U) & 0xFFU); tx_buf[2] = (real_y_start & 0xFFU); tx_buf[3] = ((uint8_t)(real_y_end >> 0x08U) & 0xFFU); tx_buf[4] = (real_y_end & 0xFFU); if (lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x05) != EPD_OK) { return EPD_FAIL; } return EPD_OK; } epd_ret_t lcd_zjy096s0800_reset(lcd_zjy096s0800_t *lcd) { return lcd->cb.reset_cb(lcd->user_data); } epd_ret_t lcd_zjy096s0800_init(lcd_zjy096s0800_t *lcd) { if (lcd_zjy096s0800_reset(lcd) != EPD_OK) return EPD_FAIL; if (epd_common_execute_sequence(&lcd->cb, lcd->user_data, lcd_zjy096s0800_init_seq, sizeof(lcd_zjy096s0800_init_seq)) != EPD_OK) return EPD_FAIL; if (lcd_zjy096s0800_config(lcd, &lcd->config) != EPD_OK) return EPD_FAIL; if (lcd_zjy096s0800_sleep(lcd, 0) != EPD_OK) return EPD_FAIL; if (lcd_zjy096s0800_display(lcd, 1) != EPD_OK) return EPD_FAIL; return EPD_OK; } epd_ret_t lcd_zjy096s0800_upload(lcd_zjy096s0800_t *lcd, uint8_t *data, epd_coord_t *coord) { uint32_t pixel_count = (coord->y_end - coord->y_start + 1) * (coord->x_end - coord->x_start + 1); uint32_t data_len; switch (lcd->config.pix_fmt) { case LCD_ZJY096S0800_RGB444: data_len = pixel_count * 3 / 2; break; case LCD_ZJY096S0800_RGB565: data_len = pixel_count * 2; break; case LCD_ZJY096S0800_RGB666: case LCD_ZJY096S0800_RGB888: data_len = pixel_count * 3; break; default: data_len = pixel_count; break; } // Set cursor if (lcd_zjy096s0800_window(lcd, coord) != EPD_OK) { return EPD_FAIL; } uint8_t command = 0x2C; // Memory Write if (lcd->cb.write_command_cb(lcd->user_data, &command, 0x01) != EPD_OK) { return EPD_FAIL; } // Write pixel data if (lcd->cb.write_data_cb(lcd->user_data, data, data_len) != EPD_OK) { return EPD_FAIL; } return EPD_OK; } epd_ret_t lcd_zjy096s0800_sleep(lcd_zjy096s0800_t *lcd, uint8_t sleep_mode) { // Write SLPIN or SLPOUT command. uint8_t command = sleep_mode ? 0x10 : 0x11; return lcd->cb.write_command_cb(lcd->user_data, &command, 0x01); } epd_ret_t lcd_zjy096s0800_display(lcd_zjy096s0800_t *lcd, uint8_t display_on) { // write display_on command; uint8_t command = display_on ? 0x29 : 0x28; if (lcd->cb.write_command_cb(lcd->user_data, &command, 0x01) != EPD_OK) { return EPD_FAIL; } if ((lcd->cb.backlight_cb != NULL) && (lcd->cb.backlight_cb(lcd->user_data, display_on) != EPD_OK)) { return EPD_FAIL; } return EPD_OK; } epd_ret_t lcd_zjy096s0800_config(lcd_zjy096s0800_t *lcd, lcd_zjy096s0800_config_t *config) { lcd->config.direction = config->direction; // Write inversion command. uint8_t command[2] = {config->inversion ? 0x20 : 0x21, 0x00}; if (lcd->cb.write_command_cb(lcd->user_data, command, 0x01) != EPD_OK) { return EPD_FAIL; } lcd->config.inversion = config->inversion; command[0] = 0x3A; command[1] = config->pix_fmt; if (lcd->cb.write_command_cb(lcd->user_data, command, 0x02) != EPD_OK) { return EPD_FAIL; } lcd->config.pix_fmt = config->pix_fmt; command[0] = 0x36; command[1] = config->direction; if (!config->bgr_mode) { command[1] &= ~0x08U; } if (config->mirrored) { if (config->direction == LCD_ZJY096S0800_DIR_90 || config->direction == LCD_ZJY096S0800_DIR_270) { command[1] ^= 0x80U; } else { command[1] ^= 0x40U; } } return lcd->cb.write_command_cb(lcd->user_data, command, 0x02); }