SSD1306 OLED display driver  1.8.2
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 
void ssd1306_debug_print_vga_buffer(void(*func)(uint8_t))