diff --git a/README.Md b/README.Md index 0086b48..82b517b 100644 --- a/README.Md +++ b/README.Md @@ -20,6 +20,7 @@ pushing updates to it. For this reason no additional NIFs are provided. software dithering * `sharp,memory-lcd`: Sharp Memory LCDs: 400x240 1-bit monochromatic * `solomon-systech,ssd1306`: Solomon Systech SSD1306: 128x64 1-bit monochromatic +* `sino-wealth,sh1106`: Sino Wealth SH1106: 128x64 1-bit monochromatic [SDL Linux display](sdl_display/) is also supported and can be built as AtomVM plugin. diff --git a/display_driver.c b/display_driver.c index 47b66af..53a9b6f 100644 --- a/display_driver.c +++ b/display_driver.c @@ -62,6 +62,8 @@ Context *display_create_port(GlobalContext *global, term opts) ctx = ili934x_display_create_port(global, opts); } else if (!strcmp(compat_string, "solomon-systech,ssd1306")) { ctx = ssd1306_display_create_port(global, opts); + } else if (!strcmp(compat_string, "sino-wealth,sh1106")) { + ctx = ssd1306_display_create_port(global, opts); } else { ESP_LOGE(TAG, "No matching display driver for given `comptaible`: `%s`.", compat_string); } diff --git a/ssd1306_display_driver.c b/ssd1306_display_driver.c index 257f683..d914a17 100644 --- a/ssd1306_display_driver.c +++ b/ssd1306_display_driver.c @@ -57,6 +57,7 @@ struct SPI { term i2c_host; + bool is_sh1106; Context *ctx; }; @@ -112,12 +113,36 @@ static void do_update(Context *ctx, term display_list) cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, CTRL_BYTE_CMD_SINGLE, true); i2c_master_write_byte(cmd, 0xB0 | ypos / 8, true); + if (spi->is_sh1106) { + // set the column, otherwise the starting column will be somewhere in the middle + i2c_master_write_byte(cmd, CTRL_BYTE_CMD_SINGLE, true); + i2c_master_write_byte(cmd, 0x00, true); + i2c_master_write_byte(cmd, CTRL_BYTE_CMD_SINGLE, true); + i2c_master_write_byte(cmd, 0x10, true); + } i2c_master_write_byte(cmd, CTRL_BYTE_DATA_STREAM, true); + + + if (spi->is_sh1106) { + // add 2 empty pages on sh1106 since it can have up to 132 pixels + // and 128 pixel screen starts at (2, 0) + i2c_master_write_byte(cmd, 0, true); + i2c_master_write_byte(cmd, 0, true); + } + for (uint8_t j = 0; j < DISPLAY_WIDTH; j++) { i2c_master_write_byte(cmd, out_buf[j], true); } + + // no need to send the last 2 page, the position will be set on next line again + // if (spi->is_sh1106) { + // i2c_master_write_byte(cmd, 0, true); + // i2c_master_write_byte(cmd, 0, true); + // } + i2c_master_stop(cmd); i2c_master_cmd_begin(i2c_num, cmd, 10 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); @@ -152,6 +177,16 @@ static void display_init(Context *ctx, term opts) spi->ctx = ctx; + term compat_value_term = interop_kv_get_value_default(opts, ATOM_STR("\xA", "compatible"), term_nil(), ctx->global); + int str_ok; + char *compat_string = interop_term_to_string(compat_value_term, &str_ok); + if (str_ok && compat_string) { + spi->is_sh1106 = !strcmp(compat_string, "sino-wealth,sh1106"); + free(compat_string); + } else { + return; + } + int reset_gpio; if (!display_common_gpio_from_opts(opts, ATOM_STR("\x5", "reset"), &reset_gpio, glb)) { ESP_LOGI(TAG, "Reset GPIO not configured.");