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

vga_isr.h
Go to the documentation of this file.
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 */
36 #ifndef _SSD1306_VGA_ATMEGA328P_ISR_H_
37 #define _SSD1306_VGA_ATMEGA328P_ISR_H_
38
39 #include "intf/vga/vga.h"
40 #include "ssd1306_hal/io.h"
41
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45
46 // Including this header defines ISR handlers in your application automatically
47 #if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(__AVR_ATmega328P__)
48
49 #ifndef DEJITTER_OFFSET
50 #define DEJITTER_OFFSET -4
51 #endif
52
53 #if defined(CONFIG_VGA_128X64_ENABLE)
54
55 static const uint16_t __VGA_VERTICAL_PIXELS = 64;
56 static const uint16_t __VGA_LINE_BYTES = 16;
57 static const uint16_t __VGA_PIXEL_HEIGHT = 7;
58 volatile uint8_t __vga_buffer[16*64] = {0};
59 static const volatile uint8_t *__VGA_BUFFER_PTR = &__vga_buffer[0];
60
61 void ssd1306_vga_controller_128x64_init_no_output(void);
62 void ssd1306_vga_controller_128x64_init_enable_output(void);
63 void ssd1306_vga_controller_128x64_init_enable_output_no_jitter_fix(void);
64 void ssd1306_debug_print_vga_buffer_128x64(void (*func)(uint8_t));
65
66 #elif defined(CONFIG_VGA_96X40_ENABLE)
67
68 static const uint16_t __VGA_VERTICAL_PIXELS = 40;
69 static const uint16_t __VGA_LINE_BYTES = 36;
70 static const uint16_t __VGA_PIXEL_HEIGHT = 10;
71 volatile uint8_t __vga_buffer[36*40] = {0};
72 static const volatile uint8_t * __VGA_BUFFER_PTR = &__vga_buffer[0];
73
74 void ssd1306_vga_controller_96x40_init_no_output(void);
75 void ssd1306_vga_controller_96x40_init_enable_output(void);
76 void ssd1306_vga_controller_96x40_init_enable_output_no_jitter_fix(void);
77 void ssd1306_debug_print_vga_buffer_96x40(void (*func)(uint8_t));
78
79 #else
80 #error "Please, define one of VGA options"
81 #endif
82
83 #if !defined(VGA_CONTROLLER_DEBUG)
84
85 // Total number of lines used in specific scan mode
86 static const uint16_t VGA_TOTAL_MODE_LINES = __VGA_VERTICAL_PIXELS*__VGA_PIXEL_HEIGHT;
87
88 // Lines to skip before starting to draw first line of the screen content
89 // This includes V-sync signal + front porch
90 static const uint8_t V_BACKPORCH_LINES = 40;
91
92 // Lines to skip before starting to draw first line of the screen content
93 // This includes V-sync signal + front porch
94 volatile int s_current_scan_line;
95
96 volatile uint8_t s_lines_to_skip;
97 volatile uint8_t s_scan_line_index;
98 volatile const uint8_t * volatile s_current_scan_line_data = __VGA_BUFFER_PTR;
99 extern volatile uint8_t s_vga_frames;
100 extern unsigned long timer0_millis;
101 // ISR: Vsync pulse
102 ISR(TIMER1_OVF_vect)
103 {
104 s_current_scan_line = 0;
105 s_scan_line_index = 0;
106 s_current_scan_line_data = __VGA_BUFFER_PTR;
107 s_lines_to_skip = V_BACKPORCH_LINES;
108 s_vga_frames++;
109 timer0_millis += 16;
110 } // end of TIMER1_OVF_vect
111
112 #if defined(CONFIG_VGA_128X64_ENABLE)
113 static inline void /*__attribute__ ((noinline))*/ do_scan_line()
114 {
115 // output all pixels
116
117 asm volatile(
118 ".rept 16\n\t"
119
120 "ld r24, Z+\n\t"
121 "out %[port], r24\n\t"
122 "lsr r24\n\t"
123 "nop\n\t"
124 "out %[port], r24\n\t"
125 "lsr r24\n\t"
126 "out %[port], r24\n\t"
127 "lsr r24\n\t"
128 "nop\n\t"
129 "out %[port], r24\n\t"
130 "lsr r24\n\t"
131 "nop\n\t"
132 "out %[port], r24\n\t"
133 "lsr r24\n\t"
134 "nop\n\t"
135 "out %[port], r24\n\t"
136 "lsr r24\n\t"
137 "nop\n\t"
138 "out %[port], r24\n\t"
139 "lsr r24\n\t"
140 "nop\n\t"
141 "out %[port], r24\n\t"
142
143 ".endr\n\t"
144 "nop\n\t"
145 "ldi r24,0\n\t"
146 "out %[port], r24 \n\t"
147 "nop\n\t"
148 :
149 : [port] "I" (_SFR_IO_ADDR(PORTC)),
150 "z" "I" ((uint8_t *)s_current_scan_line_data )
151 : "r24", "memory"
152 );
153 }
154 #elif defined(CONFIG_VGA_96X40_ENABLE)
155 static inline void /*__attribute__ ((noinline))*/ do_scan_line()
156 {
157 // output all pixels
158
159 asm volatile(
160 ".rept 12\n\t"
161
162 "ld r24, Z+\n\t" // r24 = 82227111
163 // "nop\n\t" // to make pixel wider in 96x40 mode
164 "out %[port], r24\n\t" // 111
165
166 "ld r25, Z+\n\t" // r25 = 84447333
167 "swap r24\n\t" // r24 = 71118222
168 "out %[port], r24\n\t" // 222
169
170 "andi r24, 0x88\n\t" // r24 = 70008000
171 "ld r20, Z+\n\t" // r20 = 86667555
172 "out %[port], r25\n\t" // 333
173
174 "swap r25\n\t" // r25 = 73338444
175 "lsr r24\n\t" // r24 = 00080007
176 "lsr r24\n\t" // r24 = 00800070
177 "out %[port], r25\n\t" // 444
178
179 "andi r25, 0x88\n\t" // r25 = 70008000
180 "lsr r24\n\t" // r24 = 08000700
181 "lsr r25\n\t" // r25 = 00080007
182 "out %[port], r20\n\t" // 555
183
184 "swap r20\n\t" // r20 = 75558666
185 "lsr r25\n\t" // r25 = 00800070
186 "or r24, r25\n\t" // r24 = 08800770
187 "out %[port], r20\n\t" // 666
188
189 "andi r20, 0x88\n\t" // r20 = 70008000
190 "lsr r20\n\t" // r20 = 00080007 b
191 "or r24, r20\n\t" // r24 = 08880777 rgb
192 "out %[port], r24\n\t" // 777
193
194 "swap r24\n\t" // r24 = 07770888
195 // "nop\n\t" // to make pixel wider in 96x40 mode
196 "nop\n\t"
197 "out %[port], r24\n\t" // 888
198
199 ".endr\n\t"
200 // "nop\n\t" // to make pixel wider in 96x40 mode
201 "nop\n\t"
202 "ldi r24,0\n\t"
203 "out %[port], r24 \n\t"
204 "nop\n\t"
205 :
206 : [port] "I" (_SFR_IO_ADDR(PORTC)),
207 "z" "I" ((uint8_t *)s_current_scan_line_data )
208 : "r24", "r25", "r20", "memory"
209 );
210 }
211 #endif
212
213 //#ifdef SSD1306_VGA_SLEEP_MODE
214 //ISR(TIMER2_OVF_vect) // for start of h-sync pulse
215 //#else
216 ISR(TIMER2_COMPB_vect) // for end of h-sync pulse
217 //#endif
218 {
219 // ISR should work as fast as possible
220 if (s_lines_to_skip)
221 {
222 s_lines_to_skip--;
223 return;
224 }
225 else if (s_current_scan_line >= VGA_TOTAL_MODE_LINES)
226 {
227 return;
228 }
229 #ifndef SSD1306_VGA_SLEEP_MODE
230 // This is dejitter code, it purpose to start pixels output at the same offset after h-sync
231 asm volatile(
232 " lds r24, %[timer0] \n\t" //
233 " subi r24, %[toffset] \n\t" // some offset, calculated experimentally
234 " andi r24, 7 \n\t" // use module 8 value from Timer 0 counter
235 " ldi r31, pm_hi8(LW) \n\t" // load label address
236 " ldi r30, pm_lo8(LW) \n\t" //
237 " add r30, r24 \n\t" // no need to multiply by 2 since AVR addresses are half-values
238 " adc r31, __zero_reg__ \n\t" //
239 " ijmp \n\t" //
240 "LW: \n\t" //
241 " nop \n\t" //
242 " nop \n\t" //
243 " nop \n\t" //
244 " nop \n\t" //
245 " nop \n\t" //
246 " nop \n\t" //
247 " nop \n\t" //
248 :
249 : [timer0] "i" (&TCNT0),
250 [toffset] "i" ((uint8_t)DEJITTER_OFFSET)
251 : "r30", "r31", "r24", "r25");
252 #endif
253 do_scan_line();
254 s_current_scan_line++;
255 s_scan_line_index++;
256 if ( s_scan_line_index >= __VGA_PIXEL_HEIGHT )
257 {
258 s_scan_line_index=0;
259 s_current_scan_line_data += __VGA_LINE_BYTES;
260 }
261 }
262
263 #endif // VGA_CONTROLLER_DEBUG
264
265 #if defined(CONFIG_VGA_128X64_ENABLE)
266
267 static inline void ssd1306_vga_controller_init(void)
268 {
269 // if there is no builtin support then only debug mode is available
270 #if defined(VGA_CONTROLLER_DEBUG)
271 ssd1306_vga_controller_128x64_init_no_output();
272 #elif defined(SSD1306_VGA_SLEEP_MODE)
273 ssd1306_vga_controller_128x64_init_enable_output_no_jitter_fix();
274 #else
275 ssd1306_vga_controller_128x64_init_enable_output();
276 #endif
277 }
278
279 void ssd1306_debug_print_vga_buffer(void (*func)(uint8_t))
280 {
281 ssd1306_debug_print_vga_buffer_128x64(func);
282 }
283
284 #elif defined(CONFIG_VGA_96X40_ENABLE)
285
286 static inline void ssd1306_vga_controller_init(void)
287 {
288 // if there is no builtin support then only debug mode is available
289 #if defined(VGA_CONTROLLER_DEBUG)
290 ssd1306_vga_controller_96x40_init_no_output();
291 #elif defined(SSD1306_VGA_SLEEP_MODE)
292 ssd1306_vga_controller_96x40_init_enable_output_no_jitter_fix();
293 #else
294 ssd1306_vga_controller_96x40_init_enable_output();
295 #endif
296 }
297
298 void ssd1306_debug_print_vga_buffer(void (*func)(uint8_t))
299 {
300 ssd1306_debug_print_vga_buffer_96x40(func);
301 }
302
303 #endif // CONFIG_VGA_XXX_ENABLE
304
305 #endif // SSD1306_BUILTIN_VGA_SUPPORT
306
307 #ifdef __cplusplus
308 }
309 #endif
310
311 #endif
312
io.h
vga.h
ssd1306_debug_print_vga_buffer
void ssd1306_debug_print_vga_buffer(void(*func)(uint8_t))