aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/feature_oled_driver.md42
-rw-r--r--drivers/oled/oled_driver.c7
-rw-r--r--drivers/oled/oled_driver.h43
-rwxr-xr-xkeyboards/sol/keymaps/brianweyer/keymap.c2
-rw-r--r--keyboards/sol/keymaps/danielhklein/keymap.c2
-rw-r--r--keyboards/sol/keymaps/default/keymap.c2
-rw-r--r--keyboards/zen/rev2/config.h13
-rw-r--r--keyboards/zen/rev2/rev2.c8
-rw-r--r--keyboards/zen/rev2/rules.mk7
9 files changed, 69 insertions, 57 deletions
diff --git a/docs/feature_oled_driver.md b/docs/feature_oled_driver.md
index f261bbef1..7011f1457 100644
--- a/docs/feature_oled_driver.md
+++ b/docs/feature_oled_driver.md
@@ -56,7 +56,7 @@ In split keyboards, it is very common to have two OLED displays that each render
56 56
57```C++ 57```C++
58#ifdef OLED_DRIVER_ENABLE 58#ifdef OLED_DRIVER_ENABLE
59uint8_t oled_init_user(uint8_t rotation) { 59oled_rotation_t oled_init_user(oled_rotation_t rotation) {
60 if (!is_keyboard_master()) 60 if (!is_keyboard_master())
61 return OLED_ROTATION_180; // flips the display 180 degrees if offhand 61 return OLED_ROTATION_180; // flips the display 180 degrees if offhand
62 return rotation; 62 return rotation;
@@ -99,18 +99,28 @@ void oled_task_user(void) {
99|`OLED_DISPLAY_WIDTH` |`128` |The width of the OLED display. | 99|`OLED_DISPLAY_WIDTH` |`128` |The width of the OLED display. |
100|`OLED_DISPLAY_HEIGHT` |`32` |The height of the OLED display. | 100|`OLED_DISPLAY_HEIGHT` |`32` |The height of the OLED display. |
101|`OLED_MATRIX_SIZE` |`512` |The local buffer size to allocate.<br />`(OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)`| 101|`OLED_MATRIX_SIZE` |`512` |The local buffer size to allocate.<br />`(OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)`|
102|`OLED_BLOCK_TYPE` |`uint8_t` |The unsigned integer type to use for dirty rendering.| 102|`OLED_BLOCK_TYPE` |`uint16_t` |The unsigned integer type to use for dirty rendering.|
103|`OLED_BLOCK_COUNT` |`8` |The number of blocks the display is divided into for dirty rendering.<br />`(sizeof(OLED_BLOCK_TYPE) * 8)`| 103|`OLED_BLOCK_COUNT` |`16` |The number of blocks the display is divided into for dirty rendering.<br />`(sizeof(OLED_BLOCK_TYPE) * 8)`|
104|`OLED_BLOCK_SIZE` |`64` |The size of each block for dirty rendering<br />`(OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)`| 104|`OLED_BLOCK_SIZE` |`32` |The size of each block for dirty rendering<br />`(OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)`|
105|`OLED_SOURCE_MAP` |`{ 0, ... N }` |Precalculated source array to use for mapping source buffer to target OLED memory in 90 degree rendering. | 105|`OLED_SOURCE_MAP` |`{ 0, ... N }` |Precalculated source array to use for mapping source buffer to target OLED memory in 90 degree rendering. |
106|`OLED_TARGET_MAP` |`{ 48, ... N }`|Precalculated target array to use for mapping source buffer to target OLED memory in 90 degree rendering. | 106|`OLED_TARGET_MAP` |`{ 24, ... N }`|Precalculated target array to use for mapping source buffer to target OLED memory in 90 degree rendering. |
107 107
108 108
109### 90 Degree Rotation - Technical Mumbo Jumbo 109### 90 Degree Rotation - Technical Mumbo Jumbo
110 110
111```C
112// OLED Rotation enum values are flags
113typedef enum {
114 OLED_ROTATION_0 = 0,
115 OLED_ROTATION_90 = 1,
116 OLED_ROTATION_180 = 2,
117 OLED_ROTATION_270 = 3, // OLED_ROTATION_90 | OLED_ROTATION_180
118} oled_rotation_t;
119```
120
111 OLED displays driven by SSD1306 drivers only natively support in hard ware 0 degree and 180 degree rendering. This feature is done in software and not free. Using this feature will increase the time to calculate what data to send over i2c to the OLED. If you are strapped for cycles, this can cause keycodes to not register. In testing however, the rendering time on an `atmega32u4` board only went from 2ms to 5ms and keycodes not registering was only noticed once we hit 15ms. 121 OLED displays driven by SSD1306 drivers only natively support in hard ware 0 degree and 180 degree rendering. This feature is done in software and not free. Using this feature will increase the time to calculate what data to send over i2c to the OLED. If you are strapped for cycles, this can cause keycodes to not register. In testing however, the rendering time on an `atmega32u4` board only went from 2ms to 5ms and keycodes not registering was only noticed once we hit 15ms.
112 122
113 90 Degree Rotated Rendering is achieved by using bitwise operations to rotate each 8 block of memory and uses two precalculated arrays to remap buffer memory to OLED memory. The memory map defines are precalculated for remap performance and are calculated based on the OLED Height, Width, and Block Size. For example, in the default 128x32 implementation we have a 64 byte block size. This gives us eight 8 byte blocks that need to be rotated and rendered. The OLED renders horizontally two 8 byte blocks before moving down a page, e.g: 123 90 Degree Rotated Rendering is achieved by using bitwise operations to rotate each 8 block of memory and uses two precalculated arrays to remap buffer memory to OLED memory. The memory map defines are precalculated for remap performance and are calculated based on the OLED Height, Width, and Block Size. For example, in the 128x32 implementation with a `uint8_t` block type, we have a 64 byte block size. This gives us eight 8 byte blocks that need to be rotated and rendered. The OLED renders horizontally two 8 byte blocks before moving down a page, e.g:
114 124
115| | | | | | | 125| | | | | | |
116|---|---|---|---|---|---| 126|---|---|---|---|---|---|
@@ -133,14 +143,22 @@ So those precalculated arrays just index the memory offsets in the order in whic
133## OLED API 143## OLED API
134 144
135```C++ 145```C++
136// Initialize the OLED display, rotating the rendered output 180 degrees if true. 146// OLED Rotation enum values are flags
147typedef enum {
148 OLED_ROTATION_0 = 0,
149 OLED_ROTATION_90 = 1,
150 OLED_ROTATION_180 = 2,
151 OLED_ROTATION_270 = 3, // OLED_ROTATION_90 | OLED_ROTATION_180
152} oled_rotation_t;
153
154// Initialize the OLED display, rotating the rendered output based on the define passed in.
137// Returns true if the OLED was initialized successfully 155// Returns true if the OLED was initialized successfully
138bool oled_init(bool flip180); 156bool oled_init(oled_rotation_t rotation);
139 157
140// Called at the start of oled_init, weak function overridable by the user 158// Called at the start of oled_init, weak function overridable by the user
141// flip180 - the value passed into oled_init 159// rotation - the value passed into oled_init
142// Return true if you want the oled to be flip180 160// Return new oled_rotation_t if you want to override default rotation
143bool oled_init_user(bool flip180); 161oled_rotation_t oled_init_user(oled_rotation_t rotation);
144 162
145// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering 163// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
146void oled_clear(void); 164void oled_clear(void);
@@ -217,7 +235,7 @@ bool oled_scroll_off(void);
217// Returns the maximum number of characters that will fit on a line 235// Returns the maximum number of characters that will fit on a line
218uint8_t oled_max_chars(void); 236uint8_t oled_max_chars(void);
219 237
220// Returns the maximum number of lines that will fit on the oled 238// Returns the maximum number of lines that will fit on the OLED
221uint8_t oled_max_lines(void); 239uint8_t oled_max_lines(void);
222``` 240```
223 241
diff --git a/drivers/oled/oled_driver.c b/drivers/oled/oled_driver.c
index aa025d7a4..96ea58ccb 100644
--- a/drivers/oled/oled_driver.c
+++ b/drivers/oled/oled_driver.c
@@ -203,7 +203,7 @@ bool oled_init(uint8_t rotation) {
203} 203}
204 204
205__attribute__((weak)) 205__attribute__((weak))
206uint8_t oled_init_user(uint8_t rotation) { 206oled_rotation_t oled_init_user(oled_rotation_t rotation) {
207 return rotation; 207 return rotation;
208} 208}
209 209
@@ -384,7 +384,10 @@ void oled_write_char(const char data, bool invert) {
384 384
385 // Dirty check 385 // Dirty check
386 if (memcmp(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH)) { 386 if (memcmp(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH)) {
387 oled_dirty |= (1 << ((oled_cursor - &oled_buffer[0]) / OLED_BLOCK_SIZE)); 387 uint16_t index = oled_cursor - &oled_buffer[0];
388 oled_dirty |= (1 << (index / OLED_BLOCK_SIZE));
389 // Edgecase check if the written data spans the 2 chunks
390 oled_dirty |= (1 << ((index + OLED_FONT_WIDTH) / OLED_BLOCK_SIZE));
388 } 391 }
389 392
390 // Finally move to the next char 393 // Finally move to the next char
diff --git a/drivers/oled/oled_driver.h b/drivers/oled/oled_driver.h
index 1ca31df11..ec07f1d9b 100644
--- a/drivers/oled/oled_driver.h
+++ b/drivers/oled/oled_driver.h
@@ -27,14 +27,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #define OLED_DISPLAY_WIDTH 128 27 #define OLED_DISPLAY_WIDTH 128
28 #define OLED_DISPLAY_HEIGHT 64 28 #define OLED_DISPLAY_HEIGHT 64
29 #define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 1024 (compile time mathed) 29 #define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 1024 (compile time mathed)
30 #define OLED_BLOCK_TYPE uint16_t 30 #define OLED_BLOCK_TYPE uint32_t
31 #define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 16 (compile time mathed) 31 #define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 32 (compile time mathed)
32 #define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 64 (compile time mathed) 32 #define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 32 (compile time mathed)
33 33
34 // For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays 34 // For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays
35 // The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode 35 // The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode
36 #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 } 36 #define OLED_SOURCE_MAP { 32, 40, 48, 56 }
37 #define OLED_TARGET_MAP { 56, 48, 40, 32, 24, 16, 8, 0 } 37 #define OLED_TARGET_MAP { 24, 16, 8, 0 }
38 // If OLED_BLOCK_TYPE is uint16_t, these tables would look like:
39 // #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 }
40 // #define OLED_TARGET_MAP { 56, 48, 40, 32, 24, 16, 8, 0 }
38 // If OLED_BLOCK_TYPE is uint8_t, these tables would look like: 41 // If OLED_BLOCK_TYPE is uint8_t, these tables would look like:
39 // #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120 } 42 // #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120 }
40 // #define OLED_TARGET_MAP { 56, 120, 48, 112, 40, 104, 32, 96, 24, 88, 16, 80, 8, 72, 0, 64 } 43 // #define OLED_TARGET_MAP { 56, 120, 48, 112, 40, 104, 32, 96, 24, 88, 16, 80, 8, 72, 0, 64 }
@@ -43,14 +46,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
43 #define OLED_DISPLAY_WIDTH 128 46 #define OLED_DISPLAY_WIDTH 128
44 #define OLED_DISPLAY_HEIGHT 32 47 #define OLED_DISPLAY_HEIGHT 32
45 #define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 512 (compile time mathed) 48 #define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 512 (compile time mathed)
46 #define OLED_BLOCK_TYPE uint8_t // Type to use for segmenting the oled display for smart rendering, use unsigned types only 49 #define OLED_BLOCK_TYPE uint16_t // Type to use for segmenting the oled display for smart rendering, use unsigned types only
47 #define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 8 (compile time mathed) 50 #define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 16 (compile time mathed)
48 #define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 128 (compile time mathed) 51 #define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 32 (compile time mathed)
49 52
50 // For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays 53 // For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays
51 // The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode 54 // The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode
52 #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 } 55 #define OLED_SOURCE_MAP { 0, 8, 16, 24 }
53 #define OLED_TARGET_MAP { 48, 32, 16, 0, 56, 40, 24, 8 } 56 #define OLED_TARGET_MAP { 24, 16, 8, 0 }
57 // If OLED_BLOCK_TYPE is uint8_t, these tables would look like:
58 // #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 }
59 // #define OLED_TARGET_MAP { 48, 32, 16, 0, 56, 40, 24, 8 }
54#endif // defined(OLED_DISPLAY_CUSTOM) 60#endif // defined(OLED_DISPLAY_CUSTOM)
55 61
56// Address to use for tthe i2d oled communication 62// Address to use for tthe i2d oled communication
@@ -79,19 +85,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
79 #define OLED_FONT_HEIGHT 8 85 #define OLED_FONT_HEIGHT 8
80#endif 86#endif
81 87
82#define OLED_ROTATION_0 0x00 88// OLED Rotation enum values are flags
83#define OLED_ROTATION_90 0x01 89typedef enum {
84#define OLED_ROTATION_180 0x02 90 OLED_ROTATION_0 = 0,
85#define OLED_ROTATION_270 0x03 91 OLED_ROTATION_90 = 1,
92 OLED_ROTATION_180 = 2,
93 OLED_ROTATION_270 = 3, // OLED_ROTATION_90 | OLED_ROTATION_180
94} oled_rotation_t;
86 95
87// Initialize the oled display, rotating the rendered output based on the define passed in. 96// Initialize the oled display, rotating the rendered output based on the define passed in.
88// Returns true if the OLED was initialized successfully 97// Returns true if the OLED was initialized successfully
89bool oled_init(uint8_t rotation); 98bool oled_init(oled_rotation_t rotation);
90 99
91// Called at the start of oled_init, weak function overridable by the user 100// Called at the start of oled_init, weak function overridable by the user
92// rotation - the value passed into oled_init 101// rotation - the value passed into oled_init
93// Return new uint8_t if you want to override default rotation 102// Return new oled_rotation_t if you want to override default rotation
94uint8_t oled_init_user(uint8_t rotation); 103oled_rotation_t oled_init_user(oled_rotation_t rotation);
95 104
96// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering 105// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
97void oled_clear(void); 106void oled_clear(void);
diff --git a/keyboards/sol/keymaps/brianweyer/keymap.c b/keyboards/sol/keymaps/brianweyer/keymap.c
index 9fd6ad615..87d603d81 100755
--- a/keyboards/sol/keymaps/brianweyer/keymap.c
+++ b/keyboards/sol/keymaps/brianweyer/keymap.c
@@ -181,7 +181,7 @@ void matrix_init_user(void) {
181// OLED Driver Logic 181// OLED Driver Logic
182#ifdef OLED_DRIVER_ENABLE 182#ifdef OLED_DRIVER_ENABLE
183 183
184uint8_t oled_init_user(uint8_t rotation) { 184oled_rotation_t oled_init_user(oled_rotation_t rotation) {
185 if (!has_usb()) 185 if (!has_usb())
186 return OLED_ROTATION_180; // flip 180 for offhand 186 return OLED_ROTATION_180; // flip 180 for offhand
187 return rotation; 187 return rotation;
diff --git a/keyboards/sol/keymaps/danielhklein/keymap.c b/keyboards/sol/keymaps/danielhklein/keymap.c
index cfc295323..9bcc5761a 100644
--- a/keyboards/sol/keymaps/danielhklein/keymap.c
+++ b/keyboards/sol/keymaps/danielhklein/keymap.c
@@ -246,7 +246,7 @@ void matrix_init_user(void) {
246// OLED Driver Logic 246// OLED Driver Logic
247#ifdef OLED_DRIVER_ENABLE 247#ifdef OLED_DRIVER_ENABLE
248 248
249uint8_t oled_init_user(uint8_t rotation) { 249oled_rotation_t oled_init_user(oled_rotation_t rotation) {
250 if (!has_usb()) 250 if (!has_usb())
251 return OLED_ROTATION_180; // flip 180 for offhand 251 return OLED_ROTATION_180; // flip 180 for offhand
252 return rotation; 252 return rotation;
diff --git a/keyboards/sol/keymaps/default/keymap.c b/keyboards/sol/keymaps/default/keymap.c
index 1742fc597..a40bc40b7 100644
--- a/keyboards/sol/keymaps/default/keymap.c
+++ b/keyboards/sol/keymaps/default/keymap.c
@@ -254,7 +254,7 @@ void matrix_init_user(void) {
254// OLED Driver Logic 254// OLED Driver Logic
255#ifdef OLED_DRIVER_ENABLE 255#ifdef OLED_DRIVER_ENABLE
256 256
257uint8_t oled_init_user(uint8_t rotation) { 257oled_rotation_t oled_init_user(oled_rotation_t rotation) {
258 if (!has_usb()) 258 if (!has_usb())
259 return OLED_ROTATION_180; // flip 180 for offhand 259 return OLED_ROTATION_180; // flip 180 for offhand
260 return rotation; 260 return rotation;
diff --git a/keyboards/zen/rev2/config.h b/keyboards/zen/rev2/config.h
index dc37472f6..5fa262760 100644
--- a/keyboards/zen/rev2/config.h
+++ b/keyboards/zen/rev2/config.h
@@ -66,19 +66,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
66/* ws2812 RGB LED */ 66/* ws2812 RGB LED */
67#define RGBLED_NUM 34 // Number of LEDs 67#define RGBLED_NUM 34 // Number of LEDs
68 68
69// If using 90 Degree rotation, increase block cout
70#ifdef OLED_ROTATE90
71 #define OLED_DISPLAY_CUSTOM
72 #define OLED_DISPLAY_WIDTH 128
73 #define OLED_DISPLAY_HEIGHT 32
74 #define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 512 (compile time mathed)
75 #define OLED_BLOCK_TYPE uint16_t // Type to use for segmenting the oled display for smart rendering, use unsigned types only
76 #define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 8 (compile time mathed)
77 #define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 32 (compile time mathed)
78 #define OLED_SOURCE_MAP { 0, 8, 16, 24 }
79 #define OLED_TARGET_MAP { 24, 16, 8, 0 }
80#endif
81
82/* 69/*
83 * Feature disable options 70 * Feature disable options
84 * These options are also useful to firmware size reduction. 71 * These options are also useful to firmware size reduction.
diff --git a/keyboards/zen/rev2/rev2.c b/keyboards/zen/rev2/rev2.c
index 4104460db..7bd8efbdd 100644
--- a/keyboards/zen/rev2/rev2.c
+++ b/keyboards/zen/rev2/rev2.c
@@ -47,11 +47,11 @@ void render_status(void) {
47 oled_write_P(led_usb_state & (1<<USB_LED_SCROLL_LOCK) ? PSTR("SCRLK") : PSTR(" "), false); // Line 16 47 oled_write_P(led_usb_state & (1<<USB_LED_SCROLL_LOCK) ? PSTR("SCRLK") : PSTR(" "), false); // Line 16
48} 48}
49 49
50#ifdef OLED_ROTATE90 50oled_rotation_t oled_init_user(oled_rotation_t rotation) {
51bool oled_init_user(bool flip180) { 51 if (is_keyboard_master())
52 return true; 52 return OLED_ROTATION_90; // flips the display 90 degrees if mainhand
53 return rotation;
53} 54}
54#endif
55 55
56__attribute__((weak)) 56__attribute__((weak))
57void oled_task_user(void) { 57void oled_task_user(void) {
diff --git a/keyboards/zen/rev2/rules.mk b/keyboards/zen/rev2/rules.mk
index d1fe41052..e9d19a69a 100644
--- a/keyboards/zen/rev2/rules.mk
+++ b/keyboards/zen/rev2/rules.mk
@@ -1,14 +1,9 @@
1ENCODER_ENABLE = yes 1ENCODER_ENABLE = yes
2 2
3OLED_DRIVER_ENABLE = no 3OLED_DRIVER_ENABLE = no
4OLED_ROTATE90 = yes
5 4
6# Setup so that OLED and 90 degree rotation can be turned on/off easily 5# Setup so that OLED can be turned on/off easily
7# with "OLED_DRIVER_ENABLE = yes" or "OLED_ROTATE90 = no" in user's rules.mk file
8ifeq ($(strip $(OLED_DRIVER_ENABLE)), yes) 6ifeq ($(strip $(OLED_DRIVER_ENABLE)), yes)
9 # Custom local font file 7 # Custom local font file
10 OPT_DEFS += -DOLED_FONT_H=\"common/glcdfont.c\" 8 OPT_DEFS += -DOLED_FONT_H=\"common/glcdfont.c\"
11 ifeq ($(strip $(OLED_DRIVER_ENABLE)), yes)
12 OPT_DEFS += -DOLED_ROTATE90
13 endif
14endif 9endif