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

vga128x64.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 vga128x64_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 128x64 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 /*
70 * Function sends 8 vertical pixels to buffer
71 */
72 static inline void vga_controller_put_pixels(uint8_t x, uint8_t y, uint8_t pixels)
73 {
74 uint16_t addr = (x >> 3) + (uint16_t)(y * 16);
75 uint8_t offset = x & 0x07;
76 uint8_t mask = 1 << offset;
77 if (addr >= 16*64)
78 {
79 return;
80 }
81 for (uint8_t i=8; i>0; i--)
82 {
83 if (pixels & 0x01) __vga_buffer[addr] |= mask;
84 else __vga_buffer[addr] &= ~mask;
85 addr += 16;
86 pixels >>= 1;
87 }
88 }
89
90 static void vga_controller_send_byte(uint8_t data)
91 {
92 if (s_vga_command == 0xFF)
93 {
94 s_vga_command = data;
95 return;
96 }
97 if (s_vga_command == 0x40)
98 {
99 vga_controller_put_pixels(s_cursor_x, s_cursor_y, data);
100 s_cursor_x++;
101 if (s_cursor_x > s_column_end)
102 {
103 s_cursor_x = s_column;
104 s_cursor_y += 8;
105 }
106 return;
107 }
108 // command mode
109 if (!s_vga_command)
110 {
111 s_vga_command = data;
112 s_vga_arg = 0;
113 }
114 if (s_vga_command == VGA_SET_BLOCK)
115 {
116 // set block
117 if (s_vga_arg == 1)
118 {
119 s_column = data >= ssd1306_lcd.width ? ssd1306_lcd.width - 1 : data ;
120 s_cursor_x = s_column;
121 }
122 if (s_vga_arg == 2) { s_column_end = data >= ssd1306_lcd.width ? ssd1306_lcd.width - 1 : data; }
123 if (s_vga_arg == 3) { s_cursor_y = (data << 3); }
124 if (s_vga_arg == 4) { s_vga_command = 0; }
125 }
126 if (s_vga_command == VGA_SET_MODE)
127 {
128 if (s_vga_arg == 1) { s_mode = data; s_vga_command = 0; }
129 }
130 s_vga_arg++;
131 }
132
133 static void vga_controller_send_bytes(const uint8_t *buffer, uint16_t len)
134 {
135 while (len--)
136 {
137 ssd1306_intf.send(*buffer);
138 buffer++;
139 }
140 }
141
142 static inline void init_vga_crt_driver(uint8_t enable_jitter_fix)
143 {
144 cli();
145 if (enable_jitter_fix)
146 {
147 // Configure Timer 0 to calculate jitter fix
148 TIMSK0=0;
149 TCCR0A=0;
150 TCCR0B=1;
151 OCR0A=0;
152 OCR0B=0;
153 TCNT0=0;
154 }
155 else
156 {
157 // Sorry, we still need to disable timer0 interrupts to avoid wake up in sleep mode
158 TIMSK0 &= ~(1<<TOIE0);
159 }
160
161 // Timer 1 - vertical sync pulses
162 pinMode (V_SYNC_PIN, OUTPUT);
163 TCCR1A=(1<<WGM10) | (1<<WGM11) | (1<<COM1B1);
164 TCCR1B=(1<<WGM12) | (1<<WGM13) | (1<<CS12) | (1<<CS10); //1024 prescaler
165 OCR1A = 259; // 16666 / 64 us = 260 (less one)
166 OCR1B = 0; // 64 / 64 us = 1 (less one)
167 TIFR1 = (1<<TOV1); // clear overflow flag
168 TIMSK1 = (1<<TOIE1); // interrupt on overflow on timer 1
169
170 // Timer 2 - horizontal sync pulses
171 pinMode (H_SYNC_PIN, OUTPUT);
172 TCCR2A=(1<<WGM20) | (1<<WGM21) | (1<<COM2B1); //pin3=COM2B1
173 TCCR2B=(1<<WGM22) | (1<<CS21); //8 prescaler
174 OCR2A = 63; // 32 / 0.5 us = 64 (less one)
175 OCR2B = 7; // 4 / 0.5 us = 8 (less one)
176 // if (enable_jitter_fix)
177 {
178 TIFR2 = (1<<OCF2B); // on end of h-sync pulse
179 TIMSK2 = (1<<OCIE2B); // on end of h-sync pulse
180 }
181 // else
182 // {
183 // TIFR2 = (1<<TOV2); // int on start of h-sync pulse
184 // TIMSK2 = (1<<TOIE2); // int on start of h-sync pulse
185 // }
186
187 // Set up USART in SPI mode (MSPIM)
188
189 pinMode(14, OUTPUT);
190 pinMode(15, OUTPUT);
191 pinMode(16, OUTPUT);
192 PORTC = 0;
193
194 sei();
195 }
196
197 void ssd1306_vga_controller_128x64_init_no_output(void)
198 {
199 ssd1306_intf.spi = 0;
200 ssd1306_intf.start = vga_controller_init;
201 ssd1306_intf.stop = vga_controller_stop;
202 ssd1306_intf.send = vga_controller_send_byte;
203 ssd1306_intf.send_buffer = vga_controller_send_bytes;
204 ssd1306_intf.close = vga_controller_close;
205 }
206
207 void ssd1306_vga_controller_128x64_init_enable_output(void)
208 {
209 ssd1306_vga_controller_128x64_init_no_output();
210 init_vga_crt_driver(1);
211 }
212
213 void ssd1306_vga_controller_128x64_init_enable_output_no_jitter_fix(void)
214 {
215 ssd1306_vga_controller_128x64_init_no_output();
216 init_vga_crt_driver(0);
217 // set_sleep_mode (SLEEP_MODE_IDLE);
218 }
219
220 void ssd1306_debug_print_vga_buffer_128x64(void (*func)(uint8_t))
221 {
222 for(int y = 0; y < ssd1306_lcd.height; y++)
223 {
224 for(int x = 0; x < ssd1306_lcd.width; x++)
225 {
226 uint8_t color = __vga_buffer[(x >> 3) + y * 16] & (1<< (x&0x07));
227 if (color)
228 {
229 func('#');
230 func('#');
231 }
232 else
233 {
234 func(' ');
235 func(' ');
236 }
237 }
238 func('\n');
239 }
240 func('\n');
241 }
242
243 #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
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