summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael F. Lamb <mike@datagrok.org>2019-06-11 15:27:17 -0700
committerDrashna Jaelre <drashna@live.com>2019-06-11 15:27:17 -0700
commite6a81133dd3d0d4076a08be76340f905fdbf7c7f (patch)
tree41fbbc4143b915596d5bccd5bd94a3ee74d66048
parentb92387b7499e21603e241d136db92c6e716b0cba (diff)
downloadqmk_firmware-e6a81133dd3d0d4076a08be76340f905fdbf7c7f.tar.gz
qmk_firmware-e6a81133dd3d0d4076a08be76340f905fdbf7c7f.zip
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
-rw-r--r--docs/feature_oled_driver.md38
-rw-r--r--drivers/oled/oled_driver.c31
-rw-r--r--drivers/oled/oled_driver.h14
3 files changed, 67 insertions, 16 deletions
diff --git a/docs/feature_oled_driver.md b/docs/feature_oled_driver.md
index 144b695b76..155dfa9d29 100644
--- a/docs/feature_oled_driver.md
+++ b/docs/feature_oled_driver.md
@@ -2,7 +2,17 @@
## OLED Supported Hardware
-128x32 OLED modules using SSD1306 driver IC over I2C. Supported on AVR based keyboards. Possible but untested hardware includes ARM based keyboards and other sized OLED modules using SSD1306 over I2C, such as 128x64.
+OLED modules using SSD1306 or SH1106 driver ICs, communicating over I2C.
+Tested combinations:
+
+| IC driver | Size | Keyboard Platform | Notes |
+|-----------|--------|-------------------|--------------------------|
+| SSD1306 | 128x32 | AVR | Primary support |
+| SSD1306 | 128x64 | AVR | Verified working |
+| SSD1306 | 128x32 | ARM | |
+| SH1106 | 128x64 | AVR | No rotation or scrolling |
+
+Hardware configurations using ARM-based microcontrollers or different sizes of OLED modules may be compatible, but are untested.
!> Warning: This OLED Driver currently uses the new i2c_master driver from split common code. If your split keyboard uses i2c to communication between sides this driver could cause an address conflict (serial is fine). Please contact your keyboard vendor and ask them to migrate to the latest split common code to fix this.
@@ -86,17 +96,17 @@ void oled_task_user(void) {
## Basic Configuration
-|Define |Default |Description |
-|-----------------------|---------------|------------------------------------------------|
-|`OLED_DISPLAY_ADDRESS` |`0x3C` |The i2c address of the OLED Display |
-|`OLED_FONT_H` |`"glcdfont.c"` |The font code file to use for custom fonts |
-|`OLED_FONT_START` |`0` |The starting characer index for custom fonts |
-|`OLED_FONT_END` |`224` |The ending characer index for custom fonts |
-|`OLED_FONT_WIDTH` |`6` |The font width |
-|`OLED_FONT_HEIGHT` |`8` |The font height (untested) |
-|`OLED_DISABLE_TIMEOUT` |*Not defined* |Disables the built in OLED timeout feature. Useful when implementing custom timeout rules.|
-
-
+| Define | Default | Description |
+|------------------------|-------------------|----------------------------------------------------------------------------------------------------------------------------|
+| `OLED_DISPLAY_ADDRESS` | `0x3C` | The i2c address of the OLED Display |
+| `OLED_FONT_H` | `"glcdfont.c"` | The font code file to use for custom fonts |
+| `OLED_FONT_START` | `0` | The starting characer index for custom fonts |
+| `OLED_FONT_END` | `224` | The ending characer index for custom fonts |
+| `OLED_FONT_WIDTH` | `6` | The font width |
+| `OLED_FONT_HEIGHT` | `8` | The font height (untested) |
+| `OLED_DISABLE_TIMEOUT` | *Not defined* | Disables the built in OLED timeout feature. Useful when implementing custom timeout rules. |
+| `OLED_IC` | `OLED_IC_SSD1306` | Set to `OLED_IC_SH1106` if you're using the SH1106 OLED controller. |
+| `OLED_COLUMN_OFFSET` | `0` | (SH1106 only.) Shift output to the right this many pixels.<br />Useful for 128x64 displays centered on a 132x64 SH1106 IC. |
## 128x64 & Custom sized OLED Displays
@@ -119,6 +129,8 @@ void oled_task_user(void) {
### 90 Degree Rotation - Technical Mumbo Jumbo
+!> Rotation is unsupported on the SH1106.
+
```C
// OLED Rotation enum values are flags
typedef enum {
@@ -250,6 +262,8 @@ uint8_t oled_max_chars(void);
uint8_t oled_max_lines(void);
```
+!> Scrolling and rotation are unsupported on the SH1106.
+
## SSD1306.h driver conversion guide
|Old API |Recommended New API |
diff --git a/drivers/oled/oled_driver.c b/drivers/oled/oled_driver.c
index 643e528946..a54f5fadc3 100644
--- a/drivers/oled/oled_driver.c
+++ b/drivers/oled/oled_driver.c
@@ -33,6 +33,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif // defined(__AVR__)
// 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
#define CONTRAST 0x81
#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 DISPLAY_ON 0xAF
#define DISPLAY_OFF 0xAE
+#define NOP 0xE3
// Scrolling Commands
#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 COLUMN_ADDR 0x21
#define PAGE_ADDR 0x22
+#define PAM_SETCOLUMN_LSB 0x00
+#define PAM_SETCOLUMN_MSB 0x10
+#define PAM_PAGE_ADDR 0xB0 // 0xb0 -- 0xb7
// Hardware Configuration Commands
#define DISPLAY_START_LINE 0x40
@@ -158,7 +164,11 @@ bool oled_init(uint8_t rotation) {
DISPLAY_OFFSET, 0x00,
DISPLAY_START_LINE | 0x00,
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) {
print("oled_init cmd set 1 failed\n");
return false;
@@ -219,10 +229,25 @@ void oled_clear(void) {
static void calc_bounds(uint8_t update_start, uint8_t* cmd_array)
{
- cmd_array[1] = OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_WIDTH;
- cmd_array[4] = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_WIDTH;
+ // Calculate commands to set memory addressing bounds.
+ 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[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)
diff --git a/drivers/oled/oled_driver.h b/drivers/oled/oled_driver.h
index abbdde57ed..03dda2e64a 100644
--- a/drivers/oled/oled_driver.h
+++ b/drivers/oled/oled_driver.h
@@ -19,6 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdint.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)
// 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 }
#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)
#define OLED_DISPLAY_ADDRESS 0x3C
#endif