SSD1306 OLED display driver  1.8.2
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  while (ms >= 16)
284  {
285  uint8_t vga_frames;
286  vga_frames = s_vga_frames;
287  while (vga_frames == s_vga_frames);
288  ms-=16;
289  }
290 }
291 
292 #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