SSD1306 OLED display driver 1.7.8 This library is developed to control SSD1306/SSD1331/SSD1351/IL9163/PCD8554 RGB i2c/spi LED displays

vga96x40.c
1 /*
2 MIT License
3
4 Copyright (c) 2018, Alexey Dynda
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24
25 #include "intf/vga/vga.h"
26 // Never include vga96x40_isr.h here!!!
27 #include "intf/ssd1306_interface.h"
28 #include "lcd/lcd_common.h"
29 #include "lcd/vga_commands.h"
30
31 #if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(__AVR_ATmega328P__)
32
33 extern uint16_t ssd1306_color;
34
35 /* This buffer fits 96x40 pixels
36 Each 8 pixels are packed to 3 bytes:
37
38 BYTE1: B7 R2 G2 B2 B8 R1 G1 B1
39 BYTE2: G7 R4 G4 B4 G8 R3 G3 B3
40 BYTE3: R7 R6 G6 B6 R8 R5 G5 B5
41
42 Yeah, a little bit complicated, but this allows to quickly unpack structure
43 */
44
45 // Set to ssd1306 compatible mode by default
46 static uint8_t s_mode = 0x01;
47 static uint8_t s_vga_command = 0xFF;
48 static uint8_t s_vga_arg = 0;
49 static uint8_t s_column = 0;
50 static uint8_t s_column_end = 0;
51 static uint8_t s_cursor_x = 0;
52 static uint8_t s_cursor_y = 0;
53 volatile uint8_t s_vga_frames;
54
55 static void vga_controller_init(void)
56 {
57 s_vga_command = 0xFF;
58 }
59
60 static void vga_controller_stop(void)
61 {
62 s_vga_command = 0xFF;
63 }
64
65 static void vga_controller_close(void)
66 {
67 }
68
69 /* This buffer fits 96x40 pixels
70 Each 8 pixels are packed to 3 bytes:
71
72 BYTE1: B7 R2 G2 B2 B8 R1 G1 B1
73 BYTE2: G7 R4 G4 B4 G8 R3 G3 B3
74 BYTE3: R7 R6 G6 B6 R8 R5 G5 B5
75
76 Yeah, a little bit complicated, but this allows to quickly unpack structure
77 */
78 static inline void vga_controller_put_pixel3(uint8_t x, uint8_t y, uint8_t color)
79 {
80 uint16_t addr = (x >> 3)*3 + (uint16_t)y*36;
81 uint8_t offset = x & 0x07;
82 if (addr >= 36*40)
83 {
84 return;
85 }
86 if (offset < 6)
87 {
88 if (x&1)
89 {
90 __vga_buffer[addr + (offset>>1)] &= 0x8F;
91 __vga_buffer[addr + (offset>>1)] |= (color<<4);
92 }
93 else
94 {
95 __vga_buffer[addr + (offset>>1)] &= 0xF8;
96 __vga_buffer[addr + (offset>>1)] |= color;
97 }
98 }
99 else if (offset == 6)
100 {
101 __vga_buffer[addr+0] &= 0x7F;
102 __vga_buffer[addr+0] |= ((color & 0x01) << 7);
103 __vga_buffer[addr+1] &= 0x7F;
104 __vga_buffer[addr+1] |= ((color & 0x02) << 6);
105 __vga_buffer[addr+2] &= 0x7F;
106 __vga_buffer[addr+2] |= ((color & 0x04) << 5);
107 }
108 else // if (offset == 7)
109 {
110 __vga_buffer[addr+0] &= 0xF7;
111 __vga_buffer[addr+0] |= ((color & 0x01) << 3);
112 __vga_buffer[addr+1] &= 0xF7;
113 __vga_buffer[addr+1] |= ((color & 0x02) << 2);
114 __vga_buffer[addr+2] &= 0xF7;
115 __vga_buffer[addr+2] |= ((color & 0x04) << 1);
116 }
117 }
118
119 static void vga_controller_send_byte4(uint8_t data)
120 {
121 if (s_vga_command == 0xFF)
122 {
123 s_vga_command = data;
124 return;
125 }
126 if (s_vga_command == 0x40)
127 {
128 uint8_t color = ((data & 0x80) >> 5) | ((data & 0x10) >> 3) | ((data & 0x02)>>1);
129 vga_controller_put_pixel3(s_cursor_x, s_cursor_y, color);
130 if (s_mode == 0x00)
131 {
132 s_cursor_x++;
133 if (s_cursor_x > s_column_end)
134 {
135 s_cursor_x = s_column;
136 s_cursor_y++;
137 }
138 }
139 else
140 {
141 s_cursor_y++;
142 if ((s_cursor_y & 0x07) == 0)
143 {
144 s_cursor_y -= 8;
145 s_cursor_x++;
146 }
147 }
148 return;
149 }
150 // command mode
151 if (!s_vga_command)
152 {
153 s_vga_command = data;
154 s_vga_arg = 0;
155 }
156 if (s_vga_command == VGA_SET_BLOCK)
157 {
158 // set block
159 if (s_vga_arg == 1) { s_column = data; s_cursor_x = data; }
160 if (s_vga_arg == 2) { s_column_end = data; }
161 if (s_vga_arg == 3) { s_cursor_y = data; }
162 if (s_vga_arg == 4) { s_vga_command = 0; }
163 }
164 if (s_vga_command == VGA_SET_MODE)
165 {
166 if (s_vga_arg == 1) { s_mode = data; s_vga_command = 0; }
167 }
168 s_vga_arg++;
169 }
170
171 static void vga_controller_send_bytes(const uint8_t *buffer, uint16_t len)
172 {
173 while (len--)
174 {
175 ssd1306_intf.send(*buffer);
176 buffer++;
177 }
178 }
179
180 static inline void init_vga_crt_driver(uint8_t enable_jitter_fix)
181 {
182 cli();
183 if (enable_jitter_fix)
184 {
185 // Configure Timer 0 to calculate jitter fix
186 TIMSK0=0;
187 TCCR0A=0;
188 TCCR0B=1;
189 OCR0A=0;
190 OCR0B=0;
191 TCNT0=0;
192 }
193 else
194 {
195 // Sorry, we still need to disable timer0 interrupts to avoid wake up in sleep mode
196 TIMSK0 &= ~(1<<TOIE0);
197 }
198
199 // Timer 1 - vertical sync pulses
200 pinMode (V_SYNC_PIN, OUTPUT);
201 TCCR1A=(1<<WGM10) | (1<<WGM11) | (1<<COM1B1);
202 TCCR1B=(1<<WGM12) | (1<<WGM13) | (1<<CS12) | (1<<CS10); //1024 prescaler
203 OCR1A = 259; // 16666 / 64 us = 260 (less one)
204 OCR1B = 0; // 64 / 64 us = 1 (less one)
205 TIFR1 = (1<<TOV1); // clear overflow flag
206 TIMSK1 = (1<<TOIE1); // interrupt on overflow on timer 1
207
208 // Timer 2 - horizontal sync pulses
209 pinMode (H_SYNC_PIN, OUTPUT);
210 TCCR2A=(1<<WGM20) | (1<<WGM21) | (1<<COM2B1); //pin3=COM2B1
211 TCCR2B=(1<<WGM22) | (1<<CS21); //8 prescaler
212 OCR2A = 63; // 32 / 0.5 us = 64 (less one)
213 OCR2B = 7; // 4 / 0.5 us = 8 (less one)
214 // if (enable_jitter_fix)
215 {
216 TIFR2 = (1<<OCF2B); // on end of h-sync pulse
217 TIMSK2 = (1<<OCIE2B); // on end of h-sync pulse
218 }
219 // else
220 // {
221 // TIFR2 = (1<<TOV2); // int on start of h-sync pulse
222 // TIMSK2 = (1<<TOIE2); // int on start of h-sync pulse
223 // }
224
225 // Set up USART in SPI mode (MSPIM)
226
227 pinMode(14, OUTPUT);
228 pinMode(15, OUTPUT);
229 pinMode(16, OUTPUT);
230 PORTC = 0;
231
232 sei();
233 }
234
235 void ssd1306_vga_controller_96x40_init_no_output(void)
236 {
237 ssd1306_intf.spi = 0;
238 ssd1306_intf.start = vga_controller_init;
239 ssd1306_intf.stop = vga_controller_stop;
240 ssd1306_intf.send = vga_controller_send_byte4;
241 ssd1306_intf.send_buffer = vga_controller_send_bytes;
242 ssd1306_intf.close = vga_controller_close;
243 }
244
245 void ssd1306_vga_controller_96x40_init_enable_output(void)
246 {
247 ssd1306_vga_controller_96x40_init_no_output();
248 init_vga_crt_driver(1);
249 }
250
251 void ssd1306_vga_controller_96x40_init_enable_output_no_jitter_fix(void)
252 {
253 ssd1306_vga_controller_96x40_init_no_output();
254 init_vga_crt_driver(0);
255 // set_sleep_mode (SLEEP_MODE_IDLE);
256 }
257
258 void ssd1306_debug_print_vga_buffer_96x40(void (*func)(uint8_t))
259 {
260 for(int y = 0; y < ssd1306_lcd.height; y++)
261 {
262 for(int x = 0; x < ssd1306_lcd.width; x++)
263 {
264 uint8_t color = (__vga_buffer[(y*ssd1306_lcd.width + x)/2] >> ((x&1)<<2)) & 0x0F;
265 if (color)
266 {
267 func('#');
268 func('#');
269 }
270 else
271 {
272 func(' ');
273 func(' ');
274 }
275 }
276 func('\n');
277 }
278 func('\n');
279 }
280
281 void ssd1306_vga_delay(uint32_t ms)
282 {
283 uint8_t vga_frames;
284 while (ms >= 16)
285 {
286 vga_frames = s_vga_frames;
287 while (vga_frames == s_vga_frames);
288 ms-=16;
289 }
290 }
291
292 #endif
ssd1306_interface_t::send
void(* send)(uint8_t data)
Definition: ssd1306_interface.h:70
lcd_common.h
ssd1306_interface_t::stop
void(* stop)(void)
Definition: ssd1306_interface.h:65
vga_commands.h
ssd1306_vga_delay
void ssd1306_vga_delay(uint32_t ms)
VGA_SET_MODE
Definition: vga_commands.h:59
vga.h
ssd1306_interface_t::start
void(* start)(void)
Definition: ssd1306_interface.h:61
ssd1306_interface_t::close
void(* close)(void)
deinitializes internal resources, allocated for interface.
Definition: ssd1306_interface.h:88
ssd1306_lcd
ssd1306_lcd_t ssd1306_lcd
Definition: lcd_common.c:32
ssd1306_intf
ssd1306_interface_t ssd1306_intf
Definition: ssd1306_interface.c:29
VGA_SET_BLOCK
Definition: vga_commands.h:47
ssd1306_lcd_t::height
lcduint_t height
Definition: lcd_common.h:97
ssd1306_interface.h
ssd1306_interface_t::spi
uint8_t spi
Definition: ssd1306_interface.h:57
ssd1306_interface_t::send_buffer
void(* send_buffer)(const uint8_t *buffer, uint16_t size)
Sends bytes to SSD1306 device.
Definition: ssd1306_interface.h:80
ssd1306_lcd_t::width
lcduint_t width
Definition: lcd_common.h:94