Viking Skull Lamp  V1.0.1
Loading...
Searching...
No Matches
oled.cpp
Go to the documentation of this file.
1/*
2 * Created on May 28 2022
3 *
4 * Copyright (c) 2022 - Daniel Hajnal
5 * hajnal.daniel96@gmail.com
6 * This file is part of the Viking Skull Lamp project.
7 * Modified 2022.06.27
8*/
9
10/*
11MIT License
12Copyright (c) 2022 Daniel Hajnal
13Permission is hereby granted, free of charge, to any person obtaining a copy
14of this software and associated documentation files (the "Software"), to deal
15in the Software without restriction, including without limitation the rights
16to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17copies of the Software, and to permit persons to whom the Software is
18furnished to do so, subject to the following conditions:
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27SOFTWARE.
28*/
29
30#include "oled.hpp"
31
32ssd1306::ssd1306( uint8_t address_p ){
33
34 address = address_p;
35
36}
37
39
40 // Initialize I2C peripheral.
41 Wire.begin();
42
43 // Set the clock speed to 400kHz of the I2C bus.
44 Wire.setClock( 400000 );
45
46 // Check for the presence of the display on the bus.
47 // If it fails, you may check the address.
48 Wire.beginTransmission( address );
49 if( Wire.endTransmission() != 0 ){
50
51 return false;
52
53 }
54
55 // Set Memory Addressing Mode
56 writeCommand( 0x20 );
57 // Horizontal Addressing Mode
58 writeCommand( 0x00 );
59
60 // Set Page Start Address
61 writeCommand( 0xB0 );
62 // Set COM Output Direction
63 writeCommand( 0xC8 );
64
65 // Set Low Collumn Address
66 writeCommand( 0x00 );
67 // Set High Collumn Address
68 writeCommand( 0x10 );
69
70 // Set Start Line Address
71 writeCommand( 0x40 );
72
73 // Set Contrast
74 writeCommand( 0x81 );
75 writeCommand( 0xFF );
76
77 // Set Segment Remap 0-127
78 writeCommand( 0xA1 );
79
80 // Set Normal Color
81 writeCommand( 0xA6 );
82
83 writeCommand( 0xA8 );
84
85 writeCommand( 0x1F );
86
87 // Output follows RAM content
88 writeCommand( 0xA4 );
89
90 // Set Display Offset
91 writeCommand( 0xD3 );
92 // NO Offset
93 writeCommand( 0x00 );
94
95 // Set Display Clock Divide Ratio/Osc. Freq
96 writeCommand( 0xD5 );
97 // Ratio
98 writeCommand( 0xF0 );
99
100 // Set Pre-charge Period
101 writeCommand( 0xD9 );
102 // Period
103 writeCommand( 0x22 );
104
105 // Set COM Pin Hardware Configuration
106 writeCommand( 0xDA );
107
108 // 32 pixel height
109 writeCommand( 0x02 );
110
111 // Set VCOMH
112 writeCommand( 0xD8 );
113 // 0.77 x VCC
114 writeCommand( 0x20 );
115
116 // Enable DC-DC
117 writeCommand( 0x8D );
118 writeCommand( 0x14 );
119
120 // We have to wait a bit. The charge pump needs some
121 // time to startup correctly.
122 delay( 500 );
123
124 // Turn on the display.
125 displayOn();
126
127 // Clear the display buffer.
128 clear();
129
130 return true;
131
132}
133
135
136 // Clear the display buffer.
137 memset( buffer, 0, SSD1306_WIDTH * SSD1306_HEIGHT / 8 );
138
139}
140
142
143 uint8_t i;
144
145 // Write data to the display line by line.
146 for( i = 0; i < ( SSD1306_HEIGHT / 8 ); i++ ){
147
148 writeCommand( (uint8_t)0xB0 + i );
149 writeCommand( (uint8_t)0x00 );
150 writeCommand( (uint8_t)0x10 );
151 writeData( &buffer[ (uint16_t)i * SSD1306_WIDTH ], SSD1306_WIDTH );
152
153 }
154
155}
156
157void ssd1306::writeData( uint8_t* data, uint16_t dataSize ){
158
159 uint16_t i;
160 uint8_t sent;
161
162 // Begin the transmission.
163 Wire.beginTransmission( address );
164 Wire.write( (uint8_t)0x40 );
165
166 // On AVR we have to count the sent bytes, because
167 // Wire library can only send 32 bytes at once.
168 sent = 1;
169 for( i = 0; i < dataSize; i++ ){
170
171 // Check if we reached the limit of the buffer.
172 if( sent >= 30 ){
173
174 // If the buffer is full, we have to send everything
175 // and start a new transaction.
176 Wire.endTransmission();
177 Wire.beginTransmission( address );
178 Wire.write( (uint8_t)0x40 );
179 sent = 1;
180
181 }
182
183 // Write the data.
184 Wire.write( data[ i ] );
185 sent++;
186
187 }
188
189 // Send the rest of the previous chunk.
190 Wire.endTransmission();
191
192}
193
194void ssd1306::writeCommand( uint8_t command ){
195
196 // Write the command byte.
197 Wire.beginTransmission( address );
198 Wire.write( (uint8_t)0x00 );
199 Wire.write( command );
200 Wire.endTransmission();
201
202}
203
205
206 writeCommand( 0xAF );
207
208}
209
211
212 writeCommand( 0xAE );
213
214}
215
216void ssd1306::setPixel( uint8_t x, uint8_t y ){
217
218 // Check the boundaries of the coordinates.
219 if( x >= SSD1306_WIDTH ){
220
221 return;
222
223 }
224
225 if( y >= SSD1306_HEIGHT ){
226
227 return;
228
229 }
230
231 // Set the pixel in the buffer.
232 buffer[ x + ( y / 8 ) * SSD1306_WIDTH ] |= 1 << ( y % 8 );
233
234}
235
236void ssd1306::clearPixel( uint8_t x, uint8_t y ){
237
238 // Check the boundaries of the coordinates.
239 if( x >= SSD1306_WIDTH ){
240
241 return;
242
243 }
244
245 if( y >= SSD1306_HEIGHT ){
246
247 return;
248
249 }
250
251 // Clear the pixel in the buffer.
252 buffer[ x + ( y / 8 ) * SSD1306_WIDTH ] &= ~( 1 << ( y % 8 ) );
253
254}
255
256void ssd1306::fillRect( uint8_t x, uint8_t y, uint8_t w, uint8_t h ){
257
258 uint8_t x_iter;
259 uint8_t y_iter;
260
261 // Fill the pixels of the rectangle.
262 for( x_iter = x; x_iter < ( x + w ); x_iter++ ){
263
264 for( y_iter = y; y_iter < ( y + h ); y_iter++ ){
265
266 setPixel( x_iter, y_iter );
267
268 }
269
270 }
271
272}
273
274void ssd1306::clearRect( uint8_t x, uint8_t y, uint8_t w, uint8_t h ){
275
276 uint8_t x_iter;
277 uint8_t y_iter;
278
279 // Clear the pixels of the rectangle.
280 for( x_iter = 0; x_iter < ( x + w ); x_iter++ ){
281
282 for( y_iter = 0; y_iter < ( y + h ); y_iter++ ){
283
284 clearPixel( x + x_iter, y + y_iter );
285
286 }
287
288 }
289
290}
291
292void ssd1306::writeCharacter( uint8_t c ){
293
294 uint8_t i;
295 uint8_t j;
296
297 // The character bitmaps are stored in PROGMEM.
298 // They have to be copied to a buffer before use.
299 uint8_t characterData[5];
300
301 // Copy the bitmap data to the buffer.
302 // 32 has to be subtracted from the character to match the indexing.
303 // Every bitmap is 5 byte wide and they have a sixth emty bar to separate
304 // the characters.
305 characterData[ 0 ] = pgm_read_byte_near( ASCII + (uint8_t)( c - 32 ) * 5 );
306 characterData[ 1 ] = pgm_read_byte_near( ASCII + (uint8_t)( c - 32 ) * 5 + 1 );
307 characterData[ 2 ] = pgm_read_byte_near( ASCII + (uint8_t)( c - 32 ) * 5 + 2 );
308 characterData[ 3 ] = pgm_read_byte_near( ASCII + (uint8_t)( c - 32 ) * 5 + 3 );
309 characterData[ 4 ] = pgm_read_byte_near( ASCII + (uint8_t)( c - 32 ) * 5 + 4 );
310
311 // Process every byte.
312 for( i = 0; i < 5; i++ ){
313
314 // Process every bit in the byte.
315 for( j = 0; j < 8; j++ ){
316
317 // If not inverted and the bit is set, set the character.
318 if( !!( characterData[ i ] & ( 1 << j ) ) ^ ( !!inverted ) ){
319
320 setPixel( cursorX + i , cursorY + j );
321
322 }
323
324 // Else clear the character.
325 else{
326
327 clearPixel( cursorX + i , cursorY + j );
328
329 }
330
331 }
332
333 }
334
335 // In inverted case the separator bar has to be filled.
336 if( inverted ){
337
338 for( j = 0; j < 8; j++ ){
339
340 setPixel( cursorX + i , cursorY + j );
341
342 }
343
344 }
345
346 // Step the cursor.
347 cursorX += 6;
348
349
350 // If the cursor overflows jump to next line and reset the cursor.
351 if( cursorX > 127 ){
352
353 cursorX = 0;
354 cursorY += 8;
355
356 }
357
358}
359
360void ssd1306::print( char* str ){
361
362 uint32_t i = 0;
363
364 // Print every character in the string.
365 while( str[ i ] ){
366
367 writeCharacter( str[ i ] );
368 i++;
369
370 }
371
372}
373
374void ssd1306::print( int d ){
375
376 char charBuffer[ 22 ];
377
378 // Create a formatted string that contains the number and print it.
379 snprintf( charBuffer, 22, "%d", d );
380
381 print( charBuffer );
382
383}
384
385void ssd1306::line( uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2 ){
386
387 // The good old Bresenham algorithm. He made a very elegant
388 // solution for line drawing.
389 int m_new = 2 * ( y2 - y1 );
390 int slope_error_new = m_new - ( x2 - x1 );
391 int x;
392 int y = y1;
393
394 for( x = x1; x <= x2; x++ ){
395
396 if( inverted ){
397 clearPixel( x, y );
398 }
399
400 else{
401 setPixel( x, y );
402 }
403
404 slope_error_new += m_new;
405
406 if( slope_error_new >= 0 ){
407
408 y++;
409 slope_error_new -= 2 * ( x2 - x1 );
410
411 }
412
413 }
414
415}
void writeCharacter(uint8_t c)
Write a character to the display.
Definition: oled.cpp:292
uint8_t cursorX
X-coordinate of the cursor.
Definition: oled.hpp:234
void writeData(uint8_t *data, uint16_t dataSize)
Write data to the display.
Definition: oled.cpp:157
bool inverted
If this flag is set, the draw logic will be inverted.
Definition: oled.hpp:231
void displayOff()
Turn off the oled panel.
Definition: oled.cpp:210
void line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
Print line to the display.
Definition: oled.cpp:385
bool begin()
Init function for the display.
Definition: oled.cpp:38
uint8_t buffer[SSD1306_WIDTH *SSD1306_HEIGHT/8]
Pixel buffer.
Definition: oled.hpp:243
void clearRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
Create a cleared rectangle.
Definition: oled.cpp:274
void clearPixel(uint8_t x, uint8_t y)
Clear a pixel by location.
Definition: oled.cpp:236
void displayOn()
Turn on the oled panel.
Definition: oled.cpp:204
uint8_t address
Address of the display.
Definition: oled.hpp:255
void update()
Update the content of the panel.
Definition: oled.cpp:141
void setPixel(uint8_t x, uint8_t y)
Set a pixel by location.
Definition: oled.cpp:216
uint8_t cursorY
Y-coordinate of the cursor.
Definition: oled.hpp:237
void clear()
Clear the display.
Definition: oled.cpp:134
ssd1306(uint8_t address_p)
Constructor.
Definition: oled.cpp:32
void print(char *str)
Print a c-string tho the display.
Definition: oled.cpp:360
void writeCommand(uint8_t c)
Write command to the display.
Definition: oled.cpp:194
void fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
Create a filled rectangle.
Definition: oled.cpp:256
#define SSD1306_HEIGHT
Height of the display module in pixels.
Definition: oled.hpp:41
#define SSD1306_WIDTH
Width of the display module in pixels.
Definition: oled.hpp:38