aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/avr/analog.c69
-rw-r--r--drivers/avr/analog.h52
-rw-r--r--drivers/avr/glcdfont.c276
-rw-r--r--drivers/avr/pro_micro.h362
-rw-r--r--drivers/avr/ssd1306.c325
-rw-r--r--drivers/avr/ssd1306.h93
-rw-r--r--drivers/avr/ws2812.c342
-rw-r--r--drivers/avr/ws2812.h75
-rw-r--r--drivers/ugfx/gdisp/is31fl3731c/board_is31fl3731c_template.h110
-rw-r--r--drivers/ugfx/gdisp/is31fl3731c/driver.mk3
-rw-r--r--drivers/ugfx/gdisp/is31fl3731c/gdisp_is31fl3731c.c308
-rw-r--r--drivers/ugfx/gdisp/is31fl3731c/gdisp_lld_config.h36
-rw-r--r--drivers/ugfx/gdisp/st7565/board_st7565_template.h113
-rw-r--r--drivers/ugfx/gdisp/st7565/driver.mk3
-rw-r--r--drivers/ugfx/gdisp/st7565/gdisp_lld_ST7565.c329
-rw-r--r--drivers/ugfx/gdisp/st7565/gdisp_lld_config.h27
-rw-r--r--drivers/ugfx/gdisp/st7565/st7565.h39
17 files changed, 2562 insertions, 0 deletions
diff --git a/drivers/avr/analog.c b/drivers/avr/analog.c
new file mode 100644
index 000000000..1ec38df75
--- /dev/null
+++ b/drivers/avr/analog.c
@@ -0,0 +1,69 @@
1/* Copyright 2015 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17// Simple analog to digitial conversion
18
19#include <avr/io.h>
20#include <avr/pgmspace.h>
21#include <stdint.h>
22#include "analog.h"
23
24
25static uint8_t aref = (1<<REFS0); // default to AREF = Vcc
26
27
28void analogReference(uint8_t mode)
29{
30 aref = mode & 0xC0;
31}
32
33
34// Arduino compatible pin input
35int16_t analogRead(uint8_t pin)
36{
37#if defined(__AVR_ATmega32U4__)
38 static const uint8_t PROGMEM pin_to_mux[] = {
39 0x00, 0x01, 0x04, 0x05, 0x06, 0x07,
40 0x25, 0x24, 0x23, 0x22, 0x21, 0x20};
41 if (pin >= 12) return 0;
42 return adc_read(pgm_read_byte(pin_to_mux + pin));
43#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
44 if (pin >= 8) return 0;
45 return adc_read(pin);
46#else
47 return 0;
48#endif
49}
50
51// Mux input
52int16_t adc_read(uint8_t mux)
53{
54#if defined(__AVR_AT90USB162__)
55 return 0;
56#else
57 uint8_t low;
58
59 ADCSRA = (1<<ADEN) | ADC_PRESCALER; // enable ADC
60 ADCSRB = (1<<ADHSM) | (mux & 0x20); // high speed mode
61 ADMUX = aref | (mux & 0x1F); // configure mux input
62 ADCSRA = (1<<ADEN) | ADC_PRESCALER | (1<<ADSC); // start the conversion
63 while (ADCSRA & (1<<ADSC)) ; // wait for result
64 low = ADCL; // must read LSB first
65 return (ADCH << 8) | low; // must read MSB only once!
66#endif
67}
68
69
diff --git a/drivers/avr/analog.h b/drivers/avr/analog.h
new file mode 100644
index 000000000..8d93de7dc
--- /dev/null
+++ b/drivers/avr/analog.h
@@ -0,0 +1,52 @@
1/* Copyright 2015 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef _analog_h_included__
18#define _analog_h_included__
19
20#include <stdint.h>
21
22void analogReference(uint8_t mode);
23int16_t analogRead(uint8_t pin);
24int16_t adc_read(uint8_t mux);
25
26#define ADC_REF_POWER (1<<REFS0)
27#define ADC_REF_INTERNAL ((1<<REFS1) | (1<<REFS0))
28#define ADC_REF_EXTERNAL (0)
29
30// These prescaler values are for high speed mode, ADHSM = 1
31#if F_CPU == 16000000L
32#define ADC_PRESCALER ((1<<ADPS2) | (1<<ADPS1))
33#elif F_CPU == 8000000L
34#define ADC_PRESCALER ((1<<ADPS2) | (1<<ADPS0))
35#elif F_CPU == 4000000L
36#define ADC_PRESCALER ((1<<ADPS2))
37#elif F_CPU == 2000000L
38#define ADC_PRESCALER ((1<<ADPS1) | (1<<ADPS0))
39#elif F_CPU == 1000000L
40#define ADC_PRESCALER ((1<<ADPS1))
41#else
42#define ADC_PRESCALER ((1<<ADPS0))
43#endif
44
45// some avr-libc versions do not properly define ADHSM
46#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
47#if !defined(ADHSM)
48#define ADHSM (7)
49#endif
50#endif
51
52#endif
diff --git a/drivers/avr/glcdfont.c b/drivers/avr/glcdfont.c
new file mode 100644
index 000000000..6f88bd23a
--- /dev/null
+++ b/drivers/avr/glcdfont.c
@@ -0,0 +1,276 @@
1// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0.
2// See gfxfont.h for newer custom bitmap font info.
3
4#ifndef FONT5X7_H
5#define FONT5X7_H
6
7#ifdef __AVR__
8 #include <avr/io.h>
9 #include <avr/pgmspace.h>
10#elif defined(ESP8266)
11 #include <pgmspace.h>
12#else
13 #define PROGMEM
14#endif
15
16// Standard ASCII 5x7 font
17
18static const unsigned char font[] PROGMEM = {
19 0x00, 0x00, 0x00, 0x00, 0x00,
20 0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
21 0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
22 0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
23 0x18, 0x3C, 0x7E, 0x3C, 0x18,
24 0x1C, 0x57, 0x7D, 0x57, 0x1C,
25 0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
26 0x00, 0x18, 0x3C, 0x18, 0x00,
27 0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
28 0x00, 0x18, 0x24, 0x18, 0x00,
29 0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
30 0x30, 0x48, 0x3A, 0x06, 0x0E,
31 0x26, 0x29, 0x79, 0x29, 0x26,
32 0x40, 0x7F, 0x05, 0x05, 0x07,
33 0x40, 0x7F, 0x05, 0x25, 0x3F,
34 0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
35 0x7F, 0x3E, 0x1C, 0x1C, 0x08,
36 0x08, 0x1C, 0x1C, 0x3E, 0x7F,
37 0x14, 0x22, 0x7F, 0x22, 0x14,
38 0x5F, 0x5F, 0x00, 0x5F, 0x5F,
39 0x06, 0x09, 0x7F, 0x01, 0x7F,
40 0x00, 0x66, 0x89, 0x95, 0x6A,
41 0x60, 0x60, 0x60, 0x60, 0x60,
42 0x94, 0xA2, 0xFF, 0xA2, 0x94,
43 0x08, 0x04, 0x7E, 0x04, 0x08,
44 0x10, 0x20, 0x7E, 0x20, 0x10,
45 0x08, 0x08, 0x2A, 0x1C, 0x08,
46 0x08, 0x1C, 0x2A, 0x08, 0x08,
47 0x1E, 0x10, 0x10, 0x10, 0x10,
48 0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
49 0x30, 0x38, 0x3E, 0x38, 0x30,
50 0x06, 0x0E, 0x3E, 0x0E, 0x06,
51 0x00, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x5F, 0x00, 0x00,
53 0x00, 0x07, 0x00, 0x07, 0x00,
54 0x14, 0x7F, 0x14, 0x7F, 0x14,
55 0x24, 0x2A, 0x7F, 0x2A, 0x12,
56 0x23, 0x13, 0x08, 0x64, 0x62,
57 0x36, 0x49, 0x56, 0x20, 0x50,
58 0x00, 0x08, 0x07, 0x03, 0x00,
59 0x00, 0x1C, 0x22, 0x41, 0x00,
60 0x00, 0x41, 0x22, 0x1C, 0x00,
61 0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
62 0x08, 0x08, 0x3E, 0x08, 0x08,
63 0x00, 0x80, 0x70, 0x30, 0x00,
64 0x08, 0x08, 0x08, 0x08, 0x08,
65 0x00, 0x00, 0x60, 0x60, 0x00,
66 0x20, 0x10, 0x08, 0x04, 0x02,
67 0x3E, 0x51, 0x49, 0x45, 0x3E,
68 0x00, 0x42, 0x7F, 0x40, 0x00,
69 0x72, 0x49, 0x49, 0x49, 0x46,
70 0x21, 0x41, 0x49, 0x4D, 0x33,
71 0x18, 0x14, 0x12, 0x7F, 0x10,
72 0x27, 0x45, 0x45, 0x45, 0x39,
73 0x3C, 0x4A, 0x49, 0x49, 0x31,
74 0x41, 0x21, 0x11, 0x09, 0x07,
75 0x36, 0x49, 0x49, 0x49, 0x36,
76 0x46, 0x49, 0x49, 0x29, 0x1E,
77 0x00, 0x00, 0x14, 0x00, 0x00,
78 0x00, 0x40, 0x34, 0x00, 0x00,
79 0x00, 0x08, 0x14, 0x22, 0x41,
80 0x14, 0x14, 0x14, 0x14, 0x14,
81 0x00, 0x41, 0x22, 0x14, 0x08,
82 0x02, 0x01, 0x59, 0x09, 0x06,
83 0x3E, 0x41, 0x5D, 0x59, 0x4E,
84 0x7C, 0x12, 0x11, 0x12, 0x7C,
85 0x7F, 0x49, 0x49, 0x49, 0x36,
86 0x3E, 0x41, 0x41, 0x41, 0x22,
87 0x7F, 0x41, 0x41, 0x41, 0x3E,
88 0x7F, 0x49, 0x49, 0x49, 0x41,
89 0x7F, 0x09, 0x09, 0x09, 0x01,
90 0x3E, 0x41, 0x41, 0x51, 0x73,
91 0x7F, 0x08, 0x08, 0x08, 0x7F,
92 0x00, 0x41, 0x7F, 0x41, 0x00,
93 0x20, 0x40, 0x41, 0x3F, 0x01,
94 0x7F, 0x08, 0x14, 0x22, 0x41,
95 0x7F, 0x40, 0x40, 0x40, 0x40,
96 0x7F, 0x02, 0x1C, 0x02, 0x7F,
97 0x7F, 0x04, 0x08, 0x10, 0x7F,
98 0x3E, 0x41, 0x41, 0x41, 0x3E,
99 0x7F, 0x09, 0x09, 0x09, 0x06,
100 0x3E, 0x41, 0x51, 0x21, 0x5E,
101 0x7F, 0x09, 0x19, 0x29, 0x46,
102 0x26, 0x49, 0x49, 0x49, 0x32,
103 0x03, 0x01, 0x7F, 0x01, 0x03,
104 0x3F, 0x40, 0x40, 0x40, 0x3F,
105 0x1F, 0x20, 0x40, 0x20, 0x1F,
106 0x3F, 0x40, 0x38, 0x40, 0x3F,
107 0x63, 0x14, 0x08, 0x14, 0x63,
108 0x03, 0x04, 0x78, 0x04, 0x03,
109 0x61, 0x59, 0x49, 0x4D, 0x43,
110 0x00, 0x7F, 0x41, 0x41, 0x41,
111 0x02, 0x04, 0x08, 0x10, 0x20,
112 0x00, 0x41, 0x41, 0x41, 0x7F,
113 0x04, 0x02, 0x01, 0x02, 0x04,
114 0x40, 0x40, 0x40, 0x40, 0x40,
115 0x00, 0x03, 0x07, 0x08, 0x00,
116 0x20, 0x54, 0x54, 0x78, 0x40,
117 0x7F, 0x28, 0x44, 0x44, 0x38,
118 0x38, 0x44, 0x44, 0x44, 0x28,
119 0x38, 0x44, 0x44, 0x28, 0x7F,
120 0x38, 0x54, 0x54, 0x54, 0x18,
121 0x00, 0x08, 0x7E, 0x09, 0x02,
122 0x18, 0xA4, 0xA4, 0x9C, 0x78,
123 0x7F, 0x08, 0x04, 0x04, 0x78,
124 0x00, 0x44, 0x7D, 0x40, 0x00,
125 0x20, 0x40, 0x40, 0x3D, 0x00,
126 0x7F, 0x10, 0x28, 0x44, 0x00,
127 0x00, 0x41, 0x7F, 0x40, 0x00,
128 0x7C, 0x04, 0x78, 0x04, 0x78,
129 0x7C, 0x08, 0x04, 0x04, 0x78,
130 0x38, 0x44, 0x44, 0x44, 0x38,
131 0xFC, 0x18, 0x24, 0x24, 0x18,
132 0x18, 0x24, 0x24, 0x18, 0xFC,
133 0x7C, 0x08, 0x04, 0x04, 0x08,
134 0x48, 0x54, 0x54, 0x54, 0x24,
135 0x04, 0x04, 0x3F, 0x44, 0x24,
136 0x3C, 0x40, 0x40, 0x20, 0x7C,
137 0x1C, 0x20, 0x40, 0x20, 0x1C,
138 0x3C, 0x40, 0x30, 0x40, 0x3C,
139 0x44, 0x28, 0x10, 0x28, 0x44,
140 0x4C, 0x90, 0x90, 0x90, 0x7C,
141 0x44, 0x64, 0x54, 0x4C, 0x44,
142 0x00, 0x08, 0x36, 0x41, 0x00,
143 0x00, 0x00, 0x77, 0x00, 0x00,
144 0x00, 0x41, 0x36, 0x08, 0x00,
145 0x02, 0x01, 0x02, 0x04, 0x02,
146 0x3C, 0x26, 0x23, 0x26, 0x3C,
147 0x1E, 0xA1, 0xA1, 0x61, 0x12,
148 0x3A, 0x40, 0x40, 0x20, 0x7A,
149 0x38, 0x54, 0x54, 0x55, 0x59,
150 0x21, 0x55, 0x55, 0x79, 0x41,
151 0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut
152 0x21, 0x55, 0x54, 0x78, 0x40,
153 0x20, 0x54, 0x55, 0x79, 0x40,
154 0x0C, 0x1E, 0x52, 0x72, 0x12,
155 0x39, 0x55, 0x55, 0x55, 0x59,
156 0x39, 0x54, 0x54, 0x54, 0x59,
157 0x39, 0x55, 0x54, 0x54, 0x58,
158 0x00, 0x00, 0x45, 0x7C, 0x41,
159 0x00, 0x02, 0x45, 0x7D, 0x42,
160 0x00, 0x01, 0x45, 0x7C, 0x40,
161 0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut
162 0xF0, 0x28, 0x25, 0x28, 0xF0,
163 0x7C, 0x54, 0x55, 0x45, 0x00,
164 0x20, 0x54, 0x54, 0x7C, 0x54,
165 0x7C, 0x0A, 0x09, 0x7F, 0x49,
166 0x32, 0x49, 0x49, 0x49, 0x32,
167 0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut
168 0x32, 0x4A, 0x48, 0x48, 0x30,
169 0x3A, 0x41, 0x41, 0x21, 0x7A,
170 0x3A, 0x42, 0x40, 0x20, 0x78,
171 0x00, 0x9D, 0xA0, 0xA0, 0x7D,
172 0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut
173 0x3D, 0x40, 0x40, 0x40, 0x3D,
174 0x3C, 0x24, 0xFF, 0x24, 0x24,
175 0x48, 0x7E, 0x49, 0x43, 0x66,
176 0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
177 0xFF, 0x09, 0x29, 0xF6, 0x20,
178 0xC0, 0x88, 0x7E, 0x09, 0x03,
179 0x20, 0x54, 0x54, 0x79, 0x41,
180 0x00, 0x00, 0x44, 0x7D, 0x41,
181 0x30, 0x48, 0x48, 0x4A, 0x32,
182 0x38, 0x40, 0x40, 0x22, 0x7A,
183 0x00, 0x7A, 0x0A, 0x0A, 0x72,
184 0x7D, 0x0D, 0x19, 0x31, 0x7D,
185 0x26, 0x29, 0x29, 0x2F, 0x28,
186 0x26, 0x29, 0x29, 0x29, 0x26,
187 0x30, 0x48, 0x4D, 0x40, 0x20,
188 0x38, 0x08, 0x08, 0x08, 0x08,
189 0x08, 0x08, 0x08, 0x08, 0x38,
190 0x2F, 0x10, 0xC8, 0xAC, 0xBA,
191 0x2F, 0x10, 0x28, 0x34, 0xFA,
192 0x00, 0x00, 0x7B, 0x00, 0x00,
193 0x08, 0x14, 0x2A, 0x14, 0x22,
194 0x22, 0x14, 0x2A, 0x14, 0x08,
195 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code
196 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block
197 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block
198 0x00, 0x00, 0x00, 0xFF, 0x00,
199 0x10, 0x10, 0x10, 0xFF, 0x00,
200 0x14, 0x14, 0x14, 0xFF, 0x00,
201 0x10, 0x10, 0xFF, 0x00, 0xFF,
202 0x10, 0x10, 0xF0, 0x10, 0xF0,
203 0x14, 0x14, 0x14, 0xFC, 0x00,
204 0x14, 0x14, 0xF7, 0x00, 0xFF,
205 0x00, 0x00, 0xFF, 0x00, 0xFF,
206 0x14, 0x14, 0xF4, 0x04, 0xFC,
207 0x14, 0x14, 0x17, 0x10, 0x1F,
208 0x10, 0x10, 0x1F, 0x10, 0x1F,
209 0x14, 0x14, 0x14, 0x1F, 0x00,
210 0x10, 0x10, 0x10, 0xF0, 0x00,
211 0x00, 0x00, 0x00, 0x1F, 0x10,
212 0x10, 0x10, 0x10, 0x1F, 0x10,
213 0x10, 0x10, 0x10, 0xF0, 0x10,
214 0x00, 0x00, 0x00, 0xFF, 0x10,
215 0x10, 0x10, 0x10, 0x10, 0x10,
216 0x10, 0x10, 0x10, 0xFF, 0x10,
217 0x00, 0x00, 0x00, 0xFF, 0x14,
218 0x00, 0x00, 0xFF, 0x00, 0xFF,
219 0x00, 0x00, 0x1F, 0x10, 0x17,
220 0x00, 0x00, 0xFC, 0x04, 0xF4,
221 0x14, 0x14, 0x17, 0x10, 0x17,
222 0x14, 0x14, 0xF4, 0x04, 0xF4,
223 0x00, 0x00, 0xFF, 0x00, 0xF7,
224 0x14, 0x14, 0x14, 0x14, 0x14,
225 0x14, 0x14, 0xF7, 0x00, 0xF7,
226 0x14, 0x14, 0x14, 0x17, 0x14,
227 0x10, 0x10, 0x1F, 0x10, 0x1F,
228 0x14, 0x14, 0x14, 0xF4, 0x14,
229 0x10, 0x10, 0xF0, 0x10, 0xF0,
230 0x00, 0x00, 0x1F, 0x10, 0x1F,
231 0x00, 0x00, 0x00, 0x1F, 0x14,
232 0x00, 0x00, 0x00, 0xFC, 0x14,
233 0x00, 0x00, 0xF0, 0x10, 0xF0,
234 0x10, 0x10, 0xFF, 0x10, 0xFF,
235 0x14, 0x14, 0x14, 0xFF, 0x14,
236 0x10, 0x10, 0x10, 0x1F, 0x00,
237 0x00, 0x00, 0x00, 0xF0, 0x10,
238 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
239 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
240 0xFF, 0xFF, 0xFF, 0x00, 0x00,
241 0x00, 0x00, 0x00, 0xFF, 0xFF,
242 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
243 0x38, 0x44, 0x44, 0x38, 0x44,
244 0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta
245 0x7E, 0x02, 0x02, 0x06, 0x06,
246 0x02, 0x7E, 0x02, 0x7E, 0x02,
247 0x63, 0x55, 0x49, 0x41, 0x63,
248 0x38, 0x44, 0x44, 0x3C, 0x04,
249 0x40, 0x7E, 0x20, 0x1E, 0x20,
250 0x06, 0x02, 0x7E, 0x02, 0x02,
251 0x99, 0xA5, 0xE7, 0xA5, 0x99,
252 0x1C, 0x2A, 0x49, 0x2A, 0x1C,
253 0x4C, 0x72, 0x01, 0x72, 0x4C,
254 0x30, 0x4A, 0x4D, 0x4D, 0x30,
255 0x30, 0x48, 0x78, 0x48, 0x30,
256 0xBC, 0x62, 0x5A, 0x46, 0x3D,
257 0x3E, 0x49, 0x49, 0x49, 0x00,
258 0x7E, 0x01, 0x01, 0x01, 0x7E,
259 0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
260 0x44, 0x44, 0x5F, 0x44, 0x44,
261 0x40, 0x51, 0x4A, 0x44, 0x40,
262 0x40, 0x44, 0x4A, 0x51, 0x40,
263 0x00, 0x00, 0xFF, 0x01, 0x03,
264 0xE0, 0x80, 0xFF, 0x00, 0x00,
265 0x08, 0x08, 0x6B, 0x6B, 0x08,
266 0x36, 0x12, 0x36, 0x24, 0x36,
267 0x06, 0x0F, 0x09, 0x0F, 0x06,
268 0x00, 0x00, 0x18, 0x18, 0x00,
269 0x00, 0x00, 0x10, 0x10, 0x00,
270 0x30, 0x40, 0xFF, 0x01, 0x01,
271 0x00, 0x1F, 0x01, 0x01, 0x1E,
272 0x00, 0x19, 0x1D, 0x17, 0x12,
273 0x00, 0x3C, 0x3C, 0x3C, 0x3C,
274 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP
275};
276#endif // FONT5X7_H
diff --git a/drivers/avr/pro_micro.h b/drivers/avr/pro_micro.h
new file mode 100644
index 000000000..f9e7ed75d
--- /dev/null
+++ b/drivers/avr/pro_micro.h
@@ -0,0 +1,362 @@
1/*
2 pins_arduino.h - Pin definition functions for Arduino
3 Part of Arduino - http://www.arduino.cc/
4
5 Copyright (c) 2007 David A. Mellis
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General
18 Public License along with this library; if not, write to the
19 Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 Boston, MA 02111-1307 USA
21
22 $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $
23*/
24
25#ifndef Pins_Arduino_h
26#define Pins_Arduino_h
27
28#include <avr/pgmspace.h>
29
30// Workaround for wrong definitions in "iom32u4.h".
31// This should be fixed in the AVR toolchain.
32#undef UHCON
33#undef UHINT
34#undef UHIEN
35#undef UHADDR
36#undef UHFNUM
37#undef UHFNUML
38#undef UHFNUMH
39#undef UHFLEN
40#undef UPINRQX
41#undef UPINTX
42#undef UPNUM
43#undef UPRST
44#undef UPCONX
45#undef UPCFG0X
46#undef UPCFG1X
47#undef UPSTAX
48#undef UPCFG2X
49#undef UPIENX
50#undef UPDATX
51#undef TCCR2A
52#undef WGM20
53#undef WGM21
54#undef COM2B0
55#undef COM2B1
56#undef COM2A0
57#undef COM2A1
58#undef TCCR2B
59#undef CS20
60#undef CS21
61#undef CS22
62#undef WGM22
63#undef FOC2B
64#undef FOC2A
65#undef TCNT2
66#undef TCNT2_0
67#undef TCNT2_1
68#undef TCNT2_2
69#undef TCNT2_3
70#undef TCNT2_4
71#undef TCNT2_5
72#undef TCNT2_6
73#undef TCNT2_7
74#undef OCR2A
75#undef OCR2_0
76#undef OCR2_1
77#undef OCR2_2
78#undef OCR2_3
79#undef OCR2_4
80#undef OCR2_5
81#undef OCR2_6
82#undef OCR2_7
83#undef OCR2B
84#undef OCR2_0
85#undef OCR2_1
86#undef OCR2_2
87#undef OCR2_3
88#undef OCR2_4
89#undef OCR2_5
90#undef OCR2_6
91#undef OCR2_7
92
93#define NUM_DIGITAL_PINS 30
94#define NUM_ANALOG_INPUTS 12
95
96#define TX_RX_LED_INIT DDRD |= (1<<5), DDRB |= (1<<0)
97#define TXLED0 PORTD |= (1<<5)
98#define TXLED1 PORTD &= ~(1<<5)
99#define RXLED0 PORTB |= (1<<0)
100#define RXLED1 PORTB &= ~(1<<0)
101
102static const uint8_t SDA = 2;
103static const uint8_t SCL = 3;
104#define LED_BUILTIN 13
105
106// Map SPI port to 'new' pins D14..D17
107static const uint8_t SS = 17;
108static const uint8_t MOSI = 16;
109static const uint8_t MISO = 14;
110static const uint8_t SCK = 15;
111
112// Mapping of analog pins as digital I/O
113// A6-A11 share with digital pins
114static const uint8_t ADC0 = 18;
115static const uint8_t ADC1 = 19;
116static const uint8_t ADC2 = 20;
117static const uint8_t ADC3 = 21;
118static const uint8_t ADC4 = 22;
119static const uint8_t ADC5 = 23;
120static const uint8_t ADC6 = 24; // D4
121static const uint8_t ADC7 = 25; // D6
122static const uint8_t ADC8 = 26; // D8
123static const uint8_t ADC9 = 27; // D9
124static const uint8_t ADC10 = 28; // D10
125static const uint8_t ADC11 = 29; // D12
126
127#define digitalPinToPCICR(p) ((((p) >= 8 && (p) <= 11) || ((p) >= 14 && (p) <= 17) || ((p) >= A8 && (p) <= A10)) ? (&PCICR) : ((uint8_t *)0))
128#define digitalPinToPCICRbit(p) 0
129#define digitalPinToPCMSK(p) ((((p) >= 8 && (p) <= 11) || ((p) >= 14 && (p) <= 17) || ((p) >= A8 && (p) <= A10)) ? (&PCMSK0) : ((uint8_t *)0))
130#define digitalPinToPCMSKbit(p) ( ((p) >= 8 && (p) <= 11) ? (p) - 4 : ((p) == 14 ? 3 : ((p) == 15 ? 1 : ((p) == 16 ? 2 : ((p) == 17 ? 0 : (p - A8 + 4))))))
131
132// __AVR_ATmega32U4__ has an unusual mapping of pins to channels
133extern const uint8_t PROGMEM analog_pin_to_channel_PGM[];
134#define analogPinToChannel(P) ( pgm_read_byte( analog_pin_to_channel_PGM + (P) ) )
135
136#define digitalPinToInterrupt(p) ((p) == 0 ? 2 : ((p) == 1 ? 3 : ((p) == 2 ? 1 : ((p) == 3 ? 0 : ((p) == 7 ? 4 : NOT_AN_INTERRUPT)))))
137
138#ifdef ARDUINO_MAIN
139
140// On the Arduino board, digital pins are also used
141// for the analog output (software PWM). Analog input
142// pins are a separate set.
143
144// ATMEL ATMEGA32U4 / ARDUINO LEONARDO
145//
146// D0 PD2 RXD1/INT2
147// D1 PD3 TXD1/INT3
148// D2 PD1 SDA SDA/INT1
149// D3# PD0 PWM8/SCL OC0B/SCL/INT0
150// D4 A6 PD4 ADC8
151// D5# PC6 ??? OC3A/#OC4A
152// D6# A7 PD7 FastPWM #OC4D/ADC10
153// D7 PE6 INT6/AIN0
154//
155// D8 A8 PB4 ADC11/PCINT4
156// D9# A9 PB5 PWM16 OC1A/#OC4B/ADC12/PCINT5
157// D10# A10 PB6 PWM16 OC1B/0c4B/ADC13/PCINT6
158// D11# PB7 PWM8/16 0C0A/OC1C/#RTS/PCINT7
159// D12 A11 PD6 T1/#OC4D/ADC9
160// D13# PC7 PWM10 CLK0/OC4A
161//
162// A0 D18 PF7 ADC7
163// A1 D19 PF6 ADC6
164// A2 D20 PF5 ADC5
165// A3 D21 PF4 ADC4
166// A4 D22 PF1 ADC1
167// A5 D23 PF0 ADC0
168//
169// New pins D14..D17 to map SPI port to digital pins
170//
171// MISO D14 PB3 MISO,PCINT3
172// SCK D15 PB1 SCK,PCINT1
173// MOSI D16 PB2 MOSI,PCINT2
174// SS D17 PB0 RXLED,SS/PCINT0
175//
176// Connected LEDs on board for TX and RX
177// TXLED D24 PD5 XCK1
178// RXLED D17 PB0
179// HWB PE2 HWB
180
181// these arrays map port names (e.g. port B) to the
182// appropriate addresses for various functions (e.g. reading
183// and writing)
184const uint16_t PROGMEM port_to_mode_PGM[] = {
185 NOT_A_PORT,
186 NOT_A_PORT,
187 (uint16_t) &DDRB,
188 (uint16_t) &DDRC,
189 (uint16_t) &DDRD,
190 (uint16_t) &DDRE,
191 (uint16_t) &DDRF,
192};
193
194const uint16_t PROGMEM port_to_output_PGM[] = {
195 NOT_A_PORT,
196 NOT_A_PORT,
197 (uint16_t) &PORTB,
198 (uint16_t) &PORTC,
199 (uint16_t) &PORTD,
200 (uint16_t) &PORTE,
201 (uint16_t) &PORTF,
202};
203
204const uint16_t PROGMEM port_to_input_PGM[] = {
205 NOT_A_PORT,
206 NOT_A_PORT,
207 (uint16_t) &PINB,
208 (uint16_t) &PINC,
209 (uint16_t) &PIND,
210 (uint16_t) &PINE,
211 (uint16_t) &PINF,
212};
213
214const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
215 PD, // D0 - PD2
216 PD, // D1 - PD3
217 PD, // D2 - PD1
218 PD, // D3 - PD0
219 PD, // D4 - PD4
220 PC, // D5 - PC6
221 PD, // D6 - PD7
222 PE, // D7 - PE6
223
224 PB, // D8 - PB4
225 PB, // D9 - PB5
226 PB, // D10 - PB6
227 PB, // D11 - PB7
228 PD, // D12 - PD6
229 PC, // D13 - PC7
230
231 PB, // D14 - MISO - PB3
232 PB, // D15 - SCK - PB1
233 PB, // D16 - MOSI - PB2
234 PB, // D17 - SS - PB0
235
236 PF, // D18 - A0 - PF7
237 PF, // D19 - A1 - PF6
238 PF, // D20 - A2 - PF5
239 PF, // D21 - A3 - PF4
240 PF, // D22 - A4 - PF1
241 PF, // D23 - A5 - PF0
242
243 PD, // D24 - PD5
244 PD, // D25 / D6 - A7 - PD7
245 PB, // D26 / D8 - A8 - PB4
246 PB, // D27 / D9 - A9 - PB5
247 PB, // D28 / D10 - A10 - PB6
248 PD, // D29 / D12 - A11 - PD6
249};
250
251const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
252 _BV(2), // D0 - PD2
253 _BV(3), // D1 - PD3
254 _BV(1), // D2 - PD1
255 _BV(0), // D3 - PD0
256 _BV(4), // D4 - PD4
257 _BV(6), // D5 - PC6
258 _BV(7), // D6 - PD7
259 _BV(6), // D7 - PE6
260
261 _BV(4), // D8 - PB4
262 _BV(5), // D9 - PB5
263 _BV(6), // D10 - PB6
264 _BV(7), // D11 - PB7
265 _BV(6), // D12 - PD6
266 _BV(7), // D13 - PC7
267
268 _BV(3), // D14 - MISO - PB3
269 _BV(1), // D15 - SCK - PB1
270 _BV(2), // D16 - MOSI - PB2
271 _BV(0), // D17 - SS - PB0
272
273 _BV(7), // D18 - A0 - PF7
274 _BV(6), // D19 - A1 - PF6
275 _BV(5), // D20 - A2 - PF5
276 _BV(4), // D21 - A3 - PF4
277 _BV(1), // D22 - A4 - PF1
278 _BV(0), // D23 - A5 - PF0
279
280 _BV(5), // D24 - PD5
281 _BV(7), // D25 / D6 - A7 - PD7
282 _BV(4), // D26 / D8 - A8 - PB4
283 _BV(5), // D27 / D9 - A9 - PB5
284 _BV(6), // D28 / D10 - A10 - PB6
285 _BV(6), // D29 / D12 - A11 - PD6
286};
287
288const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
289 NOT_ON_TIMER,
290 NOT_ON_TIMER,
291 NOT_ON_TIMER,
292 TIMER0B, /* 3 */
293 NOT_ON_TIMER,
294 TIMER3A, /* 5 */
295 TIMER4D, /* 6 */
296 NOT_ON_TIMER,
297
298 NOT_ON_TIMER,
299 TIMER1A, /* 9 */
300 TIMER1B, /* 10 */
301 TIMER0A, /* 11 */
302
303 NOT_ON_TIMER,
304 TIMER4A, /* 13 */
305
306 NOT_ON_TIMER,
307 NOT_ON_TIMER,
308 NOT_ON_TIMER,
309 NOT_ON_TIMER,
310 NOT_ON_TIMER,
311 NOT_ON_TIMER,
312
313 NOT_ON_TIMER,
314 NOT_ON_TIMER,
315 NOT_ON_TIMER,
316 NOT_ON_TIMER,
317 NOT_ON_TIMER,
318 NOT_ON_TIMER,
319 NOT_ON_TIMER,
320 NOT_ON_TIMER,
321 NOT_ON_TIMER,
322 NOT_ON_TIMER,
323};
324
325const uint8_t PROGMEM analog_pin_to_channel_PGM[] = {
326 7, // A0 PF7 ADC7
327 6, // A1 PF6 ADC6
328 5, // A2 PF5 ADC5
329 4, // A3 PF4 ADC4
330 1, // A4 PF1 ADC1
331 0, // A5 PF0 ADC0
332 8, // A6 D4 PD4 ADC8
333 10, // A7 D6 PD7 ADC10
334 11, // A8 D8 PB4 ADC11
335 12, // A9 D9 PB5 ADC12
336 13, // A10 D10 PB6 ADC13
337 9 // A11 D12 PD6 ADC9
338};
339
340#endif /* ARDUINO_MAIN */
341
342// These serial port names are intended to allow libraries and architecture-neutral
343// sketches to automatically default to the correct port name for a particular type
344// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN,
345// the first hardware serial port whose RX/TX pins are not dedicated to another use.
346//
347// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor
348//
349// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial
350//
351// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library
352//
353// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins.
354//
355// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX
356// pins are NOT connected to anything by default.
357#define SERIAL_PORT_MONITOR Serial
358#define SERIAL_PORT_USBVIRTUAL Serial
359#define SERIAL_PORT_HARDWARE Serial1
360#define SERIAL_PORT_HARDWARE_OPEN Serial1
361
362#endif /* Pins_Arduino_h */
diff --git a/drivers/avr/ssd1306.c b/drivers/avr/ssd1306.c
new file mode 100644
index 000000000..bb8938bba
--- /dev/null
+++ b/drivers/avr/ssd1306.c
@@ -0,0 +1,325 @@
1#ifdef SSD1306OLED
2
3#include "ssd1306.h"
4#include "i2c.h"
5#include <string.h>
6#include "print.h"
7#include "glcdfont.c"
8#ifdef ADAFRUIT_BLE_ENABLE
9#include "adafruit_ble.h"
10#endif
11#ifdef PROTOCOL_LUFA
12#include "lufa.h"
13#endif
14#include "sendchar.h"
15#include "timer.h"
16
17// Set this to 1 to help diagnose early startup problems
18// when testing power-on with ble. Turn it off otherwise,
19// as the latency of printing most of the debug info messes
20// with the matrix scan, causing keys to drop.
21#define DEBUG_TO_SCREEN 0
22
23//static uint16_t last_battery_update;
24//static uint32_t vbat;
25//#define BatteryUpdateInterval 10000 /* milliseconds */
26#define ScreenOffInterval 300000 /* milliseconds */
27#if DEBUG_TO_SCREEN
28static uint8_t displaying;
29#endif
30static uint16_t last_flush;
31
32// Write command sequence.
33// Returns true on success.
34static inline bool _send_cmd1(uint8_t cmd) {
35 bool res = false;
36
37 if (i2c_start_write(SSD1306_ADDRESS)) {
38 xprintf("failed to start write to %d\n", SSD1306_ADDRESS);
39 goto done;
40 }
41
42 if (i2c_master_write(0x0 /* command byte follows */)) {
43 print("failed to write control byte\n");
44
45 goto done;
46 }
47
48 if (i2c_master_write(cmd)) {
49 xprintf("failed to write command %d\n", cmd);
50 goto done;
51 }
52 res = true;
53done:
54 i2c_master_stop();
55 return res;
56}
57
58// Write 2-byte command sequence.
59// Returns true on success
60static inline bool _send_cmd2(uint8_t cmd, uint8_t opr) {
61 if (!_send_cmd1(cmd)) {
62 return false;
63 }
64 return _send_cmd1(opr);
65}
66
67// Write 3-byte command sequence.
68// Returns true on success
69static inline bool _send_cmd3(uint8_t cmd, uint8_t opr1, uint8_t opr2) {
70 if (!_send_cmd1(cmd)) {
71 return false;
72 }
73 if (!_send_cmd1(opr1)) {
74 return false;
75 }
76 return _send_cmd1(opr2);
77}
78
79#define send_cmd1(c) if (!_send_cmd1(c)) {goto done;}
80#define send_cmd2(c,o) if (!_send_cmd2(c,o)) {goto done;}
81#define send_cmd3(c,o1,o2) if (!_send_cmd3(c,o1,o2)) {goto done;}
82
83static void clear_display(void) {
84 matrix_clear(&display);
85
86 // Clear all of the display bits (there can be random noise
87 // in the RAM on startup)
88 send_cmd3(PageAddr, 0, (DisplayHeight / 8) - 1);
89 send_cmd3(ColumnAddr, 0, DisplayWidth - 1);
90
91 if (i2c_start_write(SSD1306_ADDRESS)) {
92 goto done;
93 }
94 if (i2c_master_write(0x40)) {
95 // Data mode
96 goto done;
97 }
98 for (uint8_t row = 0; row < MatrixRows; ++row) {
99 for (uint8_t col = 0; col < DisplayWidth; ++col) {
100 i2c_master_write(0);
101 }
102 }
103
104 display.dirty = false;
105
106done:
107 i2c_master_stop();
108}
109
110#if DEBUG_TO_SCREEN
111#undef sendchar
112static int8_t capture_sendchar(uint8_t c) {
113 sendchar(c);
114 iota_gfx_write_char(c);
115
116 if (!displaying) {
117 iota_gfx_flush();
118 }
119 return 0;
120}
121#endif
122
123bool iota_gfx_init(void) {
124 bool success = false;
125
126 send_cmd1(DisplayOff);
127 send_cmd2(SetDisplayClockDiv, 0x80);
128 send_cmd2(SetMultiPlex, DisplayHeight - 1);
129
130 send_cmd2(SetDisplayOffset, 0);
131
132
133 send_cmd1(SetStartLine | 0x0);
134 send_cmd2(SetChargePump, 0x14 /* Enable */);
135 send_cmd2(SetMemoryMode, 0 /* horizontal addressing */);
136
137#ifdef OLED_ROTATE180
138// the following Flip the display orientation 180 degrees
139 send_cmd1(SegRemap);
140 send_cmd1(ComScanInc);
141#endif
142#ifndef OLED_ROTATE180
143// Flips the display orientation 0 degrees
144 send_cmd1(SegRemap | 0x1);
145 send_cmd1(ComScanDec);
146#endif
147
148 send_cmd2(SetComPins, 0x2);
149 send_cmd2(SetContrast, 0x8f);
150 send_cmd2(SetPreCharge, 0xf1);
151 send_cmd2(SetVComDetect, 0x40);
152 send_cmd1(DisplayAllOnResume);
153 send_cmd1(NormalDisplay);
154 send_cmd1(DeActivateScroll);
155 send_cmd1(DisplayOn);
156
157 send_cmd2(SetContrast, 0); // Dim
158
159 clear_display();
160
161 success = true;
162
163 iota_gfx_flush();
164
165#if DEBUG_TO_SCREEN
166 print_set_sendchar(capture_sendchar);
167#endif
168
169done:
170 return success;
171}
172
173bool iota_gfx_off(void) {
174 bool success = false;
175
176 send_cmd1(DisplayOff);
177 success = true;
178
179done:
180 return success;
181}
182
183bool iota_gfx_on(void) {
184 bool success = false;
185
186 send_cmd1(DisplayOn);
187 success = true;
188
189done:
190 return success;
191}
192
193void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c) {
194 *matrix->cursor = c;
195 ++matrix->cursor;
196
197 if (matrix->cursor - &matrix->display[0][0] == sizeof(matrix->display)) {
198 // We went off the end; scroll the display upwards by one line
199 memmove(&matrix->display[0], &matrix->display[1],
200 MatrixCols * (MatrixRows - 1));
201 matrix->cursor = &matrix->display[MatrixRows - 1][0];
202 memset(matrix->cursor, ' ', MatrixCols);
203 }
204}
205
206void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c) {
207 matrix->dirty = true;
208
209 if (c == '\n') {
210 // Clear to end of line from the cursor and then move to the
211 // start of the next line
212 uint8_t cursor_col = (matrix->cursor - &matrix->display[0][0]) % MatrixCols;
213
214 while (cursor_col++ < MatrixCols) {
215 matrix_write_char_inner(matrix, ' ');
216 }
217 return;
218 }
219
220 matrix_write_char_inner(matrix, c);
221}
222
223void iota_gfx_write_char(uint8_t c) {
224 matrix_write_char(&display, c);
225}
226
227void matrix_write(struct CharacterMatrix *matrix, const char *data) {
228 const char *end = data + strlen(data);
229 while (data < end) {
230 matrix_write_char(matrix, *data);
231 ++data;
232 }
233}
234
235void iota_gfx_write(const char *data) {
236 matrix_write(&display, data);
237}
238
239void matrix_write_P(struct CharacterMatrix *matrix, const char *data) {
240 while (true) {
241 uint8_t c = pgm_read_byte(data);
242 if (c == 0) {
243 return;
244 }
245 matrix_write_char(matrix, c);
246 ++data;
247 }
248}
249
250void iota_gfx_write_P(const char *data) {
251 matrix_write_P(&display, data);
252}
253
254void matrix_clear(struct CharacterMatrix *matrix) {
255 memset(matrix->display, ' ', sizeof(matrix->display));
256 matrix->cursor = &matrix->display[0][0];
257 matrix->dirty = true;
258}
259
260void iota_gfx_clear_screen(void) {
261 matrix_clear(&display);
262}
263
264void matrix_render(struct CharacterMatrix *matrix) {
265 last_flush = timer_read();
266 iota_gfx_on();
267#if DEBUG_TO_SCREEN
268 ++displaying;
269#endif
270
271 // Move to the home position
272 send_cmd3(PageAddr, 0, MatrixRows - 1);
273 send_cmd3(ColumnAddr, 0, (MatrixCols * FontWidth) - 1);
274
275 if (i2c_start_write(SSD1306_ADDRESS)) {
276 goto done;
277 }
278 if (i2c_master_write(0x40)) {
279 // Data mode
280 goto done;
281 }
282
283 for (uint8_t row = 0; row < MatrixRows; ++row) {
284 for (uint8_t col = 0; col < MatrixCols; ++col) {
285 const uint8_t *glyph = font + (matrix->display[row][col] * (FontWidth - 1));
286
287 for (uint8_t glyphCol = 0; glyphCol < FontWidth - 1; ++glyphCol) {
288 uint8_t colBits = pgm_read_byte(glyph + glyphCol);
289 i2c_master_write(colBits);
290 }
291
292 // 1 column of space between chars (it's not included in the glyph)
293 i2c_master_write(0);
294 }
295 }
296
297 matrix->dirty = false;
298
299done:
300 i2c_master_stop();
301#if DEBUG_TO_SCREEN
302 --displaying;
303#endif
304}
305
306void iota_gfx_flush(void) {
307 matrix_render(&display);
308}
309
310__attribute__ ((weak))
311void iota_gfx_task_user(void) {
312}
313
314void iota_gfx_task(void) {
315 iota_gfx_task_user();
316
317 if (display.dirty) {
318 iota_gfx_flush();
319 }
320
321 if (timer_elapsed(last_flush) > ScreenOffInterval) {
322 iota_gfx_off();
323 }
324}
325#endif
diff --git a/drivers/avr/ssd1306.h b/drivers/avr/ssd1306.h
new file mode 100644
index 000000000..df6a75359
--- /dev/null
+++ b/drivers/avr/ssd1306.h
@@ -0,0 +1,93 @@
1#ifndef SSD1306_H
2#define SSD1306_H
3
4#include <stdbool.h>
5#include <stdio.h>
6#include "pincontrol.h"
7#include "config.h"
8
9enum ssd1306_cmds {
10 DisplayOff = 0xAE,
11 DisplayOn = 0xAF,
12
13 SetContrast = 0x81,
14 DisplayAllOnResume = 0xA4,
15
16 DisplayAllOn = 0xA5,
17 NormalDisplay = 0xA6,
18 InvertDisplay = 0xA7,
19 SetDisplayOffset = 0xD3,
20 SetComPins = 0xda,
21 SetVComDetect = 0xdb,
22 SetDisplayClockDiv = 0xD5,
23 SetPreCharge = 0xd9,
24 SetMultiPlex = 0xa8,
25 SetLowColumn = 0x00,
26 SetHighColumn = 0x10,
27 SetStartLine = 0x40,
28
29 SetMemoryMode = 0x20,
30 ColumnAddr = 0x21,
31 PageAddr = 0x22,
32
33 ComScanInc = 0xc0,
34 ComScanDec = 0xc8,
35 SegRemap = 0xa0,
36 SetChargePump = 0x8d,
37 ExternalVcc = 0x01,
38 SwitchCapVcc = 0x02,
39
40 ActivateScroll = 0x2f,
41 DeActivateScroll = 0x2e,
42 SetVerticalScrollArea = 0xa3,
43 RightHorizontalScroll = 0x26,
44 LeftHorizontalScroll = 0x27,
45 VerticalAndRightHorizontalScroll = 0x29,
46 VerticalAndLeftHorizontalScroll = 0x2a,
47};
48
49// Controls the SSD1306 128x32 OLED display via i2c
50
51#ifndef SSD1306_ADDRESS
52#define SSD1306_ADDRESS 0x3C
53#endif
54
55#define DisplayHeight 32
56#define DisplayWidth 128
57
58#define FontHeight 8
59#define FontWidth 6
60
61#define MatrixRows (DisplayHeight / FontHeight)
62#define MatrixCols (DisplayWidth / FontWidth)
63
64struct CharacterMatrix {
65 uint8_t display[MatrixRows][MatrixCols];
66 uint8_t *cursor;
67 bool dirty;
68};
69
70struct CharacterMatrix display;
71
72bool iota_gfx_init(void);
73void iota_gfx_task(void);
74bool iota_gfx_off(void);
75bool iota_gfx_on(void);
76void iota_gfx_flush(void);
77void iota_gfx_write_char(uint8_t c);
78void iota_gfx_write(const char *data);
79void iota_gfx_write_P(const char *data);
80void iota_gfx_clear_screen(void);
81
82void iota_gfx_task_user(void);
83
84void matrix_clear(struct CharacterMatrix *matrix);
85void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c);
86void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c);
87void matrix_write(struct CharacterMatrix *matrix, const char *data);
88void matrix_write_P(struct CharacterMatrix *matrix, const char *data);
89void matrix_render(struct CharacterMatrix *matrix);
90
91
92
93#endif
diff --git a/drivers/avr/ws2812.c b/drivers/avr/ws2812.c
new file mode 100644
index 000000000..59e032bf7
--- /dev/null
+++ b/drivers/avr/ws2812.c
@@ -0,0 +1,342 @@
1/*
2* light weight WS2812 lib V2.0b
3*
4* Controls WS2811/WS2812/WS2812B RGB-LEDs
5* Author: Tim (cpldcpu@gmail.com)
6*
7* Jan 18th, 2014 v2.0b Initial Version
8* Nov 29th, 2015 v2.3 Added SK6812RGBW support
9*
10* This program is free software: you can redistribute it and/or modify
11* it under the terms of the GNU General Public License as published by
12* the Free Software Foundation, either version 2 of the License, or
13* (at your option) any later version.
14*
15* This program is distributed in the hope that it will be useful,
16* but WITHOUT ANY WARRANTY; without even the implied warranty of
17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18* GNU General Public License for more details.
19*
20* You should have received a copy of the GNU General Public License
21* along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/
23
24#include "ws2812.h"
25#include <avr/interrupt.h>
26#include <avr/io.h>
27#include <util/delay.h>
28#include "debug.h"
29
30#ifdef RGBW_BB_TWI
31
32// Port for the I2C
33#define I2C_DDR DDRD
34#define I2C_PIN PIND
35#define I2C_PORT PORTD
36
37// Pins to be used in the bit banging
38#define I2C_CLK 0
39#define I2C_DAT 1
40
41#define I2C_DATA_HI()\
42I2C_DDR &= ~ (1 << I2C_DAT);\
43I2C_PORT |= (1 << I2C_DAT);
44#define I2C_DATA_LO()\
45I2C_DDR |= (1 << I2C_DAT);\
46I2C_PORT &= ~ (1 << I2C_DAT);
47
48#define I2C_CLOCK_HI()\
49I2C_DDR &= ~ (1 << I2C_CLK);\
50I2C_PORT |= (1 << I2C_CLK);
51#define I2C_CLOCK_LO()\
52I2C_DDR |= (1 << I2C_CLK);\
53I2C_PORT &= ~ (1 << I2C_CLK);
54
55#define I2C_DELAY 1
56
57void I2C_WriteBit(unsigned char c)
58{
59 if (c > 0)
60 {
61 I2C_DATA_HI();
62 }
63 else
64 {
65 I2C_DATA_LO();
66 }
67
68 I2C_CLOCK_HI();
69 _delay_us(I2C_DELAY);
70
71 I2C_CLOCK_LO();
72 _delay_us(I2C_DELAY);
73
74 if (c > 0)
75 {
76 I2C_DATA_LO();
77 }
78
79 _delay_us(I2C_DELAY);
80}
81
82// Inits bitbanging port, must be called before using the functions below
83//
84void I2C_Init(void)
85{
86 I2C_PORT &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
87
88 I2C_CLOCK_HI();
89 I2C_DATA_HI();
90
91 _delay_us(I2C_DELAY);
92}
93
94// Send a START Condition
95//
96void I2C_Start(void)
97{
98 // set both to high at the same time
99 I2C_DDR &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
100 _delay_us(I2C_DELAY);
101
102 I2C_DATA_LO();
103 _delay_us(I2C_DELAY);
104
105 I2C_CLOCK_LO();
106 _delay_us(I2C_DELAY);
107}
108
109// Send a STOP Condition
110//
111void I2C_Stop(void)
112{
113 I2C_CLOCK_HI();
114 _delay_us(I2C_DELAY);
115
116 I2C_DATA_HI();
117 _delay_us(I2C_DELAY);
118}
119
120// write a byte to the I2C slave device
121//
122unsigned char I2C_Write(unsigned char c)
123{
124 for (char i = 0; i < 8; i++)
125 {
126 I2C_WriteBit(c & 128);
127
128 c <<= 1;
129 }
130
131
132 I2C_WriteBit(0);
133 _delay_us(I2C_DELAY);
134 _delay_us(I2C_DELAY);
135
136 // _delay_us(I2C_DELAY);
137 //return I2C_ReadBit();
138 return 0;
139}
140
141
142#endif
143
144// Setleds for standard RGB
145void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds)
146{
147 // ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));
148 ws2812_setleds_pin(ledarray,leds, _BV(RGB_DI_PIN & 0xF));
149}
150
151void inline ws2812_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask)
152{
153 // ws2812_DDRREG |= pinmask; // Enable DDR
154 // new universal format (DDR)
155 _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= pinmask;
156
157 ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask);
158 _delay_us(50);
159}
160
161// Setleds for SK6812RGBW
162void inline ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t leds)
163{
164
165 #ifdef RGBW_BB_TWI
166 uint8_t sreg_prev, twcr_prev;
167 sreg_prev=SREG;
168 twcr_prev=TWCR;
169 cli();
170 TWCR &= ~(1<<TWEN);
171 I2C_Init();
172 I2C_Start();
173 I2C_Write(0x84);
174 uint16_t datlen = leds<<2;
175 uint8_t curbyte;
176 uint8_t * data = (uint8_t*)ledarray;
177 while (datlen--) {
178 curbyte=*data++;
179 I2C_Write(curbyte);
180 }
181 I2C_Stop();
182 SREG=sreg_prev;
183 TWCR=twcr_prev;
184 #endif
185
186
187 // ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR
188 // new universal format (DDR)
189 _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= _BV(RGB_DI_PIN & 0xF);
190
191 ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(RGB_DI_PIN & 0xF));
192
193
194 #ifndef RGBW_BB_TWI
195 _delay_us(80);
196 #endif
197}
198
199void ws2812_sendarray(uint8_t *data,uint16_t datlen)
200{
201 ws2812_sendarray_mask(data,datlen,_BV(RGB_DI_PIN & 0xF));
202}
203
204/*
205 This routine writes an array of bytes with RGB values to the Dataout pin
206 using the fast 800kHz clockless WS2811/2812 protocol.
207*/
208
209// Timing in ns
210#define w_zeropulse 350
211#define w_onepulse 900
212#define w_totalperiod 1250
213
214// Fixed cycles used by the inner loop
215#define w_fixedlow 2
216#define w_fixedhigh 4
217#define w_fixedtotal 8
218
219// Insert NOPs to match the timing, if possible
220#define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000)
221#define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000)
222#define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000)
223
224// w1 - nops between rising edge and falling edge - low
225#define w1 (w_zerocycles-w_fixedlow)
226// w2 nops between fe low and fe high
227#define w2 (w_onecycles-w_fixedhigh-w1)
228// w3 nops to complete loop
229#define w3 (w_totalcycles-w_fixedtotal-w1-w2)
230
231#if w1>0
232 #define w1_nops w1
233#else
234 #define w1_nops 0
235#endif
236
237// The only critical timing parameter is the minimum pulse length of the "0"
238// Warn or throw error if this timing can not be met with current F_CPU settings.
239#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
240#if w_lowtime>550
241 #error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
242#elif w_lowtime>450
243 #warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
244 #warning "Please consider a higher clockspeed, if possible"
245#endif
246
247#if w2>0
248#define w2_nops w2
249#else
250#define w2_nops 0
251#endif
252
253#if w3>0
254#define w3_nops w3
255#else
256#define w3_nops 0
257#endif
258
259#define w_nop1 "nop \n\t"
260#define w_nop2 "rjmp .+0 \n\t"
261#define w_nop4 w_nop2 w_nop2
262#define w_nop8 w_nop4 w_nop4
263#define w_nop16 w_nop8 w_nop8
264
265void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi)
266{
267 uint8_t curbyte,ctr,masklo;
268 uint8_t sreg_prev;
269
270 // masklo =~maskhi&ws2812_PORTREG;
271 // maskhi |= ws2812_PORTREG;
272 masklo =~maskhi&_SFR_IO8((RGB_DI_PIN >> 4) + 2);
273 maskhi |= _SFR_IO8((RGB_DI_PIN >> 4) + 2);
274 sreg_prev=SREG;
275 cli();
276
277 while (datlen--) {
278 curbyte=(*data++);
279
280 asm volatile(
281 " ldi %0,8 \n\t"
282 "loop%=: \n\t"
283 " out %2,%3 \n\t" // '1' [01] '0' [01] - re
284#if (w1_nops&1)
285w_nop1
286#endif
287#if (w1_nops&2)
288w_nop2
289#endif
290#if (w1_nops&4)
291w_nop4
292#endif
293#if (w1_nops&8)
294w_nop8
295#endif
296#if (w1_nops&16)
297w_nop16
298#endif
299 " sbrs %1,7 \n\t" // '1' [03] '0' [02]
300 " out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low
301 " lsl %1 \n\t" // '1' [04] '0' [04]
302#if (w2_nops&1)
303 w_nop1
304#endif
305#if (w2_nops&2)
306 w_nop2
307#endif
308#if (w2_nops&4)
309 w_nop4
310#endif
311#if (w2_nops&8)
312 w_nop8
313#endif
314#if (w2_nops&16)
315 w_nop16
316#endif
317 " out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high
318#if (w3_nops&1)
319w_nop1
320#endif
321#if (w3_nops&2)
322w_nop2
323#endif
324#if (w3_nops&4)
325w_nop4
326#endif
327#if (w3_nops&8)
328w_nop8
329#endif
330#if (w3_nops&16)
331w_nop16
332#endif
333
334 " dec %0 \n\t" // '1' [+2] '0' [+2]
335 " brne loop%=\n\t" // '1' [+3] '0' [+4]
336 : "=&d" (ctr)
337 : "r" (curbyte), "I" (_SFR_IO_ADDR(_SFR_IO8((RGB_DI_PIN >> 4) + 2))), "r" (maskhi), "r" (masklo)
338 );
339 }
340
341 SREG=sreg_prev;
342}
diff --git a/drivers/avr/ws2812.h b/drivers/avr/ws2812.h
new file mode 100644
index 000000000..f7e0c3144
--- /dev/null
+++ b/drivers/avr/ws2812.h
@@ -0,0 +1,75 @@
1/*
2 * light weight WS2812 lib include
3 *
4 * Version 2.3 - Nev 29th 2015
5 * Author: Tim (cpldcpu@gmail.com)
6 *
7 * Please do not change this file! All configuration is handled in "ws2812_config.h"
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#ifndef LIGHT_WS2812_H_
24#define LIGHT_WS2812_H_
25
26#include <avr/io.h>
27#include <avr/interrupt.h>
28//#include "ws2812_config.h"
29//#include "i2cmaster.h"
30
31#include "rgblight_types.h"
32
33
34/* User Interface
35 *
36 * Input:
37 * ledarray: An array of GRB data describing the LED colors
38 * number_of_leds: The number of LEDs to write
39 * pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0)
40 *
41 * The functions will perform the following actions:
42 * - Set the data-out pin as output
43 * - Send out the LED data
44 * - Wait 50�s to reset the LEDs
45 */
46
47void ws2812_setleds (LED_TYPE *ledarray, uint16_t number_of_leds);
48void ws2812_setleds_pin (LED_TYPE *ledarray, uint16_t number_of_leds,uint8_t pinmask);
49void ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds);
50
51/*
52 * Old interface / Internal functions
53 *
54 * The functions take a byte-array and send to the data output as WS2812 bitstream.
55 * The length is the number of bytes to send - three per LED.
56 */
57
58void ws2812_sendarray (uint8_t *array,uint16_t length);
59void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask);
60
61
62/*
63 * Internal defines
64 */
65#ifndef CONCAT
66#define CONCAT(a, b) a ## b
67#endif
68#ifndef CONCAT_EXP
69#define CONCAT_EXP(a, b) CONCAT(a, b)
70#endif
71
72// #define ws2812_PORTREG CONCAT_EXP(PORT,ws2812_port)
73// #define ws2812_DDRREG CONCAT_EXP(DDR,ws2812_port)
74
75#endif /* LIGHT_WS2812_H_ */
diff --git a/drivers/ugfx/gdisp/is31fl3731c/board_is31fl3731c_template.h b/drivers/ugfx/gdisp/is31fl3731c/board_is31fl3731c_template.h
new file mode 100644
index 000000000..f248cc25b
--- /dev/null
+++ b/drivers/ugfx/gdisp/is31fl3731c/board_is31fl3731c_template.h
@@ -0,0 +1,110 @@
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
25static const uint8_t led_mask[] = {
26 0xFF, 0x00, /* C1-1 -> C1-16 */
27 0xFF, 0x00, /* C2-1 -> C2-16 */
28 0xFF, 0x00, /* C3-1 -> C3-16 */
29 0xFF, 0x00, /* C4-1 -> C4-16 */
30 0x3F, 0x00, /* C5-1 -> C5-16 */
31 0x00, 0x00, /* C6-1 -> C6-16 */
32 0x00, 0x00, /* C7-1 -> C7-16 */
33 0x00, 0x00, /* C8-1 -> C8-16 */
34 0x00, 0x00, /* C9-1 -> C9-16 */
35};
36
37// The address of the LED
38#define LA(c, r) (c + r * 16 )
39// Need to be an address that is not mapped, but inside the range of the controller matrix
40#define NA LA(8, 8)
41
42// The numbers in the comments are the led numbers DXX on the PCB
43// The mapping is taken from the schematic of left hand side
44static const uint8_t led_mapping[GDISP_SCREEN_HEIGHT][GDISP_SCREEN_WIDTH] = {
45// 45 44 43 42 41 40 39
46 { LA(1, 1), LA(1, 0), LA(0, 4), LA(0, 3), LA(0, 2), LA(0, 1), LA(0, 0)},
47// 52 51 50 49 48 47 46
48 { LA(2, 3), LA(2, 2), LA(2, 1), LA(2, 0), LA(1, 4), LA(1, 3), LA(1, 2) },
49// 58 57 56 55 54 53 N/A
50 { LA(3, 4), LA(3, 3), LA(3, 2), LA(3, 1), LA(3, 0), LA(2, 4), NA },
51// 67 66 65 64 63 62 61
52 { LA(5, 3), LA(5, 2), LA(5, 1), LA(5, 0), LA(4, 4), LA(4, 3), LA(4, 2) },
53// 76 75 74 73 72 60 59
54 { LA(7, 3), LA(7, 2), LA(7, 1), LA(7, 0), LA(6, 3), LA(4, 1), LA(4, 0) },
55// N/A N/A N/A N/A N/A N/A 68
56 { NA, NA, NA, NA, NA, NA, LA(5, 4) },
57// N/A N/A N/A N/A 71 70 69
58 { NA, NA, NA, NA, LA(6, 2), LA(6, 1), LA(6, 0) },
59};
60
61
62#define IS31_ADDR_DEFAULT 0x74 // AD connected to GND
63#define IS31_TIMEOUT 5000
64
65static GFXINLINE void init_board(GDisplay *g) {
66 (void) g;
67 /* I2C pins */
68 palSetPadMode(GPIOB, 0, PAL_MODE_ALTERNATIVE_2); // PTB0/I2C0/SCL
69 palSetPadMode(GPIOB, 1, PAL_MODE_ALTERNATIVE_2); // PTB1/I2C0/SDA
70 palSetPadMode(GPIOB, 16, PAL_MODE_OUTPUT_PUSHPULL);
71 palClearPad(GPIOB, 16);
72 /* start I2C */
73 i2cStart(&I2CD1, &i2ccfg);
74 // try high drive (from kiibohd)
75 I2CD1.i2c->C2 |= I2Cx_C2_HDRS;
76 // try glitch fixing (from kiibohd)
77 I2CD1.i2c->FLT = 4;
78}
79
80static GFXINLINE void post_init_board(GDisplay *g) {
81 (void) g;
82}
83
84static GFXINLINE const uint8_t* get_led_mask(GDisplay* g) {
85 (void) g;
86 return led_mask;
87}
88
89static GFXINLINE uint8_t get_led_address(GDisplay* g, uint16_t x, uint16_t y)
90{
91 (void) g;
92 return led_mapping[y][x];
93}
94
95static GFXINLINE void set_hardware_shutdown(GDisplay* g, bool shutdown) {
96 (void) g;
97 if(!shutdown) {
98 palSetPad(GPIOB, 16);
99 }
100 else {
101 palClearPad(GPIOB, 16);
102 }
103}
104
105static GFXINLINE void write_data(GDisplay *g, uint8_t* data, uint16_t length) {
106 (void) g;
107 i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, data, length, 0, 0, US2ST(IS31_TIMEOUT));
108}
109
110#endif /* _GDISP_LLD_BOARD_H */
diff --git a/drivers/ugfx/gdisp/is31fl3731c/driver.mk b/drivers/ugfx/gdisp/is31fl3731c/driver.mk
new file mode 100644
index 000000000..4364787c9
--- /dev/null
+++ b/drivers/ugfx/gdisp/is31fl3731c/driver.mk
@@ -0,0 +1,3 @@
1GFXINC += drivers/ugfx/gdisp/is31fl3731c
2GFXSRC += drivers/ugfx/gdisp/is31fl3731c/gdisp_is31fl3731c.c
3GDISP_DRIVER_LIST += GDISPVMT_IS31FL3731C_QMK \ No newline at end of file
diff --git a/drivers/ugfx/gdisp/is31fl3731c/gdisp_is31fl3731c.c b/drivers/ugfx/gdisp/is31fl3731c/gdisp_is31fl3731c.c
new file mode 100644
index 000000000..917adadb8
--- /dev/null
+++ b/drivers/ugfx/gdisp/is31fl3731c/gdisp_is31fl3731c.c
@@ -0,0 +1,308 @@
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_QMK
23#define GDISP_SCREEN_HEIGHT LED_HEIGHT
24#define GDISP_SCREEN_WIDTH LED_WIDTH
25
26#include "gdisp_lld_config.h"
27#include "src/gdisp/gdisp_driver.h"
28
29#include "board_is31fl3731c.h"
30
31
32// Can't include led_tables from here
33extern const uint8_t CIE1931_CURVE[];
34
35/*===========================================================================*/
36/* Driver local definitions. */
37/*===========================================================================*/
38
39#ifndef GDISP_INITIAL_CONTRAST
40 #define GDISP_INITIAL_CONTRAST 0
41#endif
42#ifndef GDISP_INITIAL_BACKLIGHT
43 #define GDISP_INITIAL_BACKLIGHT 0
44#endif
45
46#define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0)
47
48#define IS31_ADDR_DEFAULT 0x74
49
50#define IS31_REG_CONFIG 0x00
51// bits in reg
52#define IS31_REG_CONFIG_PICTUREMODE 0x00
53#define IS31_REG_CONFIG_AUTOPLAYMODE 0x08
54#define IS31_REG_CONFIG_AUDIOPLAYMODE 0x18
55// D2:D0 bits are starting frame for autoplay mode
56
57#define IS31_REG_PICTDISP 0x01 // D2:D0 frame select for picture mode
58
59#define IS31_REG_AUTOPLAYCTRL1 0x02
60// D6:D4 number of loops (000=infty)
61// D2:D0 number of frames to be used
62
63#define IS31_REG_AUTOPLAYCTRL2 0x03 // D5:D0 delay time (*11ms)
64
65#define IS31_REG_DISPLAYOPT 0x05
66#define IS31_REG_DISPLAYOPT_INTENSITY_SAME 0x20 // same intensity for all frames
67#define IS31_REG_DISPLAYOPT_BLINK_ENABLE 0x8
68// D2:D0 bits blink period time (*0.27s)
69
70#define IS31_REG_AUDIOSYNC 0x06
71#define IS31_REG_AUDIOSYNC_ENABLE 0x1
72
73#define IS31_REG_FRAMESTATE 0x07
74
75#define IS31_REG_BREATHCTRL1 0x08
76// D6:D4 fade out time (26ms*2^i)
77// D2:D0 fade in time (26ms*2^i)
78
79#define IS31_REG_BREATHCTRL2 0x09
80#define IS31_REG_BREATHCTRL2_ENABLE 0x10
81// D2:D0 extinguish time (3.5ms*2^i)
82
83#define IS31_REG_SHUTDOWN 0x0A
84#define IS31_REG_SHUTDOWN_OFF 0x0
85#define IS31_REG_SHUTDOWN_ON 0x1
86
87#define IS31_REG_AGCCTRL 0x0B
88#define IS31_REG_ADCRATE 0x0C
89
90#define IS31_COMMANDREGISTER 0xFD
91#define IS31_FUNCTIONREG 0x0B // helpfully called 'page nine'
92#define IS31_FUNCTIONREG_SIZE 0xD
93
94#define IS31_FRAME_SIZE 0xB4
95
96#define IS31_PWM_REG 0x24
97#define IS31_PWM_SIZE 0x90
98
99#define IS31_LED_MASK_SIZE 0x12
100
101#define IS31
102
103/*===========================================================================*/
104/* Driver local functions. */
105/*===========================================================================*/
106
107typedef struct{
108 uint8_t write_buffer_offset;
109 uint8_t write_buffer[IS31_FRAME_SIZE];
110 uint8_t frame_buffer[GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH];
111 uint8_t page;
112}__attribute__((__packed__)) PrivData;
113
114// Some common routines and macros
115#define PRIV(g) ((PrivData*)g->priv)
116
117/*===========================================================================*/
118/* Driver exported functions. */
119/*===========================================================================*/
120
121static GFXINLINE void write_page(GDisplay* g, uint8_t page) {
122 uint8_t tx[2] __attribute__((aligned(2)));
123 tx[0] = IS31_COMMANDREGISTER;
124 tx[1] = page;
125 write_data(g, tx, 2);
126}
127
128static GFXINLINE void write_register(GDisplay* g, uint8_t page, uint8_t reg, uint8_t data) {
129 uint8_t tx[2] __attribute__((aligned(2)));
130 tx[0] = reg;
131 tx[1] = data;
132 write_page(g, page);
133 write_data(g, tx, 2);
134}
135
136static GFXINLINE void write_ram(GDisplay *g, uint8_t page, uint16_t offset, uint16_t length) {
137 PRIV(g)->write_buffer_offset = offset;
138 write_page(g, page);
139 write_data(g, (uint8_t*)PRIV(g), length + 1);
140}
141
142LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
143 // The private area is the display surface.
144 g->priv = gfxAlloc(sizeof(PrivData));
145 __builtin_memset(PRIV(g), 0, sizeof(PrivData));
146 PRIV(g)->page = 0;
147
148 // Initialise the board interface
149 init_board(g);
150 gfxSleepMilliseconds(10);
151
152 // zero function page, all registers (assuming full_page is all zeroes)
153 write_ram(g, IS31_FUNCTIONREG, 0, IS31_FUNCTIONREG_SIZE);
154 set_hardware_shutdown(g, false);
155 gfxSleepMilliseconds(10);
156 // software shutdown
157 write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
158 gfxSleepMilliseconds(10);
159 // zero function page, all registers
160 write_ram(g, IS31_FUNCTIONREG, 0, IS31_FUNCTIONREG_SIZE);
161 gfxSleepMilliseconds(10);
162
163
164 // zero all LED registers on all 8 pages, and enable the mask
165 __builtin_memcpy(PRIV(g)->write_buffer, get_led_mask(g), IS31_LED_MASK_SIZE);
166 for(uint8_t i=0; i<8; i++) {
167 write_ram(g, i, 0, IS31_FRAME_SIZE);
168 gfxSleepMilliseconds(1);
169 }
170
171 // software shutdown disable (i.e. turn stuff on)
172 write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
173 gfxSleepMilliseconds(10);
174
175 // Finish Init
176 post_init_board(g);
177
178 /* Initialise the GDISP structure */
179 g->g.Width = GDISP_SCREEN_WIDTH;
180 g->g.Height = GDISP_SCREEN_HEIGHT;
181 g->g.Orientation = GDISP_ROTATE_0;
182 g->g.Powermode = powerOff;
183 g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
184 g->g.Contrast = GDISP_INITIAL_CONTRAST;
185 return TRUE;
186}
187
188#if GDISP_HARDWARE_FLUSH
189 LLDSPEC void gdisp_lld_flush(GDisplay *g) {
190 // Don't flush if we don't need it.
191 if (!(g->flags & GDISP_FLG_NEEDFLUSH))
192 return;
193
194 PRIV(g)->page++;
195 PRIV(g)->page %= 2;
196 // TODO: some smarter algorithm for this
197 // We should run only one physical page at a time
198 // This way we don't need to send so much data, and
199 // we could use slightly less memory
200 uint8_t* src = PRIV(g)->frame_buffer;
201 for (int y=0;y<GDISP_SCREEN_HEIGHT;y++) {
202 for (int x=0;x<GDISP_SCREEN_WIDTH;x++) {
203 uint8_t val = (uint16_t)*src * g->g.Backlight / 100;
204 PRIV(g)->write_buffer[get_led_address(g, x, y)]=CIE1931_CURVE[val];
205 ++src;
206 }
207 }
208 write_ram(g, PRIV(g)->page, IS31_PWM_REG, IS31_PWM_SIZE);
209 gfxSleepMilliseconds(1);
210 write_register(g, IS31_FUNCTIONREG, IS31_REG_PICTDISP, PRIV(g)->page);
211
212 g->flags &= ~GDISP_FLG_NEEDFLUSH;
213 }
214#endif
215
216#if GDISP_HARDWARE_DRAWPIXEL
217 LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
218 coord_t x, y;
219
220 switch(g->g.Orientation) {
221 default:
222 case GDISP_ROTATE_0:
223 x = g->p.x;
224 y = g->p.y;
225 break;
226 case GDISP_ROTATE_180:
227 x = GDISP_SCREEN_WIDTH-1 - g->p.x;
228 y = g->p.y;
229 break;
230 }
231 PRIV(g)->frame_buffer[y * GDISP_SCREEN_WIDTH + x] = gdispColor2Native(g->p.color);
232 g->flags |= GDISP_FLG_NEEDFLUSH;
233 }
234#endif
235
236#if GDISP_HARDWARE_PIXELREAD
237 LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
238 coord_t x, y;
239
240 switch(g->g.Orientation) {
241 default:
242 case GDISP_ROTATE_0:
243 x = g->p.x;
244 y = g->p.y;
245 break;
246 case GDISP_ROTATE_180:
247 x = GDISP_SCREEN_WIDTH-1 - g->p.x;
248 y = g->p.y;
249 break;
250 }
251 return gdispNative2Color(PRIV(g)->frame_buffer[y * GDISP_SCREEN_WIDTH + x]);
252 }
253#endif
254
255#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
256 LLDSPEC void gdisp_lld_control(GDisplay *g) {
257 switch(g->p.x) {
258 case GDISP_CONTROL_POWER:
259 if (g->g.Powermode == (powermode_t)g->p.ptr)
260 return;
261 switch((powermode_t)g->p.ptr) {
262 case powerOff:
263 case powerSleep:
264 case powerDeepSleep:
265 write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
266 break;
267 case powerOn:
268 write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON);
269 break;
270 default:
271 return;
272 }
273 g->g.Powermode = (powermode_t)g->p.ptr;
274 return;
275
276 case GDISP_CONTROL_ORIENTATION:
277 if (g->g.Orientation == (orientation_t)g->p.ptr)
278 return;
279 switch((orientation_t)g->p.ptr) {
280 /* Rotation is handled by the drawing routines */
281 case GDISP_ROTATE_0:
282 case GDISP_ROTATE_180:
283 g->g.Height = GDISP_SCREEN_HEIGHT;
284 g->g.Width = GDISP_SCREEN_WIDTH;
285 break;
286 case GDISP_ROTATE_90:
287 case GDISP_ROTATE_270:
288 g->g.Height = GDISP_SCREEN_WIDTH;
289 g->g.Width = GDISP_SCREEN_HEIGHT;
290 break;
291 default:
292 return;
293 }
294 g->g.Orientation = (orientation_t)g->p.ptr;
295 return;
296
297 case GDISP_CONTROL_BACKLIGHT:
298 if (g->g.Backlight == (unsigned)g->p.ptr)
299 return;
300 unsigned val = (unsigned)g->p.ptr;
301 g->g.Backlight = val > 100 ? 100 : val;
302 g->flags |= GDISP_FLG_NEEDFLUSH;
303 return;
304 }
305 }
306#endif // GDISP_NEED_CONTROL
307
308#endif // GFX_USE_GDISP
diff --git a/drivers/ugfx/gdisp/is31fl3731c/gdisp_lld_config.h b/drivers/ugfx/gdisp/is31fl3731c/gdisp_lld_config.h
new file mode 100644
index 000000000..588d688cf
--- /dev/null
+++ b/drivers/ugfx/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/drivers/ugfx/gdisp/st7565/board_st7565_template.h b/drivers/ugfx/gdisp/st7565/board_st7565_template.h
new file mode 100644
index 000000000..9ab636c95
--- /dev/null
+++ b/drivers/ugfx/gdisp/st7565/board_st7565_template.h
@@ -0,0 +1,113 @@
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#define ST7565_LCD_BIAS ST7565_LCD_BIAS_9 // actually 6
12#define ST7565_ADC ST7565_ADC_NORMAL
13#define ST7565_COM_SCAN ST7565_COM_SCAN_DEC
14#define ST7565_PAGE_ORDER 0,1,2,3
15/*
16 * Custom page order for several LCD boards, e.g. HEM12864-99
17 * #define ST7565_PAGE_ORDER 4,5,6,7,0,1,2,3
18 */
19
20#define ST7565_GPIOPORT GPIOC
21#define ST7565_PORT PORTC
22#define ST7565_A0_PIN 7
23#define ST7565_RST_PIN 8
24#define ST7565_MOSI_PIN 6
25#define ST7565_SLCK_PIN 5
26#define ST7565_SS_PIN 4
27
28#define palSetPadModeRaw(portname, bits) \
29 ST7565_PORT->PCR[ST7565_##portname##_PIN] = bits
30
31#define palSetPadModeNamed(portname, portmode) \
32 palSetPadMode(ST7565_GPIOPORT, ST7565_##portname##_PIN, portmode)
33
34#define ST7565_SPI_MODE PORTx_PCRn_DSE | PORTx_PCRn_MUX(2)
35// DSPI Clock and Transfer Attributes
36// Frame Size: 8 bits
37// MSB First
38// CLK Low by default
39static const SPIConfig spi1config = {
40 // Operation complete callback or @p NULL.
41 .end_cb = NULL,
42 //The chip select line port - when not using pcs.
43 .ssport = ST7565_GPIOPORT,
44 // brief The chip select line pad number - when not using pcs.
45 .sspad=ST7565_SS_PIN,
46 // SPI initialization data.
47 .tar0 =
48 SPIx_CTARn_FMSZ(7) // Frame size = 8 bytes
49 | SPIx_CTARn_ASC(1) // After SCK Delay Scaler (min 50 ns) = 55.56ns
50 | SPIx_CTARn_DT(0) // Delay After Transfer Scaler (no minimum)= 27.78ns
51 | SPIx_CTARn_CSSCK(0) // PCS to SCK Delay Scaler (min 20 ns) = 27.78ns
52 | SPIx_CTARn_PBR(0) // Baud Rate Prescaler = 2
53 | SPIx_CTARn_BR(0) // Baud rate (min 50ns) = 55.56ns
54};
55
56static GFXINLINE void acquire_bus(GDisplay *g) {
57 (void) g;
58 // Only the LCD is using the SPI bus, so no need to acquire
59 // spiAcquireBus(&SPID1);
60 spiSelect(&SPID1);
61}
62
63static GFXINLINE void release_bus(GDisplay *g) {
64 (void) g;
65 // Only the LCD is using the SPI bus, so no need to release
66 //spiReleaseBus(&SPID1);
67 spiUnselect(&SPID1);
68}
69
70static GFXINLINE void init_board(GDisplay *g) {
71 (void) g;
72 palSetPadModeNamed(A0, PAL_MODE_OUTPUT_PUSHPULL);
73 palSetPad(ST7565_GPIOPORT, ST7565_A0_PIN);
74 palSetPadModeNamed(RST, PAL_MODE_OUTPUT_PUSHPULL);
75 palSetPad(ST7565_GPIOPORT, ST7565_RST_PIN);
76 palSetPadModeRaw(MOSI, ST7565_SPI_MODE);
77 palSetPadModeRaw(SLCK, ST7565_SPI_MODE);
78 palSetPadModeNamed(SS, PAL_MODE_OUTPUT_PUSHPULL);
79
80 spiInit();
81 spiStart(&SPID1, &spi1config);
82 release_bus(g);
83}
84
85static GFXINLINE void post_init_board(GDisplay *g) {
86 (void) g;
87}
88
89static GFXINLINE void setpin_reset(GDisplay *g, bool_t state) {
90 (void) g;
91 if (state) {
92 palClearPad(ST7565_GPIOPORT, ST7565_RST_PIN);
93 }
94 else {
95 palSetPad(ST7565_GPIOPORT, ST7565_RST_PIN);
96 }
97}
98
99static GFXINLINE void enter_data_mode(GDisplay *g) {
100 palSetPad(ST7565_GPIOPORT, ST7565_A0_PIN);
101}
102
103static GFXINLINE void enter_cmd_mode(GDisplay *g) {
104 palClearPad(ST7565_GPIOPORT, ST7565_A0_PIN);
105}
106
107
108static GFXINLINE void write_data(GDisplay *g, uint8_t* data, uint16_t length) {
109 (void) g;
110 spiSend(&SPID1, length, data);
111}
112
113#endif /* _GDISP_LLD_BOARD_H */
diff --git a/drivers/ugfx/gdisp/st7565/driver.mk b/drivers/ugfx/gdisp/st7565/driver.mk
new file mode 100644
index 000000000..31fc8f1c7
--- /dev/null
+++ b/drivers/ugfx/gdisp/st7565/driver.mk
@@ -0,0 +1,3 @@
1GFXINC += drivers/ugfx/gdisp/st7565
2GFXSRC += drivers/ugfx/gdisp/st7565/gdisp_lld_ST7565.c
3GDISP_DRIVER_LIST += GDISPVMT_ST7565_QMK \ No newline at end of file
diff --git a/drivers/ugfx/gdisp/st7565/gdisp_lld_ST7565.c b/drivers/ugfx/gdisp/st7565/gdisp_lld_ST7565.c
new file mode 100644
index 000000000..c38194b06
--- /dev/null
+++ b/drivers/ugfx/gdisp/st7565/gdisp_lld_ST7565.c
@@ -0,0 +1,329 @@
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_QMK
13#include "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 LCD_HEIGHT
24#endif
25#ifndef GDISP_SCREEN_WIDTH
26#define GDISP_SCREEN_WIDTH LCD_WIDTH
27#endif
28#ifndef GDISP_INITIAL_CONTRAST
29#define GDISP_INITIAL_CONTRAST 35
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 "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 data_pos;
62 uint8_t data[16];
63 uint8_t ram[GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH / 8];
64}PrivData;
65
66// Some common routines and macros
67#define PRIV(g) ((PrivData*)g->priv)
68#define RAM(g) (PRIV(g)->ram)
69
70static GFXINLINE void write_cmd(GDisplay* g, uint8_t cmd) {
71 PRIV(g)->data[PRIV(g)->data_pos++] = cmd;
72}
73
74static GFXINLINE void flush_cmd(GDisplay* g) {
75 write_data(g, PRIV(g)->data, PRIV(g)->data_pos);
76 PRIV(g)->data_pos = 0;
77}
78
79#define write_cmd2(g, cmd1, cmd2) { write_cmd(g, cmd1); write_cmd(g, cmd2); }
80#define write_cmd3(g, cmd1, cmd2, cmd3) { write_cmd(g, cmd1); write_cmd(g, cmd2); write_cmd(g, cmd3); }
81
82// Some common routines and macros
83#define delay(us) gfxSleepMicroseconds(us)
84#define delay_ms(ms) gfxSleepMilliseconds(ms)
85
86#define xyaddr(x, y) ((x) + ((y)>>3)*GDISP_SCREEN_WIDTH)
87#define xybit(y) (1<<((y)&7))
88
89/*===========================================================================*/
90/* Driver exported functions. */
91/*===========================================================================*/
92
93/*
94 * As this controller can't update on a pixel boundary we need to maintain the
95 * the entire display surface in memory so that we can do the necessary bit
96 * operations. Fortunately it is a small display in monochrome.
97 * 64 * 128 / 8 = 1024 bytes.
98 */
99
100LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
101 // The private area is the display surface.
102 g->priv = gfxAlloc(sizeof(PrivData));
103 PRIV(g)->buffer2 = false;
104 PRIV(g)->data_pos = 0;
105
106 // Initialise the board interface
107 init_board(g);
108
109 // Hardware reset
110 setpin_reset(g, TRUE);
111 gfxSleepMilliseconds(20);
112 setpin_reset(g, FALSE);
113 gfxSleepMilliseconds(20);
114 acquire_bus(g);
115 enter_cmd_mode(g);
116
117 write_cmd(g, ST7565_RESET);
118 write_cmd(g, ST7565_LCD_BIAS);
119 write_cmd(g, ST7565_ADC);
120 write_cmd(g, ST7565_COM_SCAN);
121
122 write_cmd(g, ST7565_RESISTOR_RATIO | 0x1);
123 write_cmd2(g, ST7565_CONTRAST, GDISP_INITIAL_CONTRAST);
124
125 // turn on internal power supply (VC=1, VR=1, VF=1)
126 write_cmd(g, ST7565_POWER_CONTROL | 0x07);
127
128 write_cmd(g, ST7565_INVERT_DISPLAY);
129 write_cmd(g, ST7565_ALLON_NORMAL);
130
131 write_cmd(g, ST7565_START_LINE | 0);
132 write_cmd(g, ST7565_RMW);
133 flush_cmd(g);
134
135 // Finish Init
136 post_init_board(g);
137
138 // Release the bus
139 release_bus(g);
140
141 /* Initialise the GDISP structure */
142 g->g.Width = GDISP_SCREEN_WIDTH;
143 g->g.Height = GDISP_SCREEN_HEIGHT;
144 g->g.Orientation = GDISP_ROTATE_0;
145 g->g.Powermode = powerOff;
146 g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
147 g->g.Contrast = GDISP_INITIAL_CONTRAST;
148 return TRUE;
149}
150
151#if GDISP_HARDWARE_FLUSH
152LLDSPEC void gdisp_lld_flush(GDisplay *g) {
153 unsigned p;
154
155 // Don't flush if we don't need it.
156 if (!(g->flags & GDISP_FLG_NEEDFLUSH))
157 return;
158
159 acquire_bus(g);
160 enter_cmd_mode(g);
161 unsigned dstOffset = (PRIV(g)->buffer2 ? 4 : 0);
162 for (p = 0; p < 4; p++) {
163 write_cmd(g, ST7565_PAGE | (p + dstOffset));
164 write_cmd(g, ST7565_COLUMN_MSB | 0);
165 write_cmd(g, ST7565_COLUMN_LSB | 0);
166 write_cmd(g, ST7565_RMW);
167 flush_cmd(g);
168 enter_data_mode(g);
169 write_data(g, RAM(g) + (p*GDISP_SCREEN_WIDTH), GDISP_SCREEN_WIDTH);
170 enter_cmd_mode(g);
171 }
172 unsigned line = (PRIV(g)->buffer2 ? 32 : 0);
173 write_cmd(g, ST7565_START_LINE | line);
174 flush_cmd(g);
175 PRIV(g)->buffer2 = !PRIV(g)->buffer2;
176 release_bus(g);
177
178 g->flags &= ~GDISP_FLG_NEEDFLUSH;
179}
180#endif
181
182#if GDISP_HARDWARE_DRAWPIXEL
183LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
184 coord_t x, y;
185
186 switch(g->g.Orientation) {
187 default:
188 case GDISP_ROTATE_0:
189 x = g->p.x;
190 y = g->p.y;
191 break;
192 case GDISP_ROTATE_90:
193 x = g->p.y;
194 y = GDISP_SCREEN_HEIGHT-1 - g->p.x;
195 break;
196 case GDISP_ROTATE_180:
197 x = GDISP_SCREEN_WIDTH-1 - g->p.x;
198 y = GDISP_SCREEN_HEIGHT-1 - g->p.y;
199 break;
200 case GDISP_ROTATE_270:
201 x = GDISP_SCREEN_HEIGHT-1 - g->p.y;
202 y = g->p.x;
203 break;
204 }
205 if (gdispColor2Native(g->p.color) != Black)
206 RAM(g)[xyaddr(x, y)] |= xybit(y);
207 else
208 RAM(g)[xyaddr(x, y)] &= ~xybit(y);
209 g->flags |= GDISP_FLG_NEEDFLUSH;
210}
211#endif
212
213#if GDISP_HARDWARE_PIXELREAD
214LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
215 coord_t x, y;
216
217 switch(g->g.Orientation) {
218 default:
219 case GDISP_ROTATE_0:
220 x = g->p.x;
221 y = g->p.y;
222 break;
223 case GDISP_ROTATE_90:
224 x = g->p.y;
225 y = GDISP_SCREEN_HEIGHT-1 - g->p.x;
226 break;
227 case GDISP_ROTATE_180:
228 x = GDISP_SCREEN_WIDTH-1 - g->p.x;
229 y = GDISP_SCREEN_HEIGHT-1 - g->p.y;
230 break;
231 case GDISP_ROTATE_270:
232 x = GDISP_SCREEN_HEIGHT-1 - g->p.y;
233 y = g->p.x;
234 break;
235 }
236 return (RAM(g)[xyaddr(x, y)] & xybit(y)) ? White : Black;
237}
238#endif
239
240LLDSPEC void gdisp_lld_blit_area(GDisplay *g) {
241 uint8_t* buffer = (uint8_t*)g->p.ptr;
242 int linelength = g->p.cx;
243 for (int i = 0; i < g->p.cy; i++) {
244 unsigned dstx = g->p.x;
245 unsigned dsty = g->p.y + i;
246 unsigned srcx = g->p.x1;
247 unsigned srcy = g->p.y1 + i;
248 unsigned srcbit = srcy * g->p.x2 + srcx;
249 for(int j=0; j < linelength; j++) {
250 uint8_t src = buffer[srcbit / 8];
251 uint8_t bit = 7-(srcbit % 8);
252 uint8_t bitset = (src >> bit) & 1;
253 uint8_t* dst = &(RAM(g)[xyaddr(dstx, dsty)]);
254 if (bitset) {
255 *dst |= xybit(dsty);
256 }
257 else {
258 *dst &= ~xybit(dsty);
259 }
260 dstx++;
261 srcbit++;
262 }
263 }
264 g->flags |= GDISP_FLG_NEEDFLUSH;
265}
266
267#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
268LLDSPEC void gdisp_lld_control(GDisplay *g) {
269 switch(g->p.x) {
270 case GDISP_CONTROL_POWER:
271 if (g->g.Powermode == (powermode_t)g->p.ptr)
272 return;
273 switch((powermode_t)g->p.ptr) {
274 case powerOff:
275 case powerSleep:
276 case powerDeepSleep:
277 acquire_bus(g);
278 enter_cmd_mode(g);
279 write_cmd(g, ST7565_DISPLAY_OFF);
280 flush_cmd(g);
281 release_bus(g);
282 break;
283 case powerOn:
284 acquire_bus(g);
285 enter_cmd_mode(g);
286 write_cmd(g, ST7565_DISPLAY_ON);
287 flush_cmd(g);
288 release_bus(g);
289 break;
290 default:
291 return;
292 }
293 g->g.Powermode = (powermode_t)g->p.ptr;
294 return;
295
296 case GDISP_CONTROL_ORIENTATION:
297 if (g->g.Orientation == (orientation_t)g->p.ptr)
298 return;
299 switch((orientation_t)g->p.ptr) {
300 /* Rotation is handled by the drawing routines */
301 case GDISP_ROTATE_0:
302 case GDISP_ROTATE_180:
303 g->g.Height = GDISP_SCREEN_HEIGHT;
304 g->g.Width = GDISP_SCREEN_WIDTH;
305 break;
306 case GDISP_ROTATE_90:
307 case GDISP_ROTATE_270:
308 g->g.Height = GDISP_SCREEN_WIDTH;
309 g->g.Width = GDISP_SCREEN_HEIGHT;
310 break;
311 default:
312 return;
313 }
314 g->g.Orientation = (orientation_t)g->p.ptr;
315 return;
316
317 case GDISP_CONTROL_CONTRAST:
318 g->g.Contrast = (unsigned)g->p.ptr & 63;
319 acquire_bus(g);
320 enter_cmd_mode(g);
321 write_cmd2(g, ST7565_CONTRAST, g->g.Contrast);
322 flush_cmd(g);
323 release_bus(g);
324 return;
325 }
326}
327#endif // GDISP_NEED_CONTROL
328
329#endif // GFX_USE_GDISP
diff --git a/drivers/ugfx/gdisp/st7565/gdisp_lld_config.h b/drivers/ugfx/gdisp/st7565/gdisp_lld_config.h
new file mode 100644
index 000000000..4446bd38b
--- /dev/null
+++ b/drivers/ugfx/gdisp/st7565/gdisp_lld_config.h
@@ -0,0 +1,27 @@
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#define GDISP_HARDWARE_BITFILLS TRUE
22
23#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO
24
25#endif /* GFX_USE_GDISP */
26
27#endif /* _GDISP_LLD_CONFIG_H */
diff --git a/drivers/ugfx/gdisp/st7565/st7565.h b/drivers/ugfx/gdisp/st7565/st7565.h
new file mode 100644
index 000000000..24924ff05
--- /dev/null
+++ b/drivers/ugfx/gdisp/st7565/st7565.h
@@ -0,0 +1,39 @@
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#define ST7565_RESET 0xE2
38
39#endif /* _ST7565_H */