b0995ac31a57f5c5b65200ef5489103282861bf6
[hackover2013-badge-firmware.git] / drivers / lcd / bitmap / st7565 / st7565.c
1 /**************************************************************************/
2 /*!
3 @file ST7565.c
4 @author K. Townsend (microBuilder.eu)
5
6 @section DESCRIPTION
7
8 Driver for 128x64 pixel display based on the ST7565 LCD controller.
9
10 This driver is based on the ST7565 Library from Limor Fried
11 (Adafruit Industries) at: http://github.com/adafruit/ST7565-LCD/
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 "st7565.h"
46
47 #include "core/gpio/gpio.h"
48 #include "core/systick/systick.h"
49 #include "drivers/lcd/smallfonts.h"
50
51 void sendByte(uint8_t byte);
52
53 #define CMD(c) do { gpioSetValue( ST7565_A0_PORT, ST7565_A0_PIN, 0 ); sendByte( c ); } while (0);
54 #define DATA(d) do { gpioSetValue( ST7565_A0_PORT, ST7565_A0_PIN, 1 ); sendByte( d ); } while (0);
55 #define DELAY(mS) do { systickDelay( mS / CFG_SYSTICK_DELAY_IN_MS ); } while(0);
56
57 uint8_t buffer[128*64/8];
58
59 /**************************************************************************/
60 /* Private Methods */
61 /**************************************************************************/
62
63 /**************************************************************************/
64 /*!
65 @brief Renders the buffer contents
66
67 @param[in] buffer
68 Pointer to the buffer containing the raw pixel data
69 */
70 /**************************************************************************/
71 void writeBuffer(uint8_t *buffer)
72 {
73 uint8_t c, p;
74 int pagemap[] = { 3, 2, 1, 0, 7, 6, 5, 4 };
75
76 for(p = 0; p < 8; p++)
77 {
78 CMD(ST7565_CMD_SET_PAGE | pagemap[p]);
79 CMD(ST7565_CMD_SET_COLUMN_LOWER | (0x0 & 0xf));
80 CMD(ST7565_CMD_SET_COLUMN_UPPER | ((0x0 >> 4) & 0xf));
81 CMD(ST7565_CMD_RMW);
82 DATA(0xff);
83
84 for(c = 0; c < 128; c++)
85 {
86 DATA(buffer[(128*p)+c]);
87 }
88 }
89 }
90
91 /**************************************************************************/
92 /*!
93 @brief Simulates an SPI write using GPIO
94
95 @param[in] byte
96 The byte to send
97 */
98 /**************************************************************************/
99 void sendByte(uint8_t byte)
100 {
101 int8_t i;
102
103 // Note: This code can be optimised to avoid the branches by setting
104 // GPIO registers directly, but we'll leave it as is for the moment
105 // for simplicity sake
106
107 // Make sure clock pin starts high
108 gpioSetValue(ST7565_SCLK_PORT, ST7565_SCLK_PIN, 1);
109
110 // Write from MSB to LSB
111 for (i=7; i>=0; i--)
112 {
113 // Set clock pin low
114 gpioSetValue(ST7565_SCLK_PORT, ST7565_SCLK_PIN, 0);
115 // Set data pin high or low depending on the value of the current bit
116 gpioSetValue(ST7565_SDAT_PORT, ST7565_SDAT_PIN, byte & (1 << i) ? 1 : 0);
117 // Set clock pin high
118 gpioSetValue(ST7565_SCLK_PORT, ST7565_SCLK_PIN, 1);
119 }
120 }
121
122 /**************************************************************************/
123 /*!
124 @brief Draws a single graphic character using the supplied font
125 */
126 /**************************************************************************/
127 void drawChar(uint16_t x, uint16_t y, uint8_t c, struct FONT_DEF font)
128 {
129 uint8_t col, column[font.u8Width];
130
131 // Check if the requested character is available
132 if ((c >= font.u8FirstChar) && (c <= font.u8LastChar))
133 {
134 // Retrieve appropriate columns from font data
135 for (col = 0; col < font.u8Width; col++)
136 {
137 column[col] = font.au8FontTable[((c - 32) * font.u8Width) + col]; // Get first column of appropriate character
138 }
139 }
140 else
141 {
142 // Requested character is not available in this font ... send a space instead
143 for (col = 0; col < font.u8Width; col++)
144 {
145 column[col] = 0xFF; // Send solid space
146 }
147 }
148
149 // Render each column
150 uint16_t xoffset, yoffset;
151 for (xoffset = 0; xoffset < font.u8Width; xoffset++)
152 {
153 for (yoffset = 0; yoffset < (font.u8Height + 1); yoffset++)
154 {
155 uint8_t bit = 0x00;
156 bit = (column[xoffset] << (8 - (yoffset + 1))); // Shift current row bit left
157 bit = (bit >> 7); // Shift current row but right (results in 0x01 for black, and 0x00 for white)
158 if (bit)
159 {
160 st7565DrawPixel(x + xoffset, y + yoffset);
161 }
162 }
163 }
164 }
165
166 /**************************************************************************/
167 /* Public Methods */
168 /**************************************************************************/
169
170 /**************************************************************************/
171 /*!
172 @brief Initialises the ST7565 LCD display
173 */
174 /**************************************************************************/
175 void st7565Init(void)
176 {
177 // Note: This can be optimised to set all pins to output and high
178 // in two commands by manipulating the registers directly (assuming
179 // that the pins are located in the same GPIO bank). The code is left
180 // as is for clarity sake in case the pins are not all located in the
181 // same bank.
182
183 // Set clock pin to output and high
184 gpioSetDir(ST7565_SCLK_PORT, ST7565_SCLK_PIN, 1);
185 gpioSetValue(ST7565_SCLK_PORT, ST7565_SCLK_PIN, 1);
186
187 // Set data pin to output and high
188 gpioSetDir(ST7565_SDAT_PORT, ST7565_SDAT_PIN, 1);
189 gpioSetValue(ST7565_SDAT_PORT, ST7565_SDAT_PIN, 1);
190
191 // Configure backlight pin to output and set high (off)
192 gpioSetDir(ST7565_BL_PORT, ST7565_BL_PIN, 1);
193 gpioSetValue(ST7565_BL_PORT, ST7565_BL_PIN, 1);
194
195 // Configure A0 pin to output and set high
196 gpioSetDir(ST7565_A0_PORT, ST7565_A0_PIN, 1);
197 gpioSetValue(ST7565_A0_PORT, ST7565_A0_PIN, 1);
198
199 // Configure Reset pin and set high
200 gpioSetDir(ST7565_RST_PORT, ST7565_RST_PIN, 1);
201 gpioSetValue(ST7565_RST_PORT, ST7565_RST_PIN, 1);
202
203 // Configure select pin and set high
204 gpioSetDir(ST7565_CS_PORT, ST7565_CS_PIN, 1);
205 gpioSetValue(ST7565_CS_PORT, ST7565_CS_PIN, 1);
206
207 // Reset
208 gpioSetValue(ST7565_CS_PORT, ST7565_CS_PIN, 0); // Set CS low
209 gpioSetValue(ST7565_RST_PORT, ST7565_RST_PIN, 0); // Set reset low
210 DELAY(500 / CFG_SYSTICK_DELAY_IN_MS); // Wait 500mS
211 gpioSetValue(ST7565_RST_PORT, ST7565_RST_PIN, 1); // Set reset high
212
213 // Configure Display
214 CMD(ST7565_CMD_SET_BIAS_7); // LCD Bias Select
215 CMD(ST7565_CMD_SET_ADC_NORMAL); // ADC Select
216 CMD(ST7565_CMD_SET_COM_NORMAL); // SHL Select
217 CMD(ST7565_CMD_SET_DISP_START_LINE); // Initial Display Line
218 CMD(ST7565_CMD_SET_POWER_CONTROL | 0x04); // Turn on voltage converter (VC=1, VR=0, VF=0)
219 DELAY(50 / CFG_SYSTICK_DELAY_IN_MS); // Wait 50mS
220 CMD(ST7565_CMD_SET_POWER_CONTROL | 0x06); // Turn on voltage regulator (VC=1, VR=1, VF=0)
221 DELAY(50 / CFG_SYSTICK_DELAY_IN_MS); // Wait 50mS
222 CMD(ST7565_CMD_SET_POWER_CONTROL | 0x07); // Turn on voltage follower
223 DELAY(10 / CFG_SYSTICK_DELAY_IN_MS); // Wait 10mS
224 CMD(ST7565_CMD_SET_RESISTOR_RATIO | 0x6); // Set LCD operating voltage
225
226 // Turn display on
227 CMD(ST7565_CMD_DISPLAY_ON);
228 CMD(ST7565_CMD_SET_ALLPTS_NORMAL);
229 st7565SetBrightness(0x18);
230 }
231
232 /**************************************************************************/
233 /*!
234 @brief Enables or disables the backlight
235 */
236 /**************************************************************************/
237 void st7565Backlight(bool state)
238 {
239 gpioSetValue( ST7565_BL_PORT, ST7565_BL_PIN, state ? 0 : 1 );
240 }
241
242 /**************************************************************************/
243 /*!
244 @brief Sets the display brightness
245 */
246 /**************************************************************************/
247 void st7565SetBrightness(uint8_t val)
248 {
249 CMD(ST7565_CMD_SET_VOLUME_FIRST);
250 CMD(ST7565_CMD_SET_VOLUME_SECOND | (val & 0x3f));
251 }
252
253 /**************************************************************************/
254 /*!
255 @brief Clears the screen
256 */
257 /**************************************************************************/
258 void st7565ClearScreen(void)
259 {
260 memset(&buffer, 0x00, 128*64/8);
261 }
262
263 /**************************************************************************/
264 /*!
265 @brief Renders the contents of the pixel buffer on the LCD
266 */
267 /**************************************************************************/
268 void st7565Refresh(void)
269 {
270 writeBuffer(buffer);
271 }
272
273 /**************************************************************************/
274 /*!
275 @brief Draws a single pixel in image buffer
276
277 @param[in] x
278 The x position (0..127)
279 @param[in] y
280 The y position (0..63)
281 */
282 /**************************************************************************/
283 void st7565DrawPixel(uint8_t x, uint8_t y)
284 {
285 if ((x >= 128) || (y >= 64))
286 return;
287
288 // x is which column
289 buffer[x+ (y/8)*128] |= (1 << (7-(y%8)));
290 }
291
292 /**************************************************************************/
293 /*!
294 @brief Clears a single pixel in image buffer
295
296 @param[in] x
297 The x position (0..127)
298 @param[in] y
299 The y position (0..63)
300 */
301 /**************************************************************************/
302 void st7565ClearPixel(uint8_t x, uint8_t y)
303 {
304 if ((x >= 128) || (y >= 64))
305 return;
306
307 // x is which column
308 buffer[x+ (y/8)*128] &= ~(1 << (7-(y%8)));
309 }
310
311 /**************************************************************************/
312 /*!
313 @brief Gets the value (1 or 0) of the specified pixel from the buffer
314
315 @param[in] x
316 The x position (0..127)
317 @param[in] y
318 The y position (0..63)
319
320 @return 1 if the pixel is enabled, 0 if disabled
321 */
322 /**************************************************************************/
323 uint8_t st7565GetPixel(uint8_t x, uint8_t y)
324 {
325 if ((x >= 128) || (y >= 64)) return 0;
326 return buffer[x+ (y/8)*128] & (1 << (7-(y%8)));
327 }
328
329 /**************************************************************************/
330 /*!
331 @brief Draws a string using the supplied font data.
332
333 @param[in] x
334 Starting x co-ordinate
335 @param[in] y
336 Starting y co-ordinate
337 @param[in] text
338 The string to render
339 @param[in] font
340 Pointer to the FONT_DEF to use when drawing the string
341
342 @section Example
343
344 @code
345
346 #include "drivers/lcd/bitmap/st7565/st7565.h"
347 #include "drivers/lcd/smallfonts.h"
348
349 // Configure the pins and initialise the LCD screen
350 st7565Init();
351
352 // Enable the backlight
353 st7565BLEnable();
354
355 // Render some text on the screen with different fonts
356 st7565DrawString(1, 1, "3X6 SYSTEM", Font_System3x6); // 3x6 is UPPER CASE only
357 st7565DrawString(1, 10, "5x8 System", Font_System5x8);
358 st7565DrawString(1, 20, "7x8 System", Font_System7x8);
359
360 // Refresh the screen to see the results
361 st7565Refresh();
362
363 @endcode
364 */
365 /**************************************************************************/
366 void st7565DrawString(uint16_t x, uint16_t y, char* text, struct FONT_DEF font)
367 {
368 uint8_t l;
369 for (l = 0; l < strlen(text); l++)
370 {
371 drawChar(x + (l * (font.u8Width + 1)), y, text[l], font);
372 }
373 }
374
375 /**************************************************************************/
376 /*!
377 @brief Shifts the contents of the frame buffer up the specified
378 number of pixels
379
380 @param[in] height
381 The number of pixels to shift the frame buffer up, leaving
382 a blank space at the bottom of the frame buffer x pixels
383 high
384
385 @section Example
386
387 @code
388
389 #include "drivers/lcd/bitmap/st7565/st7565.h"
390 #include "drivers/lcd/smallfonts.h"
391
392 // Configure the pins and initialise the LCD screen
393 st7565Init();
394
395 // Enable the backlight
396 st7565BLEnable();
397
398 // Continually write some text, scrolling upward one line each time
399 while (1)
400 {
401 // Shift the buffer up 8 pixels (adjust for font-height)
402 st7565ShiftFrameBuffer(8);
403 // Render some text on the screen with different fonts
404 st7565DrawString(1, 56, "INSERT TEXT HERE", Font_System3x6); // 3x6 is UPPER CASE only
405 // Refresh the screen to see the results
406 st7565Refresh();
407 // Wait a bit before writing the next line
408 systickDelay(1000);
409 }
410
411 @endcode
412 */
413 /**************************************************************************/
414 void st7565ShiftFrameBuffer( uint8_t height )
415 {
416 if (height == 0) return;
417 if (height >= 64)
418 {
419 // Clear the entire frame buffer
420 st7565ClearScreen();
421 return;
422 }
423
424 // This is horribly inefficient, but at least easy to understand
425 // In a production environment, this should be significantly optimised
426
427 uint8_t y, x;
428 for (y = 0; y < 64; y++)
429 {
430 for (x = 0; x < 128; x++)
431 {
432 if (63 - y > height)
433 {
434 // Shift height from further ahead in the buffer
435 st7565GetPixel(x, y + height) ? st7565DrawPixel(x, y) : st7565ClearPixel(x, y);
436 }
437 else
438 {
439 // Clear the entire line
440 st7565ClearPixel(x, y);
441 }
442 }
443 }
444 }
445
This page took 0.089306 seconds and 3 git commands to generate.