From b2c6174c2c3b14713274dda313d51861e9d5ad88 Mon Sep 17 00:00:00 2001 From: Andrey Chilikin Date: Wed, 7 Oct 2015 20:28:46 +0100 Subject: [PATCH] Added support for SH1106 Now both SSD1306 and SH1106 controllers supported --- main.c | 13 +++++-- ossd_i2c.c | 109 +++++++++++++++++++++-------------------------------- ossd_i2c.h | 24 ++++++++---- 3 files changed, 69 insertions(+), 77 deletions(-) diff --git a/main.c b/main.c index d3158a5..a5a29ef 100644 --- a/main.c +++ b/main.c @@ -16,7 +16,7 @@ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @@ -43,7 +43,7 @@ /** sarg: short argument - larg: long argument + larg: long argument */ static int arg_is(const char *arg, const char *sarg, const char *larg) { @@ -77,6 +77,7 @@ int main(int argc, char **argv) char *file; bdfe_t *font; int flags = 0; + uint8_t driver = OSSD_SSD1306; uint8_t i2c_bus = 1; uint8_t i2c_address = 0x3C; uint8_t orientation = 0; @@ -136,6 +137,12 @@ int main(int argc, char **argv) if (arg_is(argv[i], "-r", "rotate")) flags |= BDF_ROTATE; + if (arg_is(argv[i], "-3", "ssd1306")) + driver = OSSD_SSD1306; + + if (arg_is(argv[i], "-1", "sh1106")) + driver = OSSD_SH1106; + if (arg_is(argv[i], "-B", "i2c_bus")) { i++; uint32_t i2bus = strtoul(argv[i], NULL, 16); @@ -193,7 +200,7 @@ int main(int argc, char **argv) of.gn = (uint8_t)font->chars; of.font = font->font; - ossd_init(i2c_bus, orientation); + ossd_init(driver, i2c_bus, orientation); ossd_set_user_font(&of, NULL); ossd_select_font(OSSD_FONT_USER); diff --git a/ossd_i2c.c b/ossd_i2c.c index f183528..6e2e151 100644 --- a/ossd_i2c.c +++ b/ossd_i2c.c @@ -16,7 +16,7 @@ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @@ -25,7 +25,7 @@ */ /** - Limited set of functions for SSD1306 compatible OLED 128x64 displays + Limited set of functions for SSD1306 / SH1106 compatible OLED 128x64 displays in text mode to minimize memory footprint if used on Atmel AVRs chips with low memory. */ @@ -34,12 +34,12 @@ #include "ossd_i2c.h" -#if (OSSD_TARGET == OSSD_IF_AVR) +#if (OSSD_TARGET == OSSD_IF_AVR) #include #include #include #include "i2cmaster.h" -#else +#else #define PROGMEM #define pgm_read_byte(x) (*((uint8_t *)x)) #include @@ -105,6 +105,16 @@ #define OSSD_CHARGE_PUMP_ON 0x14 #define OSSD_CHARGE_PUMP_OFF 0x10 +#define OSSD_SET_DC_DC 0xAD +#define OSSD_DC_DC_DISABLE 0x8A +#define OSSD_DC_DC_ENABLE 0x8B + +#define OSSD_SET_PUMP_VPP 0x30 +#define OSSD_VPP_V74 0x00 // 7.4V +#define OSSD_VPP_V80 0x01 // 8.0V +#define OSSD_VPP_V84 0x02 // 8.4V +#define OSSD_VPP_V90 0x03 // 9.0V + static const uint8_t font68[] PROGMEM = { #include "font6x8.h" }; @@ -118,14 +128,14 @@ static const uint8_t font816[] PROGMEM = { }; static ossd_font_t _ofont[OSSD_FONT_MAX+1] = { - { 6, 8, 32, 127-32, font68 }, + { 6, 8, 32, 127-32, font68 }, { 8, 8, 32, 127-32, font88 }, { 8, 16, 32, 127-32, font816 }, { 0, 0, 0, 0, NULL } }; static uint8_t _cfont; -static uint8_t _mode; +static uint8_t _offset; static uint8_t _i2c_val; uint8_t ossd_select_font(uint8_t font) @@ -146,7 +156,7 @@ void ossd_set_user_font(ossd_font_t *nfont, ossd_font_t *ofont) ofont->font = _ofont[OSSD_FONT_USER].font; } _ofont[OSSD_FONT_USER].gw = nfont->gw; - _ofont[OSSD_FONT_USER].gh = nfont->gh; + _ofont[OSSD_FONT_USER].gh = nfont->gh; _ofont[OSSD_FONT_USER].go = nfont->go; _ofont[OSSD_FONT_USER].gn = nfont->gn; _ofont[OSSD_FONT_USER].font = nfont->font; @@ -172,16 +182,6 @@ static void ossd_cmd_arg(uint8_t cmd, uint8_t arg) li2c_write(_i2c_val, data, 3); } -static void ossd_cmd_arg2(uint8_t cmd, uint8_t arg1, uint8_t arg2) -{ - uint8_t data[4]; - data[0] = OSSD_CMD; - data[1] = cmd; - data[2] = arg1; - data[3] = arg2; - li2c_write(_i2c_val, data, 4); -} - static void ossd_fill_line(uint8_t data, uint8_t num) { uint8_t *buf = (uint8_t *)alloca(num+1); @@ -209,16 +209,6 @@ static void ossd_cmd_arg(uint8_t cmd, uint8_t arg) i2c_stop(); } -static void ossd_cmd_arg2(uint8_t cmd, uint8_t arg1, uint8_t arg2) -{ - i2c_start(_i2c_val); - i2c_write(OSSD_CMD); - i2c_write(cmd); - i2c_write(arg1); - i2c_write(arg2); - i2c_stop(); -} - #if (OSSD_TARGET == OSSD_IF_AVR) static void ossd_fill_line(uint8_t data, uint8_t num) @@ -255,35 +245,12 @@ static inline void ossd_data(uint8_t data) ossd_send_byte(OSSD_DATA, data); } -static uint8_t ossd_set_addr_mode(uint8_t set_mode) -{ - uint8_t ret = _mode; - if (_mode != set_mode) { - ossd_cmd_arg(OSSD_SET_ADDR_MODE, set_mode); - // if switching back to page mode - // set full screen as output region - if (set_mode == OSSD_ADDR_MODE_PAGE) { - ossd_cmd_arg2(OSSD_SET_PAGE_ADDR, 0, 7); - ossd_cmd_arg2(OSSD_SET_COL_ADDR, 0, 127); - } - _mode = set_mode; - } - return ret; -} - void ossd_goto(uint8_t line, uint8_t x) { - if (_mode == OSSD_ADDR_MODE_PAGE) { - ossd_cmd(OSSD_SET_START_PAGE | (line & 0x07)); - ossd_cmd(OSSD_SET_START_LCOL | (x & 0x0F)); - ossd_cmd(OSSD_SET_START_HCOL | (x >> 4)); - } - else { - uint8_t gw = _ofont[_cfont].gw; - // in OSSD_ADDR_MODE_HOR/VER mode we set output region (gw x 16) - ossd_cmd_arg2(OSSD_SET_COL_ADDR, x, x + gw - 1); - ossd_cmd_arg2(OSSD_SET_PAGE_ADDR, line, line+1); - } + x += _offset; + ossd_cmd(OSSD_SET_START_PAGE | (line & 0x07)); + ossd_cmd(OSSD_SET_START_LCOL | (x & 0x0F)); + ossd_cmd(OSSD_SET_START_HCOL | (x >> 4)); } void ossd_fill_screen(uint8_t data) @@ -294,7 +261,7 @@ void ossd_fill_screen(uint8_t data) ossd_goto(line, 0); ossd_fill_line(data, 128); } -} +} void ossd_sleep(uint8_t on_off) { @@ -365,22 +332,23 @@ void ossd_putlx(uint8_t line, int8_t x, const char *str, uint8_t atr) over = 0x01; if (atr & OSSD_TEXT_UNDERLINE) under = 0x80; - + uint8_t gw = _ofont[_cfont].gw; uint8_t gh = _ofont[_cfont].gh; uint8_t go = _ofont[_cfont].go; uint8_t gb = gw*(gh / 8); // bytes per glyph const uint8_t *font = _ofont[_cfont].font; - uint8_t cmode = ossd_set_addr_mode(OSSD_ADDR_MODE_HOR); for(; *str != '\0'; str++, x += gw) { uint16_t idx = (*str - go) * gb; if ((uint8_t)x > (128 - gw)) { x = 0; line = (line + (gh+7)/8) & 0x07; } - ossd_goto(line, x); + ossd_goto(line, x); uint8_t i; for(i = 0; i < gb; i++) { + if ((gh > 8) && (i == 8)) + ossd_goto(line + 1, x); uint8_t d = pgm_read_byte(&font[idx+i]); d ^= rev; if (under && (gh == 8 || i > (gw - 1))) @@ -390,21 +358,23 @@ void ossd_putlx(uint8_t line, int8_t x, const char *str, uint8_t atr) ossd_data(d); } } - ossd_set_addr_mode(cmode); } -void ossd_init(uint8_t i2c_val, uint8_t orientation) +void ossd_init(uint8_t driver, uint8_t i2c_val, uint8_t orientation) { - _mode = 0xFF; + _offset = 0; _i2c_val = i2c_val; -#if (OSSD_TARGET == OSSD_IF_AVR) +#if (OSSD_TARGET == OSSD_IF_AVR) _i2c_val = (_i2c_val << 1) | I2C_WRITE; #endif - // set all default values + /* set all default values */ ossd_cmd(OSSD_SET_SLEEP_ON); - ossd_cmd_arg(OSSD_SET_MUX_RATIO, 63); + ossd_cmd_arg(OSSD_SET_MUX_RATIO, 63); ossd_cmd_arg(OSSD_SET_DISP_OFFSET, 0); + ossd_cmd(OSSD_SET_START_PAGE); ossd_cmd(OSSD_SET_START_LINE | 0); + ossd_cmd(OSSD_SET_START_LCOL | 2); + ossd_cmd(OSSD_SET_START_HCOL | 0); ossd_cmd(OSSD_SET_SEG_REMAP | (orientation & OSSD_SEG_REMAP_R2L)); ossd_cmd(OSSD_SET_COM_DIR | (orientation & OSSD_COM_DIR_UPDOWN)); ossd_cmd_arg(OSSD_SET_COM_CONFIG, OSSD_COM_ALT); @@ -414,8 +384,15 @@ void ossd_init(uint8_t i2c_val, uint8_t orientation) ossd_cmd_arg(OSSD_SET_PRECHARGE, 0x22); ossd_cmd_arg(OSSD_SET_VCOMH_LEVEL, OSSD_VCOMH_L077); ossd_cmd(OSSD_SET_INVERSE_OFF); - ossd_cmd_arg(OSSD_SET_CHARGE_PUMP, OSSD_CHARGE_PUMP_ON); - ossd_set_addr_mode(OSSD_ADDR_MODE_PAGE); + + if (driver != OSSD_SH1106) + ossd_cmd_arg(OSSD_SET_CHARGE_PUMP, OSSD_CHARGE_PUMP_ON); + else { + ossd_cmd_arg(OSSD_SET_DC_DC, OSSD_DC_DC_ENABLE); /* POR */ + ossd_cmd(OSSD_SET_PUMP_VPP | OSSD_VPP_V74); + _offset = 2; + } + ossd_fill_screen(0x00); ossd_cmd(OSSD_SET_SLEEP_OFF); ossd_goto(0, 0); diff --git a/ossd_i2c.h b/ossd_i2c.h index d3a07c9..c462622 100644 --- a/ossd_i2c.h +++ b/ossd_i2c.h @@ -16,7 +16,7 @@ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @@ -27,8 +27,9 @@ #define __OLED_SSD1306_I2C__ /** - Limited set of functions for SSD1306 compatible OLED displays in text mode - to minimize memory footprint if used on Atmel AVRs with low memory. + Limited set of functions for SSD1306 / SH1106 compatible OLED 128x64 displays + in text mode to minimize memory footprint if used on Atmel AVRs chips + with low memory. */ #ifdef __cplusplus @@ -70,7 +71,13 @@ typedef struct ossd_font_s const uint8_t *font; } ossd_font_t; -/** +/** + Most common OLED drivers SSD1306 and SH1106 are supported + */ +#define OSSD_SH1106 0 +#define OSSD_SSD1306 1 + +/** flat cable connected at the top use ossd_init(OSSD_UPDOWN) to rotate screen */ @@ -79,10 +86,11 @@ typedef struct ossd_font_s /** set default parameters - for AVR i2c_val is I2C address - for Linux (Edison, RPi) i2c_val is I2C bus + driver: OSSD_SSD1306 or OSSD_SH1106 + i2c_val: I2C address for AVR + I2C bus for Linux (Edison, RPi) */ -void ossd_init(uint8_t i2c_val, uint8_t orientation); +void ossd_init(uint8_t driver, uint8_t i2c_val, uint8_t orientation); /** fill screen with specified pattern */ void ossd_fill_screen(uint8_t data); @@ -96,7 +104,7 @@ void ossd_set_contrast(uint8_t val); /** select one of three fonts for following ossd_putlx() calls */ uint8_t ossd_select_font(uint8_t font); -/** +/** set user font selectable by OSSD_FONT_USER to nfont store current user font in ofont (if not NULL) */ -- 2.39.5