Add SH1106 OLED support (#5787)

* modify oled_driver to support SH1106

also:
- improve mechanism to specify which OLED IC we use
- comment calc_bounds()
- give OLED_COLUMN_OFFSET a default value
- inline comment re: OLED MEMORY_MODE and SH1106
- update docs/feature_oled_driver.h for SH1106 support and related changes
- docs: OLED: note we have tested SSD1306 on ARM boards (per @XScorpion2)
- define out MEMORY_MODE when using SH1106 OLED driver

* document that SSD1306 128x64 on AVR works

Per @XScorpion2: https://github.com/qmk/qmk_firmware/pull/5787#discussion_r291837842
pull/6512/head
Michael F. Lamb 6 years ago committed by Florian Didron
parent 2aa3b88823
commit 1c9011fbd1

@ -33,6 +33,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif // defined(__AVR__) #endif // defined(__AVR__)
// Used commands from spec sheet: https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf // Used commands from spec sheet: https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
// for SH1106: https://www.velleman.eu/downloads/29/infosheets/sh1106_datasheet.pdf
// Fundamental Commands // Fundamental Commands
#define CONTRAST 0x81 #define CONTRAST 0x81
#define DISPLAY_ALL_ON 0xA5 #define DISPLAY_ALL_ON 0xA5
@ -40,6 +42,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define NORMAL_DISPLAY 0xA6 #define NORMAL_DISPLAY 0xA6
#define DISPLAY_ON 0xAF #define DISPLAY_ON 0xAF
#define DISPLAY_OFF 0xAE #define DISPLAY_OFF 0xAE
#define NOP 0xE3
// Scrolling Commands // Scrolling Commands
#define ACTIVATE_SCROLL 0x2F #define ACTIVATE_SCROLL 0x2F
@ -53,6 +56,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MEMORY_MODE 0x20 #define MEMORY_MODE 0x20
#define COLUMN_ADDR 0x21 #define COLUMN_ADDR 0x21
#define PAGE_ADDR 0x22 #define PAGE_ADDR 0x22
#define PAM_SETCOLUMN_LSB 0x00
#define PAM_SETCOLUMN_MSB 0x10
#define PAM_PAGE_ADDR 0xB0 // 0xb0 -- 0xb7
// Hardware Configuration Commands // Hardware Configuration Commands
#define DISPLAY_START_LINE 0x40 #define DISPLAY_START_LINE 0x40
@ -158,7 +164,11 @@ bool oled_init(uint8_t rotation) {
DISPLAY_OFFSET, 0x00, DISPLAY_OFFSET, 0x00,
DISPLAY_START_LINE | 0x00, DISPLAY_START_LINE | 0x00,
CHARGE_PUMP, 0x14, CHARGE_PUMP, 0x14,
MEMORY_MODE, 0x00, }; // Horizontal addressing mode #if (OLED_IC != OLED_IC_SH1106)
// MEMORY_MODE is unsupported on SH1106 (Page Addressing only)
MEMORY_MODE, 0x00, // Horizontal addressing mode
#endif
};
if (I2C_TRANSMIT_P(display_setup1) != I2C_STATUS_SUCCESS) { if (I2C_TRANSMIT_P(display_setup1) != I2C_STATUS_SUCCESS) {
print("oled_init cmd set 1 failed\n"); print("oled_init cmd set 1 failed\n");
return false; return false;
@ -219,10 +229,25 @@ void oled_clear(void) {
static void calc_bounds(uint8_t update_start, uint8_t* cmd_array) static void calc_bounds(uint8_t update_start, uint8_t* cmd_array)
{ {
cmd_array[1] = OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_WIDTH; // Calculate commands to set memory addressing bounds.
cmd_array[4] = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_WIDTH; uint8_t start_page = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_WIDTH;
uint8_t start_column = OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_WIDTH;
#if (OLED_IC == OLED_IC_SH1106)
// Commands for Page Addressing Mode. Sets starting page and column; has no end bound.
// Column value must be split into high and low nybble and sent as two commands.
cmd_array[0] = PAM_PAGE_ADDR | start_page;
cmd_array[1] = PAM_SETCOLUMN_LSB | ((OLED_COLUMN_OFFSET + start_column) & 0x0f);
cmd_array[2] = PAM_SETCOLUMN_MSB | ((OLED_COLUMN_OFFSET + start_column) >> 4 & 0x0f);
cmd_array[3] = NOP;
cmd_array[4] = NOP;
cmd_array[5] = NOP;
#else
// Commands for use in Horizontal Addressing mode.
cmd_array[1] = start_column;
cmd_array[4] = start_page;
cmd_array[2] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) % OLED_DISPLAY_WIDTH + cmd_array[1]; cmd_array[2] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) % OLED_DISPLAY_WIDTH + cmd_array[1];
cmd_array[5] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) / OLED_DISPLAY_WIDTH - 1; cmd_array[5] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) / OLED_DISPLAY_WIDTH - 1;
#endif
} }
static void calc_bounds_90(uint8_t update_start, uint8_t* cmd_array) static void calc_bounds_90(uint8_t update_start, uint8_t* cmd_array)

@ -19,6 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
// an enumeration of the chips this driver supports
#define OLED_IC_SSD1306 0
#define OLED_IC_SH1106 1
#if defined(OLED_DISPLAY_CUSTOM) #if defined(OLED_DISPLAY_CUSTOM)
// Expected user to implement the necessary defines // Expected user to implement the necessary defines
@ -100,7 +103,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// #define OLED_TARGET_MAP { 48, 32, 16, 0, 56, 40, 24, 8 } // #define OLED_TARGET_MAP { 48, 32, 16, 0, 56, 40, 24, 8 }
#endif // defined(OLED_DISPLAY_CUSTOM) #endif // defined(OLED_DISPLAY_CUSTOM)
// Address to use for tthe i2d oled communication #if !defined(OLED_IC)
#define OLED_IC OLED_IC_SSD1306
#endif
// the column address corresponding to the first column in the display hardware
#if !defined(OLED_COLUMN_OFFSET)
#define OLED_COLUMN_OFFSET 0
#endif
// Address to use for the i2c oled communication
#if !defined(OLED_DISPLAY_ADDRESS) #if !defined(OLED_DISPLAY_ADDRESS)
#define OLED_DISPLAY_ADDRESS 0x3C #define OLED_DISPLAY_ADDRESS 0x3C
#endif #endif

Loading…
Cancel
Save