Added I2C
[hackover2013-badge-firmware.git] / drivers / displays / bitmap / ssd1306 / ssd1306.c
1 /**************************************************************************/
2 /*!
3 @file ssd1306.c
4 @author K. Townsend (microBuilder.eu)
5
6 @section DESCRIPTION
7
8 Driver for 128x64 OLED display based on the SSD1306 controller.
9
10 This driver is based on the SSD1306 Library from Limor Fried
11 (Adafruit Industries) at: https://github.com/adafruit/SSD1306
12
13 @section LICENSE
14
15 Software License Agreement (BSD License)
16
17 Copyright (c) 2012, microBuilder SARL
18 All rights reserved.
19
20 Redistribution and use in source and binary forms, with or without
21 modification, are permitted provided that the following conditions are met:
22 1. Redistributions of source code must retain the above copyright
23 notice, this list of conditions and the following disclaimer.
24 2. Redistributions in binary form must reproduce the above copyright
25 notice, this list of conditions and the following disclaimer in the
26 documentation and/or other materials provided with the distribution.
27 3. Neither the name of the copyright holders nor the
28 names of its contributors may be used to endorse or promote products
29 derived from this software without specific prior written permission.
30
31 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
32 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
35 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 */
42 /**************************************************************************/
43 #include <string.h>
44
45 #include "ssd1306.h"
46
47 #include "core/gpio/gpio.h"
48 #include "core/i2c/i2c.h"
49 #include "core/systick/systick.h"
50 #include "drivers/displays/smallfonts.h"
51
52 #define DELAY(mS) do { systickDelay( mS / CFG_SYSTICK_DELAY_IN_MS ); } while(0);
53
54 // LCD framebuffer
55 uint8_t _ssd1306buffer[SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8];
56
57 #if defined SSD1306_BUS_I2C
58 void ssd1306SendCommand(uint8_t byte);
59 void ssd1306SendData(uint8_t data);
60
61 extern volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE];
62 extern volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE];
63 extern volatile uint32_t I2CReadLength, I2CWriteLength;
64 #endif
65
66 #if defined SSD1306_BUS_SPI
67 void ssd1306SendByte(uint8_t byte);
68
69 #define CMD(c) do { gpioSetValue( SSD1306_CS_PORT, SSD1306_CS_PIN, 1 ); \
70 gpioSetValue( SSD1306_DC_PORT, SSD1306_DC_PIN, 0 ); \
71 gpioSetValue( SSD1306_CS_PORT, SSD1306_CS_PIN, 0 ); \
72 ssd1306SendByte( c ); \
73 gpioSetValue( SSD1306_CS_PORT, SSD1306_CS_PIN, 1 ); \
74 } while (0);
75 #define DATA(c) do { gpioSetValue( SSD1306_CS_PORT, SSD1306_CS_PIN, 1 ); \
76 gpioSetValue( SSD1306_DC_PORT, SSD1306_DC_PIN, 1 ); \
77 gpioSetValue( SSD1306_CS_PORT, SSD1306_CS_PIN, 0 ); \
78 ssd1306SendByte( c ); \
79 gpioSetValue( SSD1306_CS_PORT, SSD1306_CS_PIN, 1 ); \
80 } while (0);
81 #endif
82
83 /**************************************************************************/
84 /* Private Methods */
85 /**************************************************************************/
86
87 #if defined SSD1306_BUS_SPI
88 /**************************************************************************/
89 /*!
90 @brief Simulates an SPI write using GPIO
91
92 @param[in] byte
93 The byte to send
94 */
95 /**************************************************************************/
96 void ssd1306SendByte(uint8_t byte)
97 {
98 int8_t i;
99
100 // Make sure clock pin starts high
101 gpioSetValue(SSD1306_SCLK_PORT, SSD1306_SCLK_PIN, 1);
102
103 // Write from MSB to LSB
104 for (i=7; i>=0; i--)
105 {
106 // Set clock pin low
107 gpioSetValue(SSD1306_SCLK_PORT, SSD1306_SCLK_PIN, 0);
108 // Set data pin high or low depending on the value of the current bit
109 gpioSetValue(SSD1306_SDAT_PORT, SSD1306_SDAT_PIN, byte & (1 << i) ? 1 : 0);
110 // Set clock pin high
111 gpioSetValue(SSD1306_SCLK_PORT, SSD1306_SCLK_PIN, 1);
112 }
113 }
114 #endif
115
116 #if defined SSD1306_BUS_I2C
117 /**************************************************************************/
118 /*!
119 @brief Sends a command via I2C
120
121 @param[in] byte
122 The byte to send
123 */
124 /**************************************************************************/
125 void ssd1306SendCommand(uint8_t byte)
126 {
127 uint8_t control = 0x00; // Co = 0, D/C = 0
128 uint32_t i2cState;
129
130 // Clear write buffers
131 uint32_t i;
132 for ( i = 0; i < I2C_BUFSIZE; i++ )
133 {
134 I2CMasterBuffer[i] = 0x00;
135 }
136
137 // Send the specified bytes
138 I2CWriteLength = 3;
139 I2CReadLength = 0;
140 I2CMasterBuffer[0] = SSD1306_I2C_ADDRESS;
141 I2CMasterBuffer[1] = control;
142 I2CMasterBuffer[2] = byte;
143 i2cState = i2cEngine();
144
145 // Check if we got an ACK
146 if ((i2cState == I2CSTATE_NACK) || (i2cState == I2CSTATE_SLA_NACK))
147 {
148 // I2C slave didn't acknowledge the master transfer
149 // The PN532 probably isn't connected properly or the
150 // bus select pins are in the wrong state
151 // return PN532_ERROR_NACK;
152 }
153
154 // return PN532_ERROR_NONE;
155 }
156
157 /**************************************************************************/
158 /*!
159 @brief Sends data via I2C
160
161 @param[in] byte
162 The byte to send
163 */
164 /**************************************************************************/
165 void ssd1306SendData(uint8_t data)
166 {
167 uint8_t control = 0x40; // Co = 0, D/C = 1
168 uint32_t i2cState;
169
170 // Clear write buffers
171 uint32_t i;
172 for ( i = 0; i < I2C_BUFSIZE; i++ )
173 {
174 I2CMasterBuffer[i] = 0x00;
175 }
176
177 // Send the specified bytes
178 I2CWriteLength = 3;
179 I2CReadLength = 0;
180 I2CMasterBuffer[0] = SSD1306_I2C_ADDRESS;
181 I2CMasterBuffer[1] = control;
182 I2CMasterBuffer[2] = data;
183 i2cState = i2cEngine();
184
185 // Check if we got an ACK
186 if ((i2cState == I2CSTATE_NACK) || (i2cState == I2CSTATE_SLA_NACK))
187 {
188 // I2C slave didn't acknowledge the master transfer
189 // The PN532 probably isn't connected properly or the
190 // bus select pins are in the wrong state
191 // return PN532_ERROR_NACK;
192 }
193
194 // return PN532_ERROR_NONE;
195 }
196 #endif
197
198 /**************************************************************************/
199 /*!
200 @brief Draws a single graphic character using the supplied font
201 */
202 /**************************************************************************/
203 static void ssd1306DrawChar(uint16_t x, uint16_t y, uint8_t c, struct FONT_DEF font)
204 {
205 uint8_t col, column[font.u8Width];
206
207 // Make sure we are exceeding the display limits
208 // This also gets checked in ssd1306DrawPixel, but if we start
209 // outside the limits we can avoid some unecessary work at the outset
210 if ((x > SSD1306_LCDWIDTH) || (y > SSD1306_LCDHEIGHT))
211 return;
212
213 // Check if the requested character is available
214 if ((c >= font.u8FirstChar) && (c <= font.u8LastChar))
215 {
216 // Retrieve appropriate columns from font data
217 for (col = 0; col < font.u8Width; col++)
218 {
219 column[col] = font.au8FontTable[((c - 32) * font.u8Width) + col]; // Get first column of appropriate character
220 }
221 }
222 else
223 {
224 // Requested character is not available in this font ... send a space instead
225 for (col = 0; col < font.u8Width; col++)
226 {
227 column[col] = 0xFF; // Send solid space
228 }
229 }
230
231 // Render each column
232 uint16_t xoffset, yoffset;
233 for (xoffset = 0; xoffset < font.u8Width; xoffset++)
234 {
235 for (yoffset = 0; yoffset < (font.u8Height + 1); yoffset++)
236 {
237 uint8_t bit = 0x00;
238 bit = (column[xoffset] << (8 - (yoffset + 1))); // Shift current row bit left
239 bit = (bit >> 7); // Shift current row but right (results in 0x01 for black, and 0x00 for white)
240 if (bit)
241 {
242 ssd1306DrawPixel(x + xoffset, y + yoffset);
243 }
244 }
245 }
246 }
247
248 /**************************************************************************/
249 /* Public Methods */
250 /**************************************************************************/
251
252 /**************************************************************************/
253 /*!
254 @brief Initialises the SSD1306 LCD display
255 */
256 /**************************************************************************/
257 void ssd1306Init(uint8_t vccstate)
258 {
259 // SPI Initialisation
260 #if defined SSD1306_BUS_SPI
261 // Set all pins to output
262 gpioSetDir(SSD1306_SCLK_PORT, SSD1306_SCLK_PIN, gpioDirection_Output);
263 gpioSetDir(SSD1306_SDAT_PORT, SSD1306_SDAT_PIN, gpioDirection_Output);
264 gpioSetDir(SSD1306_DC_PORT, SSD1306_DC_PIN, gpioDirection_Output);
265 gpioSetDir(SSD1306_RST_PORT, SSD1306_RST_PIN, gpioDirection_Output);
266 gpioSetDir(SSD1306_CS_PORT, SSD1306_CS_PIN, gpioDirection_Output);
267
268 // Reset the LCD
269 gpioSetValue(SSD1306_RST_PORT, SSD1306_RST_PIN, 1);
270 DELAY(1);
271 gpioSetValue(SSD1306_RST_PORT, SSD1306_RST_PIN, 0);
272 DELAY(10);
273 gpioSetValue(SSD1306_RST_PORT, SSD1306_RST_PIN, 1);
274
275 #if defined SSD1306_128_32
276 // Init sequence taken from datasheet for UG-2832HSWEG04 (128x32 OLED module)
277 CMD(SSD1306_DISPLAYOFF); // 0xAE
278 CMD(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
279 CMD(0x80); // the suggested ratio 0x80
280 CMD(SSD1306_SETMULTIPLEX); // 0xA8
281 CMD(0x1F); // 31
282 CMD(SSD1306_SETDISPLAYOFFSET); // 0xD3
283 CMD(0x0); // no offset
284 CMD(SSD1306_SETSTARTLINE | 0x0); // line #0
285 CMD(SSD1306_CHARGEPUMP); // 0x8D
286 if (vccstate == SSD1306_EXTERNALVCC)
287 { CMD(0x10) }
288 else
289 { CMD(0x14) }
290 CMD(SSD1306_MEMORYMODE); // 0x20
291 CMD(0x00); // 0x0 act like ks0108
292 CMD(SSD1306_SEGREMAP | 0x1);
293 CMD(SSD1306_COMSCANDEC);
294 CMD(SSD1306_SETCOMPINS); // 0xDA
295 CMD(0x02);
296 CMD(SSD1306_SETCONTRAST); // 0x81
297 if (vccstate == SSD1306_EXTERNALVCC)
298 { CMD(0x9F) }
299 else
300 { CMD(0xCF) }
301 CMD(SSD1306_SETPRECHARGE); // 0xd9
302 if (vccstate == SSD1306_EXTERNALVCC)
303 { CMD(0x22) }
304 else
305 { CMD(0xF1) }
306 CMD(SSD1306_SETVCOMDETECT); // 0xDB
307 CMD(0x40);
308 CMD(SSD1306_DISPLAYALLON_RESUME); // 0xA4
309 CMD(SSD1306_NORMALDISPLAY); // 0xA6
310 #endif
311
312 #if defined SSD1306_128_64
313 // Init sequence taken from datasheet for UG-2864HSWEG01 (128x64 OLED module)
314 CMD(SSD1306_DISPLAYOFF); // 0xAE
315 CMD(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
316 CMD(0x80); // the suggested ratio 0x80
317 CMD(SSD1306_SETMULTIPLEX); // 0xA8
318 CMD(0x3F); // 63
319 CMD(SSD1306_SETDISPLAYOFFSET); // 0xD3
320 CMD(0x0); // no offset
321 CMD(SSD1306_SETSTARTLINE | 0x0); // line #0
322 CMD(SSD1306_CHARGEPUMP); // 0x8D
323 if (vccstate == SSD1306_EXTERNALVCC)
324 { CMD(0x10) }
325 else
326 { CMD(0x14) }
327 CMD(SSD1306_MEMORYMODE); // 0x20
328 CMD(0x00); // 0x0 act like ks0108
329 CMD(SSD1306_SEGREMAP | 0x1);
330 CMD(SSD1306_COMSCANDEC);
331 CMD(SSD1306_SETCOMPINS); // 0xDA
332 CMD(0x12);
333 CMD(SSD1306_SETCONTRAST); // 0x81
334 if (vccstate == SSD1306_EXTERNALVCC)
335 { CMD(0x9F) }
336 else
337 { CMD(0xCF) }
338 CMD(SSD1306_SETPRECHARGE); // 0xd9
339 if (vccstate == SSD1306_EXTERNALVCC)
340 { CMD(0x22) }
341 else
342 { CMD(0xF1) }
343 CMD(SSD1306_SETVCOMDETECT); // 0xDB
344 CMD(0x40);
345 CMD(SSD1306_DISPLAYALLON_RESUME); // 0xA4
346 CMD(SSD1306_NORMALDISPLAY); // 0xA6
347 #endif
348 // Enabled the OLED panel
349 CMD(SSD1306_DISPLAYON);
350 #endif
351
352 // I2C Initialisation
353 #if defined SSD1306_BUS_I2C
354 // Set all pins to output
355 gpioSetDir(SSD1306_RST_PORT, SSD1306_RST_PORT, gpioDirection_Output);
356
357 // Reset the LCD
358 gpioSetValue(SSD1306_RST_PORT, SSD1306_RST_PIN, 1);
359 DELAY(1);
360 gpioSetValue(SSD1306_RST_PORT, SSD1306_RST_PIN, 0);
361 DELAY(10);
362 gpioSetValue(SSD1306_RST_PORT, SSD1306_RST_PIN, 1);
363
364 #if defined SSD1306_128_32
365 // Init sequence taken from datasheet for UG-2832HSWEG04 (128x32 OLED module)
366 ssd1306SendCommand(SSD1306_DISPLAYOFF); // 0xAE
367 ssd1306SendCommand(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
368 ssd1306SendCommand(0x80); // the suggested ratio 0x80
369 ssd1306SendCommand(SSD1306_SETMULTIPLEX); // 0xA8
370 ssd1306SendCommand(0x1F); // 31
371 ssd1306SendCommand(SSD1306_SETDISPLAYOFFSET); // 0xD3
372 ssd1306SendCommand(0x0); // no offset
373 ssd1306SendCommand(SSD1306_SETSTARTLINE | 0x0); // line #0
374 ssd1306SendCommand(SSD1306_CHARGEPUMP); // 0x8D
375 if (vccstate == SSD1306_EXTERNALVCC)
376 { ssd1306SendCommand(0x10); }
377 else
378 { ssd1306SendCommand(0x14); }
379 ssd1306SendCommand(SSD1306_MEMORYMODE); // 0x20
380 ssd1306SendCommand(0x00); // 0x0 act like ks0108
381 ssd1306SendCommand(SSD1306_SEGREMAP | 0x1);
382 ssd1306SendCommand(SSD1306_COMSCANDEC);
383 ssd1306SendCommand(SSD1306_SETCOMPINS); // 0xDA
384 ssd1306SendCommand(0x02);
385 ssd1306SendCommand(SSD1306_SETCONTRAST); // 0x81
386 if (vccstate == SSD1306_EXTERNALVCC)
387 { ssd1306SendCommand(0x9F); }
388 else
389 { ssd1306SendCommand(0xCF); }
390 ssd1306SendCommand(SSD1306_SETPRECHARGE); // 0xd9
391 if (vccstate == SSD1306_EXTERNALVCC)
392 { ssd1306SendCommand(0x22); }
393 else
394 { ssd1306SendCommand(0xF1); }
395 ssd1306SendCommand(SSD1306_SETVCOMDETECT); // 0xDB
396 ssd1306SendCommand(0x40);
397 ssd1306SendCommand(SSD1306_DISPLAYALLON_RESUME); // 0xA4
398 ssd1306SendCommand(SSD1306_NORMALDISPLAY); // 0xA6
399 #endif
400
401 #if defined SSD1306_128_64
402 // Init sequence taken from datasheet for UG-2864HSWEG01 (128x64 OLED module)
403 ssd1306SendCommand(SSD1306_DISPLAYOFF); // 0xAE
404 ssd1306SendCommand(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
405 ssd1306SendCommand(0x80); // the suggested ratio 0x80
406 ssd1306SendCommand(SSD1306_SETMULTIPLEX); // 0xA8
407 ssd1306SendCommand(0x3F); // 63
408 ssd1306SendCommand(SSD1306_SETDISPLAYOFFSET); // 0xD3
409 ssd1306SendCommand(0x0); // no offset
410 ssd1306SendCommand(SSD1306_SETSTARTLINE | 0x0); // line #0
411 ssd1306SendCommand(SSD1306_CHARGEPUMP); // 0x8D
412 if (vccstate == SSD1306_EXTERNALVCC)
413 { ssd1306SendCommand(0x10); }
414 else
415 { ssd1306SendCommand(0x14); }
416 ssd1306SendCommand(SSD1306_MEMORYMODE); // 0x20
417 ssd1306SendCommand(0x00); // 0x0 act like ks0108
418 ssd1306SendCommand(SSD1306_SEGREMAP | 0x1);
419 ssd1306SendCommand(SSD1306_COMSCANDEC);
420 ssd1306SendCommand(SSD1306_SETCOMPINS); // 0xDA
421 ssd1306SendCommand(0x12);
422 ssd1306SendCommand(SSD1306_SETCONTRAST); // 0x81
423 if (vccstate == SSD1306_EXTERNALVCC)
424 { ssd1306SendCommand(0x9F); }
425 else
426 { ssd1306SendCommand(0xCF); }
427 ssd1306SendCommand(SSD1306_SETPRECHARGE); // 0xd9
428 if (vccstate == SSD1306_EXTERNALVCC)
429 { ssd1306SendCommand(0x22); }
430 else
431 { ssd1306SendCommand(0xF1); }
432 ssd1306SendCommand(SSD1306_SETVCOMDETECT); // 0xDB
433 ssd1306SendCommand(0x40);
434 ssd1306SendCommand(SSD1306_DISPLAYALLON_RESUME); // 0xA4
435 ssd1306SendCommand(SSD1306_NORMALDISPLAY); // 0xA6
436 #endif
437 // Enable the OLED panel
438 ssd1306SendCommand(SSD1306_DISPLAYON);
439 #endif
440 }
441
442 /**************************************************************************/
443 /*!
444 @brief Draws a single pixel in image buffer
445
446 @param[in] x
447 The x position (0..127)
448 @param[in] y
449 The y position (0..63)
450 */
451 /**************************************************************************/
452 void ssd1306DrawPixel(uint8_t x, uint8_t y)
453 {
454 if ((x >= SSD1306_LCDWIDTH) || (y >= SSD1306_LCDHEIGHT))
455 return;
456
457 _ssd1306buffer[x+ (y/8)*SSD1306_LCDWIDTH] |= (1 << y%8);
458 }
459
460 /**************************************************************************/
461 /*!
462 @brief Clears a single pixel in image buffer
463
464 @param[in] x
465 The x position (0..127)
466 @param[in] y
467 The y position (0..63)
468 */
469 /**************************************************************************/
470 void ssd1306ClearPixel(uint8_t x, uint8_t y)
471 {
472 if ((x >= SSD1306_LCDWIDTH) || (y >= SSD1306_LCDHEIGHT))
473 return;
474
475 _ssd1306buffer[x+ (y/8)*SSD1306_LCDWIDTH] &= ~(1 << y%8);
476 }
477
478 /**************************************************************************/
479 /*!
480 @brief Gets the value (1 or 0) of the specified pixel from the buffer
481
482 @param[in] x
483 The x position (0..127)
484 @param[in] y
485 The y position (0..63)
486
487 @return 1 if the pixel is enabled, 0 if disabled
488 */
489 /**************************************************************************/
490 uint8_t ssd1306GetPixel(uint8_t x, uint8_t y)
491 {
492 if ((x >= SSD1306_LCDWIDTH) || (y >=SSD1306_LCDHEIGHT)) return 0;
493 return _ssd1306buffer[x+ (y/8)*SSD1306_LCDWIDTH] & (1 << y%8) ? 1 : 0;
494 }
495
496 /**************************************************************************/
497 /*!
498 @brief Clears the screen
499 */
500 /**************************************************************************/
501 void ssd1306ClearScreen()
502 {
503 memset(_ssd1306buffer, 0, 1024);
504 }
505
506 /**************************************************************************/
507 /*!
508 @brief Renders the contents of the pixel buffer on the LCD
509 */
510 /**************************************************************************/
511 void ssd1306Refresh(void)
512 {
513 #if defined SSD1306_BUS_SPI
514 CMD(SSD1306_SETLOWCOLUMN | 0x0); // low col = 0
515 CMD(SSD1306_SETHIGHCOLUMN | 0x0); // hi col = 0
516 CMD(SSD1306_SETSTARTLINE | 0x0); // line #0
517
518 uint16_t i;
519 for (i=0; i<1024; i++)
520 {
521 DATA(_ssd1306buffer[i]);
522 }
523 #endif
524
525 #if defined SSD1306_BUS_I2C
526 ssd1306SendCommand(SSD1306_SETLOWCOLUMN | 0x0); // low col = 0
527 ssd1306SendCommand(SSD1306_SETHIGHCOLUMN | 0x0); // hi col = 0
528 ssd1306SendCommand(SSD1306_SETSTARTLINE | 0x0); // line #0
529
530 uint16_t i;
531 for (i=0; i<1024; i++)
532 {
533 ssd1306SendData(_ssd1306buffer[i]);
534 }
535 #endif
536 }
537
538 /**************************************************************************/
539 /*!
540 @brief Draws a string using the supplied font data.
541
542 @param[in] x
543 Starting x co-ordinate
544 @param[in] y
545 Starting y co-ordinate
546 @param[in] text
547 The string to render
548 @param[in] font
549 Pointer to the FONT_DEF to use when drawing the string
550
551 @section Example
552
553 @code
554
555 #include "drivers/displays/bitmap/ssd1306/ssd1306.h"
556 #include "drivers/displays/smallfonts.h"
557
558 // Configure the pins and initialise the LCD screen
559 ssd1306Init(SSD1306_INTERNALVCC);
560
561 // Render some text on the screen
562 ssd1306DrawString(1, 10, "5x8 System", Font_System5x8);
563 ssd1306DrawString(1, 20, "7x8 System", Font_System7x8);
564
565 // Refresh the screen to see the results
566 ssd1306Refresh();
567
568 @endcode
569 */
570 /**************************************************************************/
571 void ssd1306DrawString(uint16_t x, uint16_t y, char* text, struct FONT_DEF font)
572 {
573 uint8_t l;
574 for (l = 0; l < strlen(text); l++)
575 {
576 ssd1306DrawChar(x + (l * (font.u8Width + 1)), y, text[l], font);
577 }
578 }
579
580 /**************************************************************************/
581 /*!
582 @brief Shifts the contents of the frame buffer up the specified
583 number of pixels
584
585 @param[in] height
586 The number of pixels to shift the frame buffer up, leaving
587 a blank space at the bottom of the frame buffer x pixels
588 high
589
590 @section Example
591
592 @code
593
594 #include "drivers/displays/bitmap/ssd1306/ssd1306.h"
595 #include "drivers/displays/smallfonts.h"
596
597 // Configure the pins and initialise the LCD screen
598 ssd1306Init(SSD1306_INTERNALVCC);
599
600 // Continually write some text, scrolling upward one line each time
601 while (1)
602 {
603 // Shift the buffer up 8 pixels (adjust for font-height)
604 ssd1306ShiftFrameBuffer(8);
605 // Render some text on the screen with different fonts
606 ssd1306DrawString(1, 56, "INSERT TEXT HERE", Font_System5x8);
607 // Refresh the screen to see the results
608 ssd1306Refresh();
609 // Wait a bit before writing the next line
610 systickDelay(1000);
611 }
612
613 @endcode
614 */
615 /**************************************************************************/
616 void ssd1306ShiftFrameBuffer( uint8_t height )
617 {
618 if (height == 0) return;
619 if (height >= SSD1306_LCDHEIGHT)
620 {
621 // Clear the entire frame buffer
622 ssd1306ClearScreen();
623 return;
624 }
625
626 // This is horribly inefficient, but at least easy to understand
627 // In a production environment, this should be significantly optimised
628
629 uint8_t y, x;
630 for (y = 0; y < SSD1306_LCDHEIGHT; y++)
631 {
632 for (x = 0; x < SSD1306_LCDWIDTH; x++)
633 {
634 if ((SSD1306_LCDHEIGHT - 1) - y > height)
635 {
636 // Shift height from further ahead in the buffer
637 ssd1306GetPixel(x, y + height) ? ssd1306DrawPixel(x, y) : ssd1306ClearPixel(x, y);
638 }
639 else
640 {
641 // Clear the entire line
642 ssd1306ClearPixel(x, y);
643 }
644 }
645 }
646 }
This page took 0.091829 seconds and 5 git commands to generate.