aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/board_IS31FL3731C.h113
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/driver.mk2
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/gdisp_IS31FL3731C.c333
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/gdisp_lld_config.h36
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/emulator_lcd/driver.mk2
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/emulator_lcd/emulator_lcd.c10
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/emulator_led/driver.mk2
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/emulator_led/emulator_led.c10
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/board_ST7565.h127
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/driver.mk2
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/gdisp_lld_ST7565.c292
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/gdisp_lld_config.h26
-rw-r--r--keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/st7565.h37
13 files changed, 992 insertions, 0 deletions
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/board_IS31FL3731C.h b/keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/board_IS31FL3731C.h
new file mode 100644
index 000000000..2ea73f1fb
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/board_IS31FL3731C.h
@@ -0,0 +1,113 @@
1/*
2Copyright 2016 Fred Sundvik <fsundvik@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#ifndef _GDISP_LLD_BOARD_H
19#define _GDISP_LLD_BOARD_H
20
21static const I2CConfig i2ccfg = {
22 400000 // clock speed (Hz); 400kHz max for IS31
23};
24
25#define GDISP_SCREEN_WIDTH 7
26#define GDISP_SCREEN_HEIGHT 7
27
28static const uint8_t led_mask[] = {
29 0xFF, 0x00, /* C1-1 -> C1-16 */
30 0xFF, 0x00, /* C2-1 -> C2-16 */
31 0xFF, 0x00, /* C3-1 -> C3-16 */
32 0xFF, 0x00, /* C4-1 -> C4-16 */
33 0x3F, 0x00, /* C5-1 -> C5-16 */
34 0x00, 0x00, /* C6-1 -> C6-16 */
35 0x00, 0x00, /* C7-1 -> C7-16 */
36 0x00, 0x00, /* C8-1 -> C8-16 */
37 0x00, 0x00, /* C9-1 -> C9-16 */
38};
39
40// The address of the LED
41#define LA(c, r) (c + r * 16 )
42// Need to be an address that is not mapped, but inside the range of the controller matrix
43#define NA LA(8, 8)
44
45// The numbers in the comments are the led numbers DXX on the PCB
46// The mapping is taken from the schematic of left hand side
47static const uint8_t led_mapping[GDISP_SCREEN_HEIGHT][GDISP_SCREEN_WIDTH] = {
48// 45 44 43 42 41 40 39
49 { LA(1, 1), LA(1, 0), LA(0, 4), LA(0, 3), LA(0, 2), LA(0, 1), LA(0, 0)},
50// 52 51 50 49 48 47 46
51 { LA(2, 3), LA(2, 2), LA(2, 1), LA(2, 0), LA(1, 4), LA(1, 3), LA(1, 2) },
52// 58 57 56 55 54 53 N/A
53 { LA(3, 4), LA(3, 3), LA(3, 2), LA(3, 1), LA(3, 0), LA(2, 4), NA },
54// 67 66 65 64 63 62 61
55 { LA(5, 3), LA(5, 2), LA(5, 1), LA(5, 0), LA(4, 4), LA(4, 3), LA(4, 2) },
56// 76 75 74 73 72 60 59
57 { LA(7, 3), LA(7, 2), LA(7, 1), LA(7, 0), LA(6, 3), LA(4, 1), LA(4, 0) },
58// N/A N/A N/A N/A N/A N/A 68
59 { NA, NA, NA, NA, NA, NA, LA(5, 4) },
60// N/A N/A N/A N/A 71 70 69
61 { NA, NA, NA, NA, LA(6, 2), LA(6, 1), LA(6, 0) },
62};
63
64
65#define IS31_ADDR_DEFAULT 0x74 // AD connected to GND
66#define IS31_TIMEOUT 5000
67
68static GFXINLINE void init_board(GDisplay *g) {
69 (void) g;
70 /* I2C pins */
71 palSetPadMode(GPIOB, 0, PAL_MODE_ALTERNATIVE_2); // PTB0/I2C0/SCL
72 palSetPadMode(GPIOB, 1, PAL_MODE_ALTERNATIVE_2); // PTB1/I2C0/SDA
73 palSetPadMode(GPIOB, 16, PAL_MODE_OUTPUT_PUSHPULL);
74 palClearPad(GPIOB, 16);
75 /* start I2C */
76 i2cStart(&I2CD1, &i2ccfg);
77 // try high drive (from kiibohd)
78 I2CD1.i2c->C2 |= I2Cx_C2_HDRS;
79 // try glitch fixing (from kiibohd)
80 I2CD1.i2c->FLT = 4;
81}
82
83static GFXINLINE void post_init_board(GDisplay *g) {
84 (void) g;
85}
86
87static GFXINLINE const uint8_t* get_led_mask(GDisplay* g) {
88 (void) g;
89 return led_mask;
90}
91
92static GFXINLINE uint8_t get_led_address(GDisplay* g, uint16_t x, uint16_t y)
93{
94 (void) g;
95 return led_mapping[y][x];
96}
97
98static GFXINLINE void set_hardware_shutdown(GDisplay* g, bool shutdown) {
99 (void) g;
100 if(!shutdown) {
101 palSetPad(GPIOB, 16);
102 }
103 else {
104 palClearPad(GPIOB, 16);
105 }
106}
107
108static GFXINLINE void write_data(GDisplay *g, uint8_t* data, uint16_t length) {
109 (void) g;
110 i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, data, length, 0, 0, US2ST(IS31_TIMEOUT));
111}
112
113#endif /* _GDISP_LLD_BOARD_H */
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/driver.mk b/keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/driver.mk
new file mode 100644
index 000000000..f32d0d868
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/driver.mk
@@ -0,0 +1,2 @@
1GFXINC += drivers/gdisp/IS31FL3731C
2GFXSRC += drivers/gdisp/IS31FL3731C/gdisp_IS31FL3731C.c
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/gdisp_IS31FL3731C.c b/keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/gdisp_IS31FL3731C.c
new file mode 100644
index 000000000..1d21f0c49
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/gdisp_IS31FL3731C.c
@@ -0,0 +1,333 @@
1/*
2Copyright 2016 Fred Sundvik <fsundvik@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "gfx.h"
19
20#if GFX_USE_GDISP
21
22#define GDISP_DRIVER_VMT GDISPVMT_IS31FL3731C_ERGODOX
23#include "drivers/gdisp/IS31FL3731C/gdisp_lld_config.h"
24#include "src/gdisp/gdisp_driver.h"
25
26#include "board_IS31FL3731C.h"
27
28/*===========================================================================*/
29/* Driver local definitions. */
30/*===========================================================================*/
31
32#ifndef GDISP_SCREEN_HEIGHT
33 #define GDISP_SCREEN_HEIGHT 9
34#endif
35#ifndef GDISP_SCREEN_WIDTH
36 #define GDISP_SCREEN_WIDTH 16
37#endif
38#ifndef GDISP_INITIAL_CONTRAST
39 #define GDISP_INITIAL_CONTRAST 0
40#endif
41#ifndef GDISP_INITIAL_BACKLIGHT
42 #define GDISP_INITIAL_BACKLIGHT 100
43#endif
44
45#define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0)
46
47#define IS31_ADDR_DEFAULT 0x74
48
49#define IS31_REG_CONFIG 0x00
50// bits in reg
51#define IS31_REG_CONFIG_PICTUREMODE 0x00
52#define IS31_REG_CONFIG_AUTOPLAYMODE 0x08
53#define IS31_REG_CONFIG_AUDIOPLAYMODE 0x18
54// D2:D0 bits are starting frame for autoplay mode
55
56#define IS31_REG_PICTDISP 0x01 // D2:D0 frame select for picture mode
57
58#define IS31_REG_AUTOPLAYCTRL1 0x02
59// D6:D4 number of loops (000=infty)
60// D2:D0 number of frames to be used
61
62#define IS31_REG_AUTOPLAYCTRL2 0x03 // D5:D0 delay time (*11ms)
63
64#define IS31_REG_DISPLAYOPT 0x05
65#define IS31_REG_DISPLAYOPT_INTENSITY_SAME 0x20 // same intensity for all frames
66#define IS31_REG_DISPLAYOPT_BLINK_ENABLE 0x8
67// D2:D0 bits blink period time (*0.27s)
68
69#define IS31_REG_AUDIOSYNC 0x06
70#define IS31_REG_AUDIOSYNC_ENABLE 0x1
71
72#define IS31_REG_FRAMESTATE 0x07
73
74#define IS31_REG_BREATHCTRL1 0x08
75// D6:D4 fade out time (26ms*2^i)
76// D2:D0 fade in time (26ms*2^i)
77
78#define IS31_REG_BREATHCTRL2 0x09
79#define IS31_REG_BREATHCTRL2_ENABLE 0x10
80// D2:D0 extinguish time (3.5ms*2^i)
81
82#define IS31_REG_SHUTDOWN 0x0A
83#define IS31_REG_SHUTDOWN_OFF 0x0
84#define IS31_REG_SHUTDOWN_ON 0x1
85
86#define IS31_REG_AGCCTRL 0x0B
87#define IS31_REG_ADCRATE 0x0C
88
89#define IS31_COMMANDREGISTER 0xFD
90#define IS31_FUNCTIONREG 0x0B // helpfully called 'page nine'
91#define IS31_FUNCTIONREG_SIZE 0xD
92
93#define IS31_FRAME_SIZE 0xB4
94
95#define IS31_PWM_REG 0x24
96#define IS31_PWM_SIZE 0x90
97
98#define IS31_LED_MASK_SIZE 0x12
99#define IS31_SCREEN_WIDTH 16
100
101#define IS31
102
103//Generated by http://jared.geek.nz/2013/feb/linear-led-pwm
104const unsigned char cie[256] = {
105 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
106 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
107 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
108 3, 4, 4, 4, 4, 4, 4, 5, 5, 5,
109 5, 5, 6, 6, 6, 6, 6, 7, 7, 7,
110 7, 8, 8, 8, 8, 9, 9, 9, 10, 10,
111 10, 10, 11, 11, 11, 12, 12, 12, 13, 13,
112 13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
113 17, 18, 18, 19, 19, 20, 20, 21, 21, 22,
114 22, 23, 23, 24, 24, 25, 25, 26, 26, 27,
115 28, 28, 29, 29, 30, 31, 31, 32, 32, 33,
116 34, 34, 35, 36, 37, 37, 38, 39, 39, 40,
117 41, 42, 43, 43, 44, 45, 46, 47, 47, 48,
118 49, 50, 51, 52, 53, 54, 54, 55, 56, 57,
119 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
120 68, 70, 71, 72, 73, 74, 75, 76, 77, 79,
121 80, 81, 82, 83, 85, 86, 87, 88, 90, 91,
122 92, 94, 95, 96, 98, 99, 100, 102, 103, 105,
123 106, 108, 109, 110, 112, 113, 115, 116, 118, 120,
124 121, 123, 124, 126, 128, 129, 131, 132, 134, 136,
125 138, 139, 141, 143, 145, 146, 148, 150, 152, 154,
126 155, 157, 159, 161, 163, 165, 167, 169, 171, 173,
127 175, 177, 179, 181, 183, 185, 187, 189, 191, 193,
128 196, 198, 200, 202, 204, 207, 209, 211, 214, 216,
129 218, 220, 223, 225, 228, 230, 232, 235, 237, 240,
130 242, 245, 247, 250, 252, 255,
131};
132
133
134/*===========================================================================*/
135/* Driver local functions. */
136/*===========================================================================*/
137
138typedef struct{
139 uint8_t write_buffer_offset;
140 uint8_t write_buffer[IS31_FRAME_SIZE];
141 uint8_t frame_buffer[GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH];
142 uint8_t page;
143}__attribute__((__packed__)) PrivData;
144
145// Some common routines and macros
146#define PRIV(g) ((PrivData*)g->priv)
147
148/*===========================================================================*/
149/* Driver exported functions. */
150/*===========================================================================*/
151
152static GFXINLINE void write_page(GDisplay* g, uint8_t page) {
153 uint8_t tx[2] __attribute__((aligned(2)));
154 tx[0] = IS31_COMMANDREGISTER;
155 tx[1] = page;
156 write_data(g, tx, 2);
157}
158
159static GFXINLINE void write_register(GDisplay* g, uint8_t page, uint8_t reg, uint8_t data) {
160 uint8_t tx[2] __attribute__((aligned(2)));
161 tx[0] = reg;
162 tx[1] = data;
163 write_page(g, page);
164 write_data(g, tx, 2);
165}
166
167static GFXINLINE void write_ram(GDisplay *g, uint8_t page, uint16_t offset, uint16_t length) {
168 PRIV(g)->write_buffer_offset = offset;
169 write_page(g, page);
170 write_data(g, (uint8_t*)PRIV(g), length + 1);
171}
172
173LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
174 // The private area is the display surface.
175 g->priv = gfxAlloc(sizeof(PrivData));
176 __builtin_memset(PRIV(g), 0, sizeof(PrivData));
177 PRIV(g)->page = 0;
178
179 // Initialise the board interface
180 init_board(g);
181 gfxSleepMilliseconds(10);
182
183 // zero function page, all registers (assuming full_page is all zeroes)
184 write_ram(g, IS31_FUNCTIONREG, 0, IS31_FUNCTIONREG_SIZE);
185 set_hardware_shutdown(g, false);
186 gfxSleepMilliseconds(10);
187 // software shutdown
188 write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
189 gfxSleepMilliseconds(10);
190 // zero function page, all registers
191 write_ram(g, IS31_FUNCTIONREG, 0, IS31_FUNCTIONREG_SIZE);
192 gfxSleepMilliseconds(10);
193
194
195 // zero all LED registers on all 8 pages, and enable the mask
196 __builtin_memcpy(PRIV(g)->write_buffer, get_led_mask(g), IS31_LED_MASK_SIZE);
197 for(uint8_t i=0; i<8; i++) {
198 write_ram(g, i, 0, IS31_FRAME_SIZE);
199 gfxSleepMilliseconds(1);
200 }
201
202 // software shutdown disable (i.e. turn stuff on)
203 write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON);
204 gfxSleepMilliseconds(10);
205
206 // Finish Init
207 post_init_board(g);
208
209 /* Initialise the GDISP structure */
210 g->g.Width = GDISP_SCREEN_WIDTH;
211 g->g.Height = GDISP_SCREEN_HEIGHT;
212 g->g.Orientation = GDISP_ROTATE_0;
213 g->g.Powermode = powerOn;
214 g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
215 g->g.Contrast = GDISP_INITIAL_CONTRAST;
216 return TRUE;
217}
218
219#if GDISP_HARDWARE_FLUSH
220 LLDSPEC void gdisp_lld_flush(GDisplay *g) {
221 // Don't flush if we don't need it.
222 if (!(g->flags & GDISP_FLG_NEEDFLUSH))
223 return;
224
225 PRIV(g)->page++;
226 PRIV(g)->page %= 2;
227 // TODO: some smarter algorithm for this
228 // We should run only one physical page at a time
229 // This way we don't need to send so much data, and
230 // we could use slightly less memory
231 uint8_t* src = PRIV(g)->frame_buffer;
232 for (int y=0;y<GDISP_SCREEN_HEIGHT;y++) {
233 for (int x=0;x<GDISP_SCREEN_WIDTH;x++) {
234 PRIV(g)->write_buffer[get_led_address(g, x, y)]=cie[*src];
235 ++src;
236 }
237 }
238 write_ram(g, PRIV(g)->page, IS31_PWM_REG, IS31_PWM_SIZE);
239 gfxSleepMilliseconds(1);
240 write_register(g, IS31_FUNCTIONREG, IS31_REG_PICTDISP, PRIV(g)->page);
241
242 g->flags &= ~GDISP_FLG_NEEDFLUSH;
243 }
244#endif
245
246#if GDISP_HARDWARE_DRAWPIXEL
247 LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
248 coord_t x, y;
249
250 switch(g->g.Orientation) {
251 default:
252 case GDISP_ROTATE_0:
253 x = g->p.x;
254 y = g->p.y;
255 break;
256 case GDISP_ROTATE_180:
257 x = GDISP_SCREEN_WIDTH-1 - g->p.x;
258 y = g->p.y;
259 break;
260 }
261 PRIV(g)->frame_buffer[y * GDISP_SCREEN_WIDTH + x] = gdispColor2Native(g->p.color);
262 g->flags |= GDISP_FLG_NEEDFLUSH;
263 }
264#endif
265
266#if GDISP_HARDWARE_PIXELREAD
267 LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
268 coord_t x, y;
269
270 switch(g->g.Orientation) {
271 default:
272 case GDISP_ROTATE_0:
273 x = g->p.x;
274 y = g->p.y;
275 break;
276 case GDISP_ROTATE_180:
277 x = GDISP_SCREEN_WIDTH-1 - g->p.x;
278 y = g->p.y;
279 break;
280 }
281 return gdispNative2Color(PRIV(g)->frame_buffer[y * GDISP_SCREEN_WIDTH + x]);
282 }
283#endif
284
285#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
286 LLDSPEC void gdisp_lld_control(GDisplay *g) {
287 switch(g->p.x) {
288 case GDISP_CONTROL_POWER:
289 if (g->g.Powermode == (powermode_t)g->p.ptr)
290 return;
291 switch((powermode_t)g->p.ptr) {
292 case powerOff:
293 case powerSleep:
294 case powerDeepSleep:
295 write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
296 break;
297 case powerOn:
298 write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON);
299 break;
300 default:
301 return;
302 }
303 g->g.Powermode = (powermode_t)g->p.ptr;
304 return;
305
306 case GDISP_CONTROL_ORIENTATION:
307 if (g->g.Orientation == (orientation_t)g->p.ptr)
308 return;
309 switch((orientation_t)g->p.ptr) {
310 /* Rotation is handled by the drawing routines */
311 case GDISP_ROTATE_0:
312 case GDISP_ROTATE_180:
313 g->g.Height = GDISP_SCREEN_HEIGHT;
314 g->g.Width = GDISP_SCREEN_WIDTH;
315 break;
316 case GDISP_ROTATE_90:
317 case GDISP_ROTATE_270:
318 g->g.Height = GDISP_SCREEN_WIDTH;
319 g->g.Width = GDISP_SCREEN_HEIGHT;
320 break;
321 default:
322 return;
323 }
324 g->g.Orientation = (orientation_t)g->p.ptr;
325 return;
326
327 case GDISP_CONTROL_CONTRAST:
328 return;
329 }
330 }
331#endif // GDISP_NEED_CONTROL
332
333#endif // GFX_USE_GDISP
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/gdisp_lld_config.h b/keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/gdisp_lld_config.h
new file mode 100644
index 000000000..bb28ad775
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/IS31FL3731C/gdisp_lld_config.h
@@ -0,0 +1,36 @@
1/*
2Copyright 2016 Fred Sundvik <fsundvik@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#ifndef _GDISP_LLD_CONFIG_H
19#define _GDISP_LLD_CONFIG_H
20
21#if GFX_USE_GDISP
22
23/*===========================================================================*/
24/* Driver hardware support. */
25/*===========================================================================*/
26
27#define GDISP_HARDWARE_FLUSH TRUE // This controller requires flushing
28#define GDISP_HARDWARE_DRAWPIXEL TRUE
29#define GDISP_HARDWARE_PIXELREAD TRUE
30#define GDISP_HARDWARE_CONTROL TRUE
31
32#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_GRAY256
33
34#endif /* GFX_USE_GDISP */
35
36#endif /* _GDISP_LLD_CONFIG_H */
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/emulator_lcd/driver.mk b/keyboards/infinity_ergodox/drivers/gdisp/emulator_lcd/driver.mk
new file mode 100644
index 000000000..16c3f80f5
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/emulator_lcd/driver.mk
@@ -0,0 +1,2 @@
1GFXINC += drivers/gdisp/emulator_lcd
2GFXSRC += drivers/gdisp/emulator_lcd/emulator_lcd.c
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/emulator_lcd/emulator_lcd.c b/keyboards/infinity_ergodox/drivers/gdisp/emulator_lcd/emulator_lcd.c
new file mode 100644
index 000000000..babfe2b36
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/emulator_lcd/emulator_lcd.c
@@ -0,0 +1,10 @@
1#define GDISP_DRIVER_VMT GDISPVMT_EMULATOR_LCD_ERGODOX
2#define GDISP_HARDWARE_DRAWPIXEL TRUE
3#define GDISP_HARDWARE_PIXELREAD TRUE
4#define GDISP_HARDWARE_CONTROL TRUE
5#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO
6#define GDISP_SCREEN_WIDTH 128
7#define GDISP_SCREEN_HEIGHT 32
8#define ROTATE_180_IS_FLIP
9
10#include "emulator/emulator_driver_impl.h"
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/emulator_led/driver.mk b/keyboards/infinity_ergodox/drivers/gdisp/emulator_led/driver.mk
new file mode 100644
index 000000000..255434432
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/emulator_led/driver.mk
@@ -0,0 +1,2 @@
1GFXINC += drivers/gdisp/emulator_led
2GFXSRC += drivers/gdisp/emulator_led/emulator_led.c
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/emulator_led/emulator_led.c b/keyboards/infinity_ergodox/drivers/gdisp/emulator_led/emulator_led.c
new file mode 100644
index 000000000..b0ebcdc47
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/emulator_led/emulator_led.c
@@ -0,0 +1,10 @@
1#define GDISP_DRIVER_VMT GDISPVMT_EMULATOR_LED_ERGODOX
2#define GDISP_HARDWARE_DRAWPIXEL TRUE
3#define GDISP_HARDWARE_PIXELREAD TRUE
4#define GDISP_HARDWARE_CONTROL TRUE
5#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO
6#define GDISP_SCREEN_WIDTH 7
7#define GDISP_SCREEN_HEIGHT 7
8#define ROTATE_180_IS_FLIP
9
10#include "emulator/emulator_driver_impl.h"
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/board_ST7565.h b/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/board_ST7565.h
new file mode 100644
index 000000000..290571ce5
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/board_ST7565.h
@@ -0,0 +1,127 @@
1/*
2 * This file is subject to the terms of the GFX License. If a copy of
3 * the license was not distributed with this file, you can obtain one at:
4 *
5 * http://ugfx.org/license.html
6 */
7
8#ifndef _GDISP_LLD_BOARD_H
9#define _GDISP_LLD_BOARD_H
10
11#include "print.h"
12
13#define ST7565_LCD_BIAS ST7565_LCD_BIAS_9 // actually 6
14#define ST7565_ADC ST7565_ADC_NORMAL
15#define ST7565_COM_SCAN ST7565_COM_SCAN_DEC
16#define ST7565_PAGE_ORDER 0,1,2,3
17/*
18 * Custom page order for several LCD boards, e.g. HEM12864-99
19 * #define ST7565_PAGE_ORDER 4,5,6,7,0,1,2,3
20 */
21
22#define ST7565_GPIOPORT GPIOC
23#define ST7565_PORT PORTC
24#define ST7565_A0_PIN 7
25#define ST7565_RST_PIN 8
26#define ST7565_MOSI_PIN 6
27#define ST7565_SLCK_PIN 5
28#define ST7565_SS_PIN 4
29
30#define palSetPadModeRaw(portname, bits) \
31 ST7565_PORT->PCR[ST7565_##portname##_PIN] = bits
32
33#define palSetPadModeNamed(portname, portmode) \
34 palSetPadMode(ST7565_GPIOPORT, ST7565_##portname##_PIN, portmode)
35
36#define ST7565_SPI_MODE PORTx_PCRn_DSE | PORTx_PCRn_MUX(2)
37// DSPI Clock and Transfer Attributes
38// Frame Size: 8 bits
39// MSB First
40// CLK Low by default
41static const SPIConfig spi1config = {
42 NULL,
43 /* HW dependent part.*/
44 ST7565_GPIOPORT,
45 ST7565_SS_PIN,
46 SPIx_CTARn_FMSZ(7)
47 | SPIx_CTARn_ASC(7)
48 | SPIx_CTARn_DT(7)
49 | SPIx_CTARn_CSSCK(7)
50 | SPIx_CTARn_PBR(0)
51 | SPIx_CTARn_BR(7)
52 //SPI_CR1_BR_0
53};
54
55static bool_t st7565_is_data_mode = 1;
56
57static GFXINLINE void init_board(GDisplay *g) {
58 (void) g;
59 palSetPadModeNamed(A0, PAL_MODE_OUTPUT_PUSHPULL);
60 palSetPad(ST7565_GPIOPORT, ST7565_A0_PIN);
61 st7565_is_data_mode = 1;
62 palSetPadModeNamed(RST, PAL_MODE_OUTPUT_PUSHPULL);
63 palSetPad(ST7565_GPIOPORT, ST7565_RST_PIN);
64 palSetPadModeRaw(MOSI, ST7565_SPI_MODE);
65 palSetPadModeRaw(SLCK, ST7565_SPI_MODE);
66 palSetPadModeRaw(SS, ST7565_SPI_MODE);
67
68 spiInit();
69 spiStart(&SPID1, &spi1config);
70 spiSelect(&SPID1);
71}
72
73static GFXINLINE void post_init_board(GDisplay *g) {
74 (void) g;
75}
76
77static GFXINLINE void setpin_reset(GDisplay *g, bool_t state) {
78 (void) g;
79 if (state) {
80 palClearPad(ST7565_GPIOPORT, ST7565_RST_PIN);
81 }
82 else {
83 palSetPad(ST7565_GPIOPORT, ST7565_RST_PIN);
84 }
85}
86
87static GFXINLINE void acquire_bus(GDisplay *g) {
88 (void) g;
89 // Only the LCD is using the SPI bus, so no need to acquire
90 // spiAcquireBus(&SPID1);
91}
92
93static GFXINLINE void release_bus(GDisplay *g) {
94 (void) g;
95 // Only the LCD is using the SPI bus, so no need to release
96 //spiReleaseBus(&SPID1);
97}
98
99static GFXINLINE void write_cmd(GDisplay *g, uint8_t cmd) {
100 (void) g;
101 if (st7565_is_data_mode) {
102 // The sleeps need to be at lest 10 vs 25 ns respectively
103 // So let's sleep two ticks, one tick might not be enough
104 // if we are at the end of the tick
105 chThdSleep(2);
106 palClearPad(ST7565_GPIOPORT, ST7565_A0_PIN);
107 chThdSleep(2);
108 st7565_is_data_mode = 0;
109 }
110 spiSend(&SPID1, 1, &cmd);
111}
112
113static GFXINLINE void write_data(GDisplay *g, uint8_t* data, uint16_t length) {
114 (void) g;
115 if (!st7565_is_data_mode) {
116 // The sleeps need to be at lest 10 vs 25 ns respectively
117 // So let's sleep two ticks, one tick might not be enough
118 // if we are at the end of the tick
119 chThdSleep(2);
120 palSetPad(ST7565_GPIOPORT, ST7565_A0_PIN);
121 chThdSleep(2);
122 st7565_is_data_mode = 1;
123 }
124 spiSend(&SPID1, length, data);
125}
126
127#endif /* _GDISP_LLD_BOARD_H */
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/driver.mk b/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/driver.mk
new file mode 100644
index 000000000..889a1a031
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/driver.mk
@@ -0,0 +1,2 @@
1GFXINC += drivers/gdisp/st7565ergodox
2GFXSRC += drivers/gdisp/st7565ergodox/gdisp_lld_ST7565.c
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/gdisp_lld_ST7565.c b/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/gdisp_lld_ST7565.c
new file mode 100644
index 000000000..c33aea81a
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/gdisp_lld_ST7565.c
@@ -0,0 +1,292 @@
1/*
2 * This file is subject to the terms of the GFX License. If a copy of
3 * the license was not distributed with this file, you can obtain one at:
4 *
5 * http://ugfx.org/license.html
6 */
7
8#include "gfx.h"
9
10#if GFX_USE_GDISP
11
12#define GDISP_DRIVER_VMT GDISPVMT_ST7565_ERGODOX
13#include "drivers/gdisp/st7565ergodox/gdisp_lld_config.h"
14#include "src/gdisp/gdisp_driver.h"
15
16#include "board_ST7565.h"
17
18/*===========================================================================*/
19/* Driver local definitions. */
20/*===========================================================================*/
21
22#ifndef GDISP_SCREEN_HEIGHT
23 #define GDISP_SCREEN_HEIGHT 32
24#endif
25#ifndef GDISP_SCREEN_WIDTH
26 #define GDISP_SCREEN_WIDTH 128
27#endif
28#ifndef GDISP_INITIAL_CONTRAST
29 #define GDISP_INITIAL_CONTRAST 0
30#endif
31#ifndef GDISP_INITIAL_BACKLIGHT
32 #define GDISP_INITIAL_BACKLIGHT 100
33#endif
34
35#define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0)
36
37#include "drivers/gdisp/st7565ergodox/st7565.h"
38
39/*===========================================================================*/
40/* Driver config defaults for backward compatibility. */
41/*===========================================================================*/
42#ifndef ST7565_LCD_BIAS
43 #define ST7565_LCD_BIAS ST7565_LCD_BIAS_7
44#endif
45#ifndef ST7565_ADC
46 #define ST7565_ADC ST7565_ADC_NORMAL
47#endif
48#ifndef ST7565_COM_SCAN
49 #define ST7565_COM_SCAN ST7565_COM_SCAN_INC
50#endif
51#ifndef ST7565_PAGE_ORDER
52 #define ST7565_PAGE_ORDER 0,1,2,3
53#endif
54
55/*===========================================================================*/
56/* Driver local functions. */
57/*===========================================================================*/
58
59typedef struct{
60 bool_t buffer2;
61 uint8_t ram[GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH / 8];
62}PrivData;
63
64// Some common routines and macros
65#define PRIV(g) ((PrivData*)g->priv)
66#define RAM(g) (PRIV(g)->ram)
67#define write_cmd2(g, cmd1, cmd2) { write_cmd(g, cmd1); write_cmd(g, cmd2); }
68#define write_cmd3(g, cmd1, cmd2, cmd3) { write_cmd(g, cmd1); write_cmd(g, cmd2); write_cmd(g, cmd3); }
69
70// Some common routines and macros
71#define delay(us) gfxSleepMicroseconds(us)
72#define delay_ms(ms) gfxSleepMilliseconds(ms)
73
74#define xyaddr(x, y) ((x) + ((y)>>3)*GDISP_SCREEN_WIDTH)
75#define xybit(y) (1<<((y)&7))
76
77/*===========================================================================*/
78/* Driver exported functions. */
79/*===========================================================================*/
80
81/*
82 * As this controller can't update on a pixel boundary we need to maintain the
83 * the entire display surface in memory so that we can do the necessary bit
84 * operations. Fortunately it is a small display in monochrome.
85 * 64 * 128 / 8 = 1024 bytes.
86 */
87
88LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
89 // The private area is the display surface.
90 g->priv = gfxAlloc(sizeof(PrivData));
91 PRIV(g)->buffer2 = false;
92
93 // Initialise the board interface
94 init_board(g);
95
96 // Hardware reset
97 setpin_reset(g, TRUE);
98 gfxSleepMilliseconds(20);
99 setpin_reset(g, FALSE);
100 gfxSleepMilliseconds(20);
101
102 acquire_bus(g);
103 write_cmd(g, ST7565_DISPLAY_OFF);
104 write_cmd(g, ST7565_LCD_BIAS);
105 write_cmd(g, ST7565_ADC);
106 write_cmd(g, ST7565_COM_SCAN);
107
108 write_cmd(g, ST7565_START_LINE | 0);
109
110 write_cmd(g, ST7565_RESISTOR_RATIO | 0x6);
111
112 // turn on voltage converter (VC=1, VR=0, VF=0)
113 write_cmd(g, ST7565_POWER_CONTROL | 0x04);
114 delay_ms(50);
115
116 // turn on voltage regulator (VC=1, VR=1, VF=0)
117 write_cmd(g, ST7565_POWER_CONTROL | 0x06);
118 delay_ms(50);
119
120 // turn on voltage follower (VC=1, VR=1, VF=1)
121 write_cmd(g, ST7565_POWER_CONTROL | 0x07);
122 delay_ms(50);
123
124 write_cmd(g, 0xE2);
125 write_cmd(g, ST7565_COM_SCAN);
126 write_cmd2(g, ST7565_CONTRAST, GDISP_INITIAL_CONTRAST*64/101);
127 //write_cmd2(g, ST7565_CONTRAST, 0);
128 write_cmd(g, ST7565_DISPLAY_ON);
129 write_cmd(g, ST7565_ALLON_NORMAL);
130 write_cmd(g, ST7565_INVERT_DISPLAY);
131
132 write_cmd(g, ST7565_RMW);
133
134 // Finish Init
135 post_init_board(g);
136
137 // Release the bus
138 release_bus(g);
139
140 /* Initialise the GDISP structure */
141 g->g.Width = GDISP_SCREEN_WIDTH;
142 g->g.Height = GDISP_SCREEN_HEIGHT;
143 g->g.Orientation = GDISP_ROTATE_0;
144 g->g.Powermode = powerOn;
145 g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
146 g->g.Contrast = GDISP_INITIAL_CONTRAST;
147 return TRUE;
148}
149
150#if GDISP_HARDWARE_FLUSH
151 LLDSPEC void gdisp_lld_flush(GDisplay *g) {
152 unsigned p;
153
154 // Don't flush if we don't need it.
155 if (!(g->flags & GDISP_FLG_NEEDFLUSH))
156 return;
157
158 acquire_bus(g);
159 unsigned dstOffset = (PRIV(g)->buffer2 ? 4 : 0);
160 for (p = 0; p < 4; p++) {
161 write_cmd(g, ST7565_PAGE | (p + dstOffset));
162 write_cmd(g, ST7565_COLUMN_MSB | 0);
163 write_cmd(g, ST7565_COLUMN_LSB | 0);
164 write_cmd(g, ST7565_RMW);
165 write_data(g, RAM(g) + (p*GDISP_SCREEN_WIDTH), GDISP_SCREEN_WIDTH);
166 }
167 unsigned line = (PRIV(g)->buffer2 ? 32 : 0);
168 write_cmd(g, ST7565_START_LINE | line);
169 PRIV(g)->buffer2 = !PRIV(g)->buffer2;
170 release_bus(g);
171
172 g->flags &= ~GDISP_FLG_NEEDFLUSH;
173 }
174#endif
175
176#if GDISP_HARDWARE_DRAWPIXEL
177 LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
178 coord_t x, y;
179
180 switch(g->g.Orientation) {
181 default:
182 case GDISP_ROTATE_0:
183 x = g->p.x;
184 y = g->p.y;
185 break;
186 case GDISP_ROTATE_90:
187 x = g->p.y;
188 y = GDISP_SCREEN_HEIGHT-1 - g->p.x;
189 break;
190 case GDISP_ROTATE_180:
191 x = GDISP_SCREEN_WIDTH-1 - g->p.x;
192 y = GDISP_SCREEN_HEIGHT-1 - g->p.y;
193 break;
194 case GDISP_ROTATE_270:
195 x = GDISP_SCREEN_HEIGHT-1 - g->p.y;
196 y = g->p.x;
197 break;
198 }
199 if (gdispColor2Native(g->p.color) != Black)
200 RAM(g)[xyaddr(x, y)] |= xybit(y);
201 else
202 RAM(g)[xyaddr(x, y)] &= ~xybit(y);
203 g->flags |= GDISP_FLG_NEEDFLUSH;
204 }
205#endif
206
207#if GDISP_HARDWARE_PIXELREAD
208 LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
209 coord_t x, y;
210
211 switch(g->g.Orientation) {
212 default:
213 case GDISP_ROTATE_0:
214 x = g->p.x;
215 y = g->p.y;
216 break;
217 case GDISP_ROTATE_90:
218 x = g->p.y;
219 y = GDISP_SCREEN_HEIGHT-1 - g->p.x;
220 break;
221 case GDISP_ROTATE_180:
222 x = GDISP_SCREEN_WIDTH-1 - g->p.x;
223 y = GDISP_SCREEN_HEIGHT-1 - g->p.y;
224 break;
225 case GDISP_ROTATE_270:
226 x = GDISP_SCREEN_HEIGHT-1 - g->p.y;
227 y = g->p.x;
228 break;
229 }
230 return (RAM(g)[xyaddr(x, y)] & xybit(y)) ? White : Black;
231 }
232#endif
233
234#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
235 LLDSPEC void gdisp_lld_control(GDisplay *g) {
236 switch(g->p.x) {
237 case GDISP_CONTROL_POWER:
238 if (g->g.Powermode == (powermode_t)g->p.ptr)
239 return;
240 switch((powermode_t)g->p.ptr) {
241 case powerOff:
242 case powerSleep:
243 case powerDeepSleep:
244 acquire_bus(g);
245 write_cmd(g, ST7565_DISPLAY_OFF);
246 release_bus(g);
247 break;
248 case powerOn:
249 acquire_bus(g);
250 write_cmd(g, ST7565_DISPLAY_ON);
251 release_bus(g);
252 break;
253 default:
254 return;
255 }
256 g->g.Powermode = (powermode_t)g->p.ptr;
257 return;
258
259 case GDISP_CONTROL_ORIENTATION:
260 if (g->g.Orientation == (orientation_t)g->p.ptr)
261 return;
262 switch((orientation_t)g->p.ptr) {
263 /* Rotation is handled by the drawing routines */
264 case GDISP_ROTATE_0:
265 case GDISP_ROTATE_180:
266 g->g.Height = GDISP_SCREEN_HEIGHT;
267 g->g.Width = GDISP_SCREEN_WIDTH;
268 break;
269 case GDISP_ROTATE_90:
270 case GDISP_ROTATE_270:
271 g->g.Height = GDISP_SCREEN_WIDTH;
272 g->g.Width = GDISP_SCREEN_HEIGHT;
273 break;
274 default:
275 return;
276 }
277 g->g.Orientation = (orientation_t)g->p.ptr;
278 return;
279
280 case GDISP_CONTROL_CONTRAST:
281 if ((unsigned)g->p.ptr > 100)
282 g->p.ptr = (void *)100;
283 acquire_bus(g);
284 write_cmd2(g, ST7565_CONTRAST, ((((unsigned)g->p.ptr)<<6)/101) & 0x3F);
285 release_bus(g);
286 g->g.Contrast = (unsigned)g->p.ptr;
287 return;
288 }
289 }
290#endif // GDISP_NEED_CONTROL
291
292#endif // GFX_USE_GDISP
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/gdisp_lld_config.h b/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/gdisp_lld_config.h
new file mode 100644
index 000000000..48587b9e1
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/gdisp_lld_config.h
@@ -0,0 +1,26 @@
1/*
2 * This file is subject to the terms of the GFX License. If a copy of
3 * the license was not distributed with this file, you can obtain one at:
4 *
5 * http://ugfx.org/license.html
6 */
7
8#ifndef _GDISP_LLD_CONFIG_H
9#define _GDISP_LLD_CONFIG_H
10
11#if GFX_USE_GDISP
12
13/*===========================================================================*/
14/* Driver hardware support. */
15/*===========================================================================*/
16
17#define GDISP_HARDWARE_FLUSH TRUE // This controller requires flushing
18#define GDISP_HARDWARE_DRAWPIXEL TRUE
19#define GDISP_HARDWARE_PIXELREAD TRUE
20#define GDISP_HARDWARE_CONTROL TRUE
21
22#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO
23
24#endif /* GFX_USE_GDISP */
25
26#endif /* _GDISP_LLD_CONFIG_H */
diff --git a/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/st7565.h b/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/st7565.h
new file mode 100644
index 000000000..48636b33d
--- /dev/null
+++ b/keyboards/infinity_ergodox/drivers/gdisp/st7565ergodox/st7565.h
@@ -0,0 +1,37 @@
1/*
2 * This file is subject to the terms of the GFX License. If a copy of
3 * the license was not distributed with this file, you can obtain one at:
4 *
5 * http://ugfx.org/license.html
6 */
7
8#ifndef _ST7565_H
9#define _ST7565_H
10
11#define ST7565_CONTRAST 0x81
12#define ST7565_ALLON_NORMAL 0xA4
13#define ST7565_ALLON 0xA5
14#define ST7565_POSITIVE_DISPLAY 0xA6
15#define ST7565_INVERT_DISPLAY 0xA7
16#define ST7565_DISPLAY_OFF 0xAE
17#define ST7565_DISPLAY_ON 0xAF
18
19#define ST7565_LCD_BIAS_7 0xA3
20#define ST7565_LCD_BIAS_9 0xA2
21
22#define ST7565_ADC_NORMAL 0xA0
23#define ST7565_ADC_REVERSE 0xA1
24
25#define ST7565_COM_SCAN_INC 0xC0
26#define ST7565_COM_SCAN_DEC 0xC8
27
28#define ST7565_START_LINE 0x40
29#define ST7565_PAGE 0xB0
30#define ST7565_COLUMN_MSB 0x10
31#define ST7565_COLUMN_LSB 0x00
32#define ST7565_RMW 0xE0
33
34#define ST7565_RESISTOR_RATIO 0x20
35#define ST7565_POWER_CONTROL 0x28
36
37#endif /* _ST7565_H */