]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/ergodox/infinity/drivers/gdisp/st7565ergodox/gdisp_lld_ST7565.c
Initial structure for Ergodox as subprojects
[qmk_firmware.git] / keyboards / ergodox / infinity / drivers / gdisp / st7565ergodox / gdisp_lld_ST7565.c
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
59 typedef 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
88 LLDSPEC 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