40d5a04a73b9c31b18c9ef8ba70265ddb46f2d50
[hackover2013-badge-firmware.git] / drivers / lcd / 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) 2010, 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/systick/systick.h"
49 #include "drivers/lcd/smallfonts.h"
50
51 void ssd1306SendByte(uint8_t byte);
52
53 #define CMD(c) do { gpioSetValue( SSD1306_CS_PORT, SSD1306_CS_PIN, 1 ); \
54 gpioSetValue( SSD1306_DC_PORT, SSD1306_DC_PIN, 0 ); \
55 gpioSetValue( SSD1306_CS_PORT, SSD1306_CS_PIN, 0 ); \
56 ssd1306SendByte( c ); \
57 gpioSetValue( SSD1306_CS_PORT, SSD1306_CS_PIN, 1 ); \
58 } while (0);
59 #define DATA(c) do { gpioSetValue( SSD1306_CS_PORT, SSD1306_CS_PIN, 1 ); \
60 gpioSetValue( SSD1306_DC_PORT, SSD1306_DC_PIN, 1 ); \
61 gpioSetValue( SSD1306_CS_PORT, SSD1306_CS_PIN, 0 ); \
62 ssd1306SendByte( c ); \
63 gpioSetValue( SSD1306_CS_PORT, SSD1306_CS_PIN, 1 ); \
64 } while (0);
65 #define DELAY(mS) do { systickDelay( mS / CFG_SYSTICK_DELAY_IN_MS ); } while(0);
66
67 uint8_t buffer[SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8];
68
69 /**************************************************************************/
70 /* Private Methods */
71 /**************************************************************************/
72
73 /**************************************************************************/
74 /*!
75 @brief Simulates an SPI write using GPIO
76
77 @param[in] byte
78 The byte to send
79 */
80 /**************************************************************************/
81 void ssd1306SendByte(uint8_t byte)
82 {
83 int8_t i;
84
85 // Make sure clock pin starts high
86 gpioSetValue(SSD1306_SCLK_PORT, SSD1306_SCLK_PIN, 1);
87
88 // Write from MSB to LSB
89 for (i=7; i>=0; i--)
90 {
91 // Set clock pin low
92 gpioSetValue(SSD1306_SCLK_PORT, SSD1306_SCLK_PIN, 0);
93 // Set data pin high or low depending on the value of the current bit
94 gpioSetValue(SSD1306_SDAT_PORT, SSD1306_SDAT_PIN, byte & (1 << i) ? 1 : 0);
95 // Set clock pin high
96 gpioSetValue(SSD1306_SCLK_PORT, SSD1306_SCLK_PIN, 1);
97 }
98 }
99
100 /**************************************************************************/
101 /*!
102 @brief Draws a single graphic character using the supplied font
103 */
104 /**************************************************************************/
105 static void ssd1306DrawChar(uint16_t x, uint16_t y, uint8_t c, struct FONT_DEF font)
106 {
107 uint8_t col, column[font.u8Width];
108
109 // Check if the requested character is available
110 if ((c >= font.u8FirstChar) && (c <= font.u8LastChar))
111 {
112 // Retrieve appropriate columns from font data
113 for (col = 0; col < font.u8Width; col++)
114 {
115 column[col] = font.au8FontTable[((c - 32) * font.u8Width) + col]; // Get first column of appropriate character
116 }
117 }
118 else
119 {
120 // Requested character is not available in this font ... send a space instead
121 for (col = 0; col < font.u8Width; col++)
122 {
123 column[col] = 0xFF; // Send solid space
124 }
125 }
126
127 // Render each column
128 uint16_t xoffset, yoffset;
129 for (xoffset = 0; xoffset < font.u8Width; xoffset++)
130 {
131 for (yoffset = 0; yoffset < (font.u8Height + 1); yoffset++)
132 {
133 uint8_t bit = 0x00;
134 bit = (column[xoffset] << (8 - (yoffset + 1))); // Shift current row bit left
135 bit = (bit >> 7); // Shift current row but right (results in 0x01 for black, and 0x00 for white)
136 if (bit)
137 {
138 ssd1306DrawPixel(x + xoffset, y + yoffset);
139 }
140 }
141 }
142 }
143
144 /**************************************************************************/
145 /* Public Methods */
146 /**************************************************************************/
147
148 /**************************************************************************/
149 /*!
150 @brief Initialises the SSD1306 LCD display
151 */
152 /**************************************************************************/
153 void ssd1306Init(uint8_t vccstate)
154 {
155 // Set all pins to output
156 gpioSetDir(SSD1306_SCLK_PORT, SSD1306_SCLK_PIN, gpioDirection_Output);
157 gpioSetDir(SSD1306_SDAT_PORT, SSD1306_SDAT_PIN, gpioDirection_Output);
158 gpioSetDir(SSD1306_DC_PORT, SSD1306_DC_PIN, gpioDirection_Output);
159 gpioSetDir(SSD1306_RST_PORT, SSD1306_RST_PIN, gpioDirection_Output);
160 gpioSetDir(SSD1306_CS_PORT, SSD1306_CS_PIN, gpioDirection_Output);
161
162 // Reset the LCD
163 gpioSetValue(SSD1306_RST_PORT, SSD1306_RST_PIN, 1);
164 DELAY(1);
165 gpioSetValue(SSD1306_RST_PORT, SSD1306_RST_PIN, 0);
166 DELAY(10);
167 gpioSetValue(SSD1306_RST_PORT, SSD1306_RST_PIN, 1);
168
169 // Initialisation sequence
170 CMD(SSD1306_DISPLAYOFF); // 0xAE
171 CMD(SSD1306_SETLOWCOLUMN | 0x0); // low col = 0
172 CMD(SSD1306_SETHIGHCOLUMN | 0x0); // hi col = 0
173 CMD(SSD1306_SETSTARTLINE | 0x0); // line #0
174 CMD(SSD1306_SETCONTRAST); // 0x81
175 if (vccstate == SSD1306_EXTERNALVCC)
176 { CMD(0x9F) }
177 else
178 { CMD(0xCF) }
179 CMD(0xa1); // setment remap 95 to 0 (?)
180 CMD(SSD1306_NORMALDISPLAY); // 0xA6
181 CMD(SSD1306_DISPLAYALLON_RESUME); // 0xA4
182 CMD(SSD1306_SETMULTIPLEX); // 0xA8
183 CMD(0x3F); // 0x3F 1/64 duty
184 CMD(SSD1306_SETDISPLAYOFFSET); // 0xD3
185 CMD(0x0); // no offset
186 CMD(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
187 CMD(0x80); // the suggested ratio 0x80
188 CMD(SSD1306_SETPRECHARGE); // 0xd9
189 if (vccstate == SSD1306_EXTERNALVCC)
190 { CMD(0x22) }
191 else
192 { CMD(0xF1) }
193 CMD(SSD1306_SETCOMPINS); // 0xDA
194 CMD(0x12); // disable COM left/right remap
195 CMD(SSD1306_SETVCOMDETECT); // 0xDB
196 CMD(0x40); // 0x20 is default?
197 CMD(SSD1306_MEMORYMODE); // 0x20
198 CMD(0x00); // 0x0 act like ks0108
199 CMD(SSD1306_SEGREMAP | 0x1);
200 CMD(SSD1306_COMSCANDEC);
201 CMD(SSD1306_CHARGEPUMP); //0x8D
202 if (vccstate == SSD1306_EXTERNALVCC)
203 { CMD(0x10) }
204 else
205 { CMD(0x14) }
206
207 // Enabled the OLED panel
208 CMD(SSD1306_DISPLAYON);
209 }
210
211 /**************************************************************************/
212 /*!
213 @brief Draws a single pixel in image buffer
214
215 @param[in] x
216 The x position (0..127)
217 @param[in] y
218 The y position (0..63)
219 */
220 /**************************************************************************/
221 void ssd1306DrawPixel(uint8_t x, uint8_t y)
222 {
223 if ((x >= SSD1306_LCDWIDTH) || (y >= SSD1306_LCDHEIGHT))
224 return;
225
226 buffer[x+ (y/8)*SSD1306_LCDWIDTH] |= (1 << y%8);
227 }
228
229 /**************************************************************************/
230 /*!
231 @brief Clears a single pixel in image buffer
232
233 @param[in] x
234 The x position (0..127)
235 @param[in] y
236 The y position (0..63)
237 */
238 /**************************************************************************/
239 void ssd1306ClearPixel(uint8_t x, uint8_t y)
240 {
241 if ((x >= SSD1306_LCDWIDTH) || (y >= SSD1306_LCDHEIGHT))
242 return;
243
244 buffer[x+ (y/8)*SSD1306_LCDWIDTH] &= ~(1 << y%8);
245 }
246
247 /**************************************************************************/
248 /*!
249 @brief Gets the value (1 or 0) of the specified pixel from the buffer
250
251 @param[in] x
252 The x position (0..127)
253 @param[in] y
254 The y position (0..63)
255
256 @return 1 if the pixel is enabled, 0 if disabled
257 */
258 /**************************************************************************/
259 uint8_t ssd1306GetPixel(uint8_t x, uint8_t y)
260 {
261 if ((x >= SSD1306_LCDWIDTH) || (y >=SSD1306_LCDHEIGHT)) return 0;
262 return buffer[x+ (y/8)*SSD1306_LCDWIDTH] & (1 << y%8) ? 1 : 0;
263 }
264
265 /**************************************************************************/
266 /*!
267 @brief Clears the screen
268 */
269 /**************************************************************************/
270 void ssd1306ClearScreen()
271 {
272 memset(buffer, 0, 1024);
273 }
274
275 /**************************************************************************/
276 /*!
277 @brief Renders the contents of the pixel buffer on the LCD
278 */
279 /**************************************************************************/
280 void ssd1306Refresh(void)
281 {
282 CMD(SSD1306_SETLOWCOLUMN | 0x0); // low col = 0
283 CMD(SSD1306_SETHIGHCOLUMN | 0x0); // hi col = 0
284 CMD(SSD1306_SETSTARTLINE | 0x0); // line #0
285
286 uint16_t i;
287 for (i=0; i<1024; i++)
288 {
289 DATA(buffer[i]);
290 }
291 }
292
293 /**************************************************************************/
294 /*!
295 @brief Draws a string using the supplied font data.
296
297 @param[in] x
298 Starting x co-ordinate
299 @param[in] y
300 Starting y co-ordinate
301 @param[in] text
302 The string to render
303 @param[in] font
304 Pointer to the FONT_DEF to use when drawing the string
305
306 @section Example
307
308 @code
309
310 #include "drivers/lcd/bitmap/ssd1306/ssd1306.h"
311 #include "drivers/lcd/smallfonts.h"
312
313 // Configure the pins and initialise the LCD screen
314 ssd1306Init(SSD1306_INTERNALVCC);
315
316 // Render some text on the screen
317 ssd1306DrawString(1, 10, "5x8 System", Font_System5x8);
318 ssd1306DrawString(1, 20, "7x8 System", Font_System7x8);
319
320 // Refresh the screen to see the results
321 ssd1306Refresh();
322
323 @endcode
324 */
325 /**************************************************************************/
326 void ssd1306DrawString(uint16_t x, uint16_t y, char* text, struct FONT_DEF font)
327 {
328 uint8_t l;
329 for (l = 0; l < strlen(text); l++)
330 {
331 ssd1306DrawChar(x + (l * (font.u8Width + 1)), y, text[l], font);
332 }
333 }
334
335 /**************************************************************************/
336 /*!
337 @brief Shifts the contents of the frame buffer up the specified
338 number of pixels
339
340 @param[in] height
341 The number of pixels to shift the frame buffer up, leaving
342 a blank space at the bottom of the frame buffer x pixels
343 high
344
345 @section Example
346
347 @code
348
349 #include "drivers/lcd/bitmap/ssd1306/ssd1306.h"
350 #include "drivers/lcd/smallfonts.h"
351
352 // Configure the pins and initialise the LCD screen
353 ssd1306Init();
354
355 // Enable the backlight
356 ssd1306BLEnable();
357
358 // Continually write some text, scrolling upward one line each time
359 while (1)
360 {
361 // Shift the buffer up 8 pixels (adjust for font-height)
362 ssd1306ShiftFrameBuffer(8);
363 // Render some text on the screen with different fonts
364 ssd1306DrawString(1, 56, "INSERT TEXT HERE", Font_System5x8);
365 // Refresh the screen to see the results
366 ssd1306Refresh();
367 // Wait a bit before writing the next line
368 systickDelay(1000);
369 }
370
371 @endcode
372 */
373 /**************************************************************************/
374 void ssd1306ShiftFrameBuffer( uint8_t height )
375 {
376 if (height == 0) return;
377 if (height >= SSD1306_LCDHEIGHT)
378 {
379 // Clear the entire frame buffer
380 ssd1306ClearScreen();
381 return;
382 }
383
384 // This is horribly inefficient, but at least easy to understand
385 // In a production environment, this should be significantly optimised
386
387 uint8_t y, x;
388 for (y = 0; y < SSD1306_LCDHEIGHT; y++)
389 {
390 for (x = 0; x < SSD1306_LCDWIDTH; x++)
391 {
392 if ((SSD1306_LCDHEIGHT - 1) - y > height)
393 {
394 // Shift height from further ahead in the buffer
395 ssd1306GetPixel(x, y + height) ? ssd1306DrawPixel(x, y) : ssd1306ClearPixel(x, y);
396 }
397 else
398 {
399 // Clear the entire line
400 ssd1306ClearPixel(x, y);
401 }
402 }
403 }
404 }
This page took 0.077429 seconds and 3 git commands to generate.