SSD1306 OLED display driver  1.8.2
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
void(* send)(uint8_t data)
void(* close)(void)
deinitializes internal resources, allocated for interface.
ssd1306_lcd_t ssd1306_lcd
Definition: lcd_common.c:33
ssd1306_interface_t ssd1306_intf
lcduint_t height
Definition: lcd_common.h:97
void(* send_buffer)(const uint8_t *buffer, uint16_t size)
Sends bytes to SSD1306 device.
lcduint_t width
Definition: lcd_common.h:94