diff --git a/CMakeLists.txt b/CMakeLists.txt index 6946a8f..277633a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,15 +4,25 @@ project(epd-spi) set(EPD_SOURCES "src/epd_common.c" - "src/epd_panel_wfh0420cz35.c" - "src/epd_panel_gdew042t2.c" - "src/lcd_panel_jlx256128g_920.c" - "src/oled_panel_elw1501aa.c" + "src/driver/oled_ssd1327.c" + "src/panel/epd_wfh0420cz35.c" + "src/panel/epd_gdew042t2.c" + "src/panel/lcd_jlx256128g_920.c" + "src/panel/oled_elw1501aa.c" + "src/panel/oled_zjy150s700.c" ) set(EPD_INCLUDES "include" ) +set(EPD_PRIVATE_INCLUDES + "include/epd-spi" + "include/private" +) + add_library(${PROJECT_NAME} ${EPD_SOURCES}) -target_include_directories(${PROJECT_NAME} PUBLIC ${EPD_INCLUDES}) +target_include_directories(${PROJECT_NAME} + PUBLIC ${EPD_INCLUDES} + PRIVATE ${EPD_PRIVATE_INCLUDES} +) diff --git a/include/epd-spi/driver/oled_ssd1327.h b/include/epd-spi/driver/oled_ssd1327.h new file mode 100644 index 0000000..3e52d18 --- /dev/null +++ b/include/epd-spi/driver/oled_ssd1327.h @@ -0,0 +1,6 @@ +#ifndef DRIVER_SSD1327_H +#define DRIVER_SSD1327_H + + + +#endif \ No newline at end of file diff --git a/include/epd_common.h b/include/epd-spi/epd_common.h similarity index 100% rename from include/epd_common.h rename to include/epd-spi/epd_common.h diff --git a/include/epd_panel_gdew042t2.h b/include/epd-spi/panel/epd_gdew042t2.h similarity index 94% rename from include/epd_panel_gdew042t2.h rename to include/epd-spi/panel/epd_gdew042t2.h index 7159a2f..2317ccd 100644 --- a/include/epd_panel_gdew042t2.h +++ b/include/epd-spi/panel/epd_gdew042t2.h @@ -1,7 +1,7 @@ #ifndef EPD_GDEW042T2_H #define EPD_GDEW042T2_H -#include "epd_common.h" +#include "epd-spi/epd_common.h" /** * @brief This display module has UC8176 controller IC, diff --git a/include/epd_panel_wfh0420cz35.h b/include/epd-spi/panel/epd_wfh0420cz35.h similarity index 89% rename from include/epd_panel_wfh0420cz35.h rename to include/epd-spi/panel/epd_wfh0420cz35.h index 9543aa6..4f72e92 100644 --- a/include/epd_panel_wfh0420cz35.h +++ b/include/epd-spi/panel/epd_wfh0420cz35.h @@ -1,7 +1,7 @@ #ifndef EPD_WFH0420CZ35_H #define EPD_WFH0420CZ35_h -#include "epd_common.h" +#include "epd-spi/epd_common.h" /** * @brief This display module has UC8176 controller IC, with BWR LUT stored in OTP. diff --git a/include/lcd_panel_jlx256128g_920.h b/include/epd-spi/panel/lcd_jlx256128g_920.h similarity index 95% rename from include/lcd_panel_jlx256128g_920.h rename to include/epd-spi/panel/lcd_jlx256128g_920.h index f8939e0..3d7debf 100644 --- a/include/lcd_panel_jlx256128g_920.h +++ b/include/epd-spi/panel/lcd_jlx256128g_920.h @@ -1,7 +1,7 @@ #ifndef LCD_PANEL_JLX256128G_920_H #define LCD_PANEL_JLX256128G_920_H -#include "epd_common.h" +#include "epd-spi/epd_common.h" /** * @brief JLX256128G-920 LCD diff --git a/include/epd-spi/panel/oled_elw1501aa.h b/include/epd-spi/panel/oled_elw1501aa.h new file mode 100644 index 0000000..3414f7f --- /dev/null +++ b/include/epd-spi/panel/oled_elw1501aa.h @@ -0,0 +1,23 @@ +#ifndef OLED_PANEL_ELW1501AA_H +#define OLED_PANEL_ELW1501AA_H + +#include "epd-spi/epd_common.h" + +/** + * @brief Futaba ELW1501AA(R) PMOLED + * Driver/Controller: Solomon Systech SSD1327 + * Resolution: 128x128@4bpp(16 grayscale) + * Link: https://www.futaba.com/oled/ + * Datasheet: https://www.futaba.com/wp-content/uploads/2021/08/ELW1501AA.pdf + */ + +typedef struct { + epd_cb_t cb; + void *user_data; +} oled_elw1501aa_t; + +epd_ret_t oled_elw1501aa_init(oled_elw1501aa_t *elw); +epd_ret_t oled_elw1501aa_upload(oled_elw1501aa_t *oled, epd_coord_t *coord, uint8_t *data); +epd_ret_t oled_elw1501aa_power(oled_elw1501aa_t *elw, uint8_t on); + +#endif \ No newline at end of file diff --git a/include/epd-spi/panel/oled_zjy150s700.h b/include/epd-spi/panel/oled_zjy150s700.h new file mode 100644 index 0000000..0af52a4 --- /dev/null +++ b/include/epd-spi/panel/oled_zjy150s700.h @@ -0,0 +1,23 @@ +#ifndef OLED_PANEL_ZJY150S700_H +#define OLED_PANEL_ZJY150S700_H + +#include "epd-spi/epd_common.h" + +/** + * @brief Futaba zjy150s700(R) PMOLED + * Driver/Controller: Solomon Systech SSD1327 + * Resolution: 128x128@4bpp(16 grayscale) + * Link: https://www.futaba.com/oled/ + * Datasheet: https://www.futaba.com/wp-content/uploads/2021/08/zjy150s700.pdf + */ + +typedef struct { + epd_cb_t cb; + void *user_data; +} oled_zjy150s700_t; + +epd_ret_t oled_zjy150s700_init(oled_zjy150s700_t *elw); +epd_ret_t oled_zjy150s700_upload(oled_zjy150s700_t *oled, epd_coord_t *coord, uint8_t *data); +epd_ret_t oled_zjy150s700_power(oled_zjy150s700_t *elw, uint8_t on); + +#endif \ No newline at end of file diff --git a/include/oled_panel_elw1501aa.h b/include/oled_panel_elw1501aa.h deleted file mode 100644 index d4e1301..0000000 --- a/include/oled_panel_elw1501aa.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef OLED_PANEL_EWL1501AA_H -#define OLED_PANEL_EWL1501AA_H - -#include "epd_common.h" - -/** - * @brief Futaba EWL1501AA(R) PMOLED - * Driver/Controller: Solomon Systech SSD1327 - * Resolution: 128x128@4bpp(16 grayscale) - * Link: https://www.futaba.com/oled/ - * Datasheet: https://www.futaba.com/wp-content/uploads/2021/08/ELW1501AA.pdf - */ - -typedef struct { - epd_cb_t cb; - void *user_data; -} oled_ewl1501aa_t; - -epd_ret_t oled_ewl1501aa_init(oled_ewl1501aa_t *ewl); -epd_ret_t oled_ewl1501aa_upload(oled_ewl1501aa_t *oled, epd_coord_t *coord, uint8_t *data); -epd_ret_t oled_ewl1501aa_power(oled_ewl1501aa_t *ewl, uint8_t on); - -#endif \ No newline at end of file diff --git a/include/epd_private.h b/include/private/epd_private.h similarity index 87% rename from include/epd_private.h rename to include/private/epd_private.h index d843ab2..3265887 100644 --- a/include/epd_private.h +++ b/include/private/epd_private.h @@ -1,7 +1,7 @@ #ifndef EPD_PRIVATE_H #define EPD_PRIVATE_H -#include "epd_common.h" +#include "epd-spi/epd_common.h" #define EPD_ASSERT(x) if(!(x)) for(;;) { /* ABORT. */} #define EPD_ERROR_CHECK(x) if(x != EPD_OK) return EPD_FAIL diff --git a/include/epd_panel_gdew042t2_lut.h b/include/private/panel/epd_gdew042t2_lut.h similarity index 100% rename from include/epd_panel_gdew042t2_lut.h rename to include/private/panel/epd_gdew042t2_lut.h diff --git a/src/driver/oled_ssd1327.c b/src/driver/oled_ssd1327.c new file mode 100644 index 0000000..1c05ce8 --- /dev/null +++ b/src/driver/oled_ssd1327.c @@ -0,0 +1,2 @@ +#include "driver/oled_ssd1327.h" + diff --git a/src/epd_panel_gdew042t2.c b/src/panel/epd_gdew042t2.c similarity index 99% rename from src/epd_panel_gdew042t2.c rename to src/panel/epd_gdew042t2.c index 6d19b9e..ed608e2 100644 --- a/src/epd_panel_gdew042t2.c +++ b/src/panel/epd_gdew042t2.c @@ -1,6 +1,6 @@ -#include "epd_panel_gdew042t2.h" +#include "panel/epd_gdew042t2.h" -#include "epd_panel_gdew042t2_lut.h" +#include "panel/epd_gdew042t2_lut.h" #include "epd_private.h" #define DTM1 0x10 diff --git a/src/epd_panel_wfh0420cz35.c b/src/panel/epd_wfh0420cz35.c similarity index 99% rename from src/epd_panel_wfh0420cz35.c rename to src/panel/epd_wfh0420cz35.c index 7e6c0b3..c5614e1 100644 --- a/src/epd_panel_wfh0420cz35.c +++ b/src/panel/epd_wfh0420cz35.c @@ -1,4 +1,4 @@ -#include "epd_panel_wfh0420cz35.h" +#include "panel/epd_wfh0420cz35.h" #include "epd_private.h" diff --git a/src/lcd_panel_jlx256128g_920.c b/src/panel/lcd_jlx256128g_920.c similarity index 99% rename from src/lcd_panel_jlx256128g_920.c rename to src/panel/lcd_jlx256128g_920.c index ea9fe2d..669793e 100644 --- a/src/lcd_panel_jlx256128g_920.c +++ b/src/panel/lcd_jlx256128g_920.c @@ -1,4 +1,4 @@ -#include "lcd_panel_jlx256128g_920.h" +#include "panel/lcd_jlx256128g_920.h" #include "epd_private.h" diff --git a/src/oled_panel_elw1501aa.c b/src/panel/oled_elw1501aa.c similarity index 76% rename from src/oled_panel_elw1501aa.c rename to src/panel/oled_elw1501aa.c index 0116888..4a4f4e9 100644 --- a/src/oled_panel_elw1501aa.c +++ b/src/panel/oled_elw1501aa.c @@ -1,8 +1,8 @@ -#include "oled_panel_elw1501aa.h" +#include "panel/oled_elw1501aa.h" #include "epd_private.h" -static uint8_t ewl1501aa_init_sequence[] = { +static uint8_t elw1501aa_init_sequence[] = { 0x01, 0x81, 0x9C, // Set contrast control 0x01, 0xA0, 0x53, // Set segment re-map 0x01, 0xA1, 0x00, // Set display start line @@ -19,7 +19,7 @@ static uint8_t ewl1501aa_init_sequence[] = { 0x02, 0x75, 0x00, 0x7F, // Set row address }; -static epd_ret_t oled_ewl1501aa_reset(oled_ewl1501aa_t *oled) { +static epd_ret_t oled_elw1501aa_reset(oled_elw1501aa_t *oled) { if (oled->cb.reset_cb != NULL) { return oled->cb.reset_cb(oled->user_data); } @@ -27,7 +27,7 @@ static epd_ret_t oled_ewl1501aa_reset(oled_ewl1501aa_t *oled) { return EPD_OK; } -static epd_ret_t oled_ewl1501aa_window(oled_ewl1501aa_t *oled, epd_coord_t *coord) { +static epd_ret_t oled_elw1501aa_window(oled_elw1501aa_t *oled, epd_coord_t *coord) { if (coord->x_start % 2 != 0 || coord->x_end % 2 == 0) { return EPD_FAIL; } @@ -51,7 +51,7 @@ static epd_ret_t oled_ewl1501aa_window(oled_ewl1501aa_t *oled, epd_coord_t *coor return EPD_OK; } -static inline uint32_t oled_ewl1501aa_data_size(epd_coord_t *coord) { +static inline uint32_t oled_elw1501aa_data_size(epd_coord_t *coord) { return (coord->x_end - coord->x_start + 1) * (coord->y_end - coord->y_start + 1) / 2; } @@ -61,13 +61,15 @@ static inline uint32_t oled_ewl1501aa_data_size(epd_coord_t *coord) { * less overhead and higher data rate, initialization sequence * are moved to this seperate function. Call this function before * sending framebuffer data. - * @param oled pointer to oled_ewl1501aa_t + * @param oled pointer to oled_elw1501aa_t * @return epd_ret_t EPD_OK for success, EPD_FAIL for error. */ -epd_ret_t oled_ewl1501aa_init(oled_ewl1501aa_t *oled) { - EPD_ERROR_CHECK(oled_ewl1501aa_reset(oled)); - EPD_ERROR_CHECK(epd_common_execute_sequence(&oled->cb, oled->user_data, ewl1501aa_init_sequence, - sizeof(ewl1501aa_init_sequence))); +epd_ret_t oled_elw1501aa_init(oled_elw1501aa_t *oled) { + EPD_ERROR_CHECK(oled_elw1501aa_reset(oled)); + EPD_ERROR_CHECK(epd_common_execute_sequence(&oled->cb, oled->user_data, elw1501aa_init_sequence, + sizeof(elw1501aa_init_sequence))); + + EPD_ERROR_CHECK(oled_elw1501aa_power(oled, 1)); return EPD_OK; } @@ -75,16 +77,16 @@ epd_ret_t oled_ewl1501aa_init(oled_ewl1501aa_t *oled) { /** * @brief Upload frame buffer to screen. * - * @param oled pointer to oled_ewl1501aa_t + * @param oled pointer to oled_elw1501aa_t * @param coord pointer to epd_coord_t, can be NULL to upload full frame. * @param data array pointer to new pixel data. * @return epd_ret_t EPD_OK for success, EPD_FAIL for error. */ -epd_ret_t oled_ewl1501aa_upload(oled_ewl1501aa_t *oled, epd_coord_t *coord, uint8_t *data) { +epd_ret_t oled_elw1501aa_upload(oled_elw1501aa_t *oled, epd_coord_t *coord, uint8_t *data) { uint32_t data_size = 8192; if (coord != NULL) { - EPD_ERROR_CHECK(oled_ewl1501aa_window(oled, coord)); - data_size = oled_ewl1501aa_data_size(coord); + EPD_ERROR_CHECK(oled_elw1501aa_window(oled, coord)); + data_size = oled_elw1501aa_data_size(coord); } EPD_ERROR_CHECK(oled->cb.write_data_cb(oled->user_data, data, data_size)); @@ -95,7 +97,7 @@ epd_ret_t oled_ewl1501aa_upload(oled_ewl1501aa_t *oled, epd_coord_t *coord, uint .y_start = 0, .y_end = 127, }; - EPD_ERROR_CHECK(oled_ewl1501aa_window(oled, &new_coord)); + EPD_ERROR_CHECK(oled_elw1501aa_window(oled, &new_coord)); } return EPD_OK; } @@ -105,11 +107,11 @@ epd_ret_t oled_ewl1501aa_upload(oled_ewl1501aa_t *oled, epd_coord_t *coord, uint * LCDs and OLEDs needs to be constant driven in order to * display a stable image, turn the drivers and source/gate scan on or off. * - * @param oled pointer to oled_ewl1501aa_t + * @param oled pointer to oled_elw1501aa_t * @param on 0:off, anything else: on * @return epd_ret_t EPD_OK for success, EPD_FAIL for error. */ -epd_ret_t oled_ewl1501aa_power(oled_ewl1501aa_t *oled, uint8_t on) { +epd_ret_t oled_elw1501aa_power(oled_elw1501aa_t *oled, uint8_t on) { uint8_t cmd[2] = {0xAE, 0x00}; if (on) cmd[0] = 0xAF; EPD_ERROR_CHECK(oled->cb.write_command_cb(oled->user_data, cmd, 1)); diff --git a/src/panel/oled_zjy150s700.c b/src/panel/oled_zjy150s700.c new file mode 100644 index 0000000..c0cd420 --- /dev/null +++ b/src/panel/oled_zjy150s700.c @@ -0,0 +1,123 @@ +#include "panel/oled_zjy150s700.h" + +#include "epd_private.h" + +static uint8_t zjy150s700_init_sequence[] = { + 0x01, 0x81, 0x77, // Set contrast control + 0x01, 0xA0, 0x53, // Set segment re-map + 0x01, 0xA1, 0x00, // Set display start line + 0x01, 0xA2, 0x00, // Set display offset + 0x00, 0xA4, // Set normal display mode + 0x01, 0xA8, 0x7F, // Set MUX ratio + 0x01, 0xAB, 0x01, // Set enable internal VDD regulator mode + 0x01, 0xB1, 0x31, // Set phase length of phase 1, phase 2 + 0x01, 0xB3, 0xB1, // Set ratio of dividing frequency & oscillation frequency + 0x01, 0xB5, 0x03, // Set GPIO pin output high (External boost regulator EN) + 0x01, 0xB6, 0x0D, // Set pre-charge period + 0x00, 0xB9, // Set gray scale table + 0x01, 0xBC, 0x07, // Set pre-charge voltage + 0x01, 0xBE, 0x07, // Set voltage VCOMH + 0x01, 0xD5, 0x02, // Set second precharge enable + 0x02, 0x15, 0x00, 0x3F, // Set column address + 0x02, 0x75, 0x00, 0x7F, // Set row address +}; + +static epd_ret_t oled_zjy150s700_reset(oled_zjy150s700_t *oled) { + if (oled->cb.reset_cb != NULL) { + return oled->cb.reset_cb(oled->user_data); + } + + return EPD_OK; +} + +static epd_ret_t oled_zjy150s700_window(oled_zjy150s700_t *oled, epd_coord_t *coord) { + if (coord->x_start % 2 != 0 || coord->x_end % 2 == 0) { + return EPD_FAIL; + } + + if (coord->x_end > 127 || coord->x_start > coord->x_end) { + return EPD_FAIL; + } + + if (coord->y_end > 127 || coord->y_start > coord->y_end) { + return EPD_FAIL; + } + + uint8_t col_start = coord->x_start / 2; + uint8_t col_end = coord->x_end / 2; + + uint8_t col_cmd_buf[3] = {0x15, col_start, col_end}; + uint8_t row_cmd_buf[3] = {0x75, coord->y_start, coord->y_end}; + EPD_ERROR_CHECK(oled->cb.write_command_cb(oled->user_data, col_cmd_buf, 3)); + EPD_ERROR_CHECK(oled->cb.write_command_cb(oled->user_data, row_cmd_buf, 3)); + + return EPD_OK; +} + +static inline uint32_t oled_zjy150s700_data_size(epd_coord_t *coord) { + return (coord->x_end - coord->x_start + 1) * (coord->y_end - coord->y_start + 1) / 2; +} + +/** + * @brief Initialize OLED panel + * As OLEDs and LCDs need to be driven constantly, also with + * less overhead and higher data rate, initialization sequence + * are moved to this seperate function. Call this function before + * sending framebuffer data. + * @param oled pointer to oled_zjy150s700_t + * @return epd_ret_t EPD_OK for success, EPD_FAIL for error. + */ +epd_ret_t oled_zjy150s700_init(oled_zjy150s700_t *oled) { + EPD_ERROR_CHECK(oled_zjy150s700_reset(oled)); + EPD_ERROR_CHECK(epd_common_execute_sequence(&oled->cb, oled->user_data, zjy150s700_init_sequence, + sizeof(zjy150s700_init_sequence))); + + EPD_ERROR_CHECK(oled_zjy150s700_power(oled, 1)); + + return EPD_OK; +} + +/** + * @brief Upload frame buffer to screen. + * + * @param oled pointer to oled_zjy150s700_t + * @param coord pointer to epd_coord_t, can be NULL to upload full frame. + * @param data array pointer to new pixel data. + * @return epd_ret_t EPD_OK for success, EPD_FAIL for error. + */ +epd_ret_t oled_zjy150s700_upload(oled_zjy150s700_t *oled, epd_coord_t *coord, uint8_t *data) { + uint32_t data_size = 8192; + if (coord != NULL) { + EPD_ERROR_CHECK(oled_zjy150s700_window(oled, coord)); + data_size = oled_zjy150s700_data_size(coord); + } + EPD_ERROR_CHECK(oled->cb.write_data_cb(oled->user_data, data, data_size)); + + if (coord != NULL) { + epd_coord_t new_coord = { + .x_start = 0, + .x_end = 127, + .y_start = 0, + .y_end = 127, + }; + EPD_ERROR_CHECK(oled_zjy150s700_window(oled, &new_coord)); + } + return EPD_OK; +} + +/** + * @brief Control the OLED drivers. + * LCDs and OLEDs needs to be constant driven in order to + * display a stable image, turn the drivers and source/gate scan on or off. + * + * @param oled pointer to oled_zjy150s700_t + * @param on 0:off, anything else: on + * @return epd_ret_t EPD_OK for success, EPD_FAIL for error. + */ +epd_ret_t oled_zjy150s700_power(oled_zjy150s700_t *oled, uint8_t on) { + uint8_t cmd[2] = {0xAE, 0x00}; + if (on) cmd[0] = 0xAF; + EPD_ERROR_CHECK(oled->cb.write_command_cb(oled->user_data, cmd, 1)); + + return EPD_OK; +} \ No newline at end of file