]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_LM3S811_KEIL/LuminaryCode/osram96x16.c
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@44 1d2547de-c912-0410-9cb9...
[freertos] / Demo / CORTEX_LM3S811_KEIL / LuminaryCode / osram96x16.c
1 //*****************************************************************************\r
2 //\r
3 // osram96x16.c - Driver for the OSRAM 96x16 graphical OLED display.\r
4 //\r
5 // Copyright (c) 2006 Luminary Micro, Inc.  All rights reserved.\r
6 //\r
7 // Software License Agreement\r
8 //\r
9 // Luminary Micro, Inc. (LMI) is supplying this software for use solely and\r
10 // exclusively on LMI's Stellaris Family of microcontroller products.\r
11 //\r
12 // The software is owned by LMI and/or its suppliers, and is protected under\r
13 // applicable copyright laws.  All rights are reserved.  Any use in violation\r
14 // of the foregoing restrictions may subject the user to criminal sanctions\r
15 // under applicable laws, as well as to civil liability for the breach of the\r
16 // terms and conditions of this license.\r
17 //\r
18 // THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED\r
19 // OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF\r
20 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.\r
21 // LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR\r
22 // CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.\r
23 //\r
24 // This is part of revision 816 of the Stellaris Driver Library.\r
25 //\r
26 //*****************************************************************************\r
27 \r
28 //*****************************************************************************\r
29 //\r
30 //! \addtogroup ev_lm3s811_api\r
31 //! @{\r
32 //\r
33 //*****************************************************************************\r
34 \r
35 #include "hw_i2c.h"\r
36 #include "hw_memmap.h"\r
37 #include "hw_sysctl.h"\r
38 #include "hw_types.h"\r
39 #include "src/debug.h"\r
40 #include "src/gpio.h"\r
41 #include "src/i2c.h"\r
42 #include "src/sysctl.h"\r
43 #include "osram96x16.h"\r
44 \r
45 //*****************************************************************************\r
46 //\r
47 // The I2C slave address of the SSD0303 controller on the OLED display.\r
48 //\r
49 //*****************************************************************************\r
50 #define SSD0303_ADDR            0x3d\r
51 \r
52 //*****************************************************************************\r
53 //\r
54 // A 5x7 font (in a 6x8 cell, where the sixth column is omitted from this\r
55 // table) for displaying text on the OLED display.  The data is organized as\r
56 // bytes from the left column to the right column, with each byte containing\r
57 // the top row in the LSB and the bottom row in the MSB.\r
58 //\r
59 //*****************************************************************************\r
60 static const unsigned char g_pucFont[95][5] =\r
61 {\r
62     { 0x00, 0x00, 0x00, 0x00, 0x00 }, // " "\r
63     { 0x00, 0x00, 0x4f, 0x00, 0x00 }, // !\r
64     { 0x00, 0x07, 0x00, 0x07, 0x00 }, // "\r
65     { 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // #\r
66     { 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $\r
67     { 0x23, 0x13, 0x08, 0x64, 0x62 }, // %\r
68     { 0x36, 0x49, 0x55, 0x22, 0x50 }, // &\r
69     { 0x00, 0x05, 0x03, 0x00, 0x00 }, // '\r
70     { 0x00, 0x1c, 0x22, 0x41, 0x00 }, // (\r
71     { 0x00, 0x41, 0x22, 0x1c, 0x00 }, // )\r
72     { 0x14, 0x08, 0x3e, 0x08, 0x14 }, // *\r
73     { 0x08, 0x08, 0x3e, 0x08, 0x08 }, // +\r
74     { 0x00, 0x50, 0x30, 0x00, 0x00 }, // ,\r
75     { 0x08, 0x08, 0x08, 0x08, 0x08 }, // -\r
76     { 0x00, 0x60, 0x60, 0x00, 0x00 }, // .\r
77     { 0x20, 0x10, 0x08, 0x04, 0x02 }, // /\r
78     { 0x3e, 0x51, 0x49, 0x45, 0x3e }, // 0\r
79     { 0x00, 0x42, 0x7f, 0x40, 0x00 }, // 1\r
80     { 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2\r
81     { 0x21, 0x41, 0x45, 0x4b, 0x31 }, // 3\r
82     { 0x18, 0x14, 0x12, 0x7f, 0x10 }, // 4\r
83     { 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5\r
84     { 0x3c, 0x4a, 0x49, 0x49, 0x30 }, // 6\r
85     { 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7\r
86     { 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8\r
87     { 0x06, 0x49, 0x49, 0x29, 0x1e }, // 9\r
88     { 0x00, 0x36, 0x36, 0x00, 0x00 }, // :\r
89     { 0x00, 0x56, 0x36, 0x00, 0x00 }, // ;\r
90     { 0x08, 0x14, 0x22, 0x41, 0x00 }, // <\r
91     { 0x14, 0x14, 0x14, 0x14, 0x14 }, // =\r
92     { 0x00, 0x41, 0x22, 0x14, 0x08 }, // >\r
93     { 0x02, 0x01, 0x51, 0x09, 0x06 }, // ?\r
94     { 0x32, 0x49, 0x79, 0x41, 0x3e }, // @\r
95     { 0x7e, 0x11, 0x11, 0x11, 0x7e }, // A\r
96     { 0x7f, 0x49, 0x49, 0x49, 0x36 }, // B\r
97     { 0x3e, 0x41, 0x41, 0x41, 0x22 }, // C\r
98     { 0x7f, 0x41, 0x41, 0x22, 0x1c }, // D\r
99     { 0x7f, 0x49, 0x49, 0x49, 0x41 }, // E\r
100     { 0x7f, 0x09, 0x09, 0x09, 0x01 }, // F\r
101     { 0x3e, 0x41, 0x49, 0x49, 0x7a }, // G\r
102     { 0x7f, 0x08, 0x08, 0x08, 0x7f }, // H\r
103     { 0x00, 0x41, 0x7f, 0x41, 0x00 }, // I\r
104     { 0x20, 0x40, 0x41, 0x3f, 0x01 }, // J\r
105     { 0x7f, 0x08, 0x14, 0x22, 0x41 }, // K\r
106     { 0x7f, 0x40, 0x40, 0x40, 0x40 }, // L\r
107     { 0x7f, 0x02, 0x0c, 0x02, 0x7f }, // M\r
108     { 0x7f, 0x04, 0x08, 0x10, 0x7f }, // N\r
109     { 0x3e, 0x41, 0x41, 0x41, 0x3e }, // O\r
110     { 0x7f, 0x09, 0x09, 0x09, 0x06 }, // P\r
111     { 0x3e, 0x41, 0x51, 0x21, 0x5e }, // Q\r
112     { 0x7f, 0x09, 0x19, 0x29, 0x46 }, // R\r
113     { 0x46, 0x49, 0x49, 0x49, 0x31 }, // S\r
114     { 0x01, 0x01, 0x7f, 0x01, 0x01 }, // T\r
115     { 0x3f, 0x40, 0x40, 0x40, 0x3f }, // U\r
116     { 0x1f, 0x20, 0x40, 0x20, 0x1f }, // V\r
117     { 0x3f, 0x40, 0x38, 0x40, 0x3f }, // W\r
118     { 0x63, 0x14, 0x08, 0x14, 0x63 }, // X\r
119     { 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y\r
120     { 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z\r
121     { 0x00, 0x7f, 0x41, 0x41, 0x00 }, // [\r
122     { 0x02, 0x04, 0x08, 0x10, 0x20 }, // "\"\r
123     { 0x00, 0x41, 0x41, 0x7f, 0x00 }, // ]\r
124     { 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^\r
125     { 0x40, 0x40, 0x40, 0x40, 0x40 }, // _\r
126     { 0x00, 0x01, 0x02, 0x04, 0x00 }, // `\r
127     { 0x20, 0x54, 0x54, 0x54, 0x78 }, // a\r
128     { 0x7f, 0x48, 0x44, 0x44, 0x38 }, // b\r
129     { 0x38, 0x44, 0x44, 0x44, 0x20 }, // c\r
130     { 0x38, 0x44, 0x44, 0x48, 0x7f }, // d\r
131     { 0x38, 0x54, 0x54, 0x54, 0x18 }, // e\r
132     { 0x08, 0x7e, 0x09, 0x01, 0x02 }, // f\r
133     { 0x0c, 0x52, 0x52, 0x52, 0x3e }, // g\r
134     { 0x7f, 0x08, 0x04, 0x04, 0x78 }, // h\r
135     { 0x00, 0x44, 0x7d, 0x40, 0x00 }, // i\r
136     { 0x20, 0x40, 0x44, 0x3d, 0x00 }, // j\r
137     { 0x7f, 0x10, 0x28, 0x44, 0x00 }, // k\r
138     { 0x00, 0x41, 0x7f, 0x40, 0x00 }, // l\r
139     { 0x7c, 0x04, 0x18, 0x04, 0x78 }, // m\r
140     { 0x7c, 0x08, 0x04, 0x04, 0x78 }, // n\r
141     { 0x38, 0x44, 0x44, 0x44, 0x38 }, // o\r
142     { 0x7c, 0x14, 0x14, 0x14, 0x08 }, // p\r
143     { 0x08, 0x14, 0x14, 0x18, 0x7c }, // q\r
144     { 0x7c, 0x08, 0x04, 0x04, 0x08 }, // r\r
145     { 0x48, 0x54, 0x54, 0x54, 0x20 }, // s\r
146     { 0x04, 0x3f, 0x44, 0x40, 0x20 }, // t\r
147     { 0x3c, 0x40, 0x40, 0x20, 0x7c }, // u\r
148     { 0x1c, 0x20, 0x40, 0x20, 0x1c }, // v\r
149     { 0x3c, 0x40, 0x30, 0x40, 0x3c }, // w\r
150     { 0x44, 0x28, 0x10, 0x28, 0x44 }, // x\r
151     { 0x0c, 0x50, 0x50, 0x50, 0x3c }, // y\r
152     { 0x44, 0x64, 0x54, 0x4c, 0x44 }, // z\r
153     { 0x00, 0x08, 0x36, 0x41, 0x00 }, // {\r
154     { 0x00, 0x00, 0x7f, 0x00, 0x00 }, // |\r
155     { 0x00, 0x41, 0x36, 0x08, 0x00 }, // }\r
156     { 0x02, 0x01, 0x02, 0x04, 0x02 }, // ~\r
157 };\r
158 \r
159 //*****************************************************************************\r
160 //\r
161 // The sequence of commands used to initialize the SSD0303 controller.  Each\r
162 // command is described as follows:  there is a byte specifying the number of\r
163 // bytes in the I2C transfer, followed by that many bytes of command data.\r
164 //\r
165 //*****************************************************************************\r
166 static const unsigned char g_pucOSRAMInit[] =\r
167 {\r
168     //\r
169     // Turn off the panel\r
170     //\r
171     0x02, 0x80, 0xae,\r
172 \r
173     //\r
174     // Set lower column address\r
175     //\r
176     0x02, 0x80, 0x04,\r
177 \r
178     //\r
179     // Set higher column address\r
180     //\r
181     0x02, 0x80, 0x12,\r
182 \r
183     //\r
184     // Set contrast control register\r
185     //\r
186     0x04, 0x80, 0x81, 0x80, 0x2b,\r
187 \r
188     //\r
189     // Set segment re-map\r
190     //\r
191     0x02, 0x80, 0xa1,\r
192 \r
193     //\r
194     // Set display start line\r
195     //\r
196     0x02, 0x80, 0x40,\r
197 \r
198     //\r
199     // Set display offset\r
200     //\r
201     0x04, 0x80, 0xd3, 0x80, 0x00,\r
202 \r
203     //\r
204     // Set multiplex ratio\r
205     //\r
206     0x04, 0x80, 0xa8, 0x80, 0x0f,\r
207 \r
208     //\r
209     // Set the display to normal mode\r
210     //\r
211     0x02, 0x80, 0xa4,\r
212 \r
213     //\r
214     // Non-inverted display\r
215     //\r
216     0x02, 0x80, 0xa6,\r
217 \r
218     //\r
219     // Set the page address\r
220     //\r
221     0x02, 0x80, 0xb0,\r
222 \r
223     //\r
224     // Set COM output scan direction\r
225     //\r
226     0x02, 0x80, 0xc8,\r
227 \r
228     //\r
229     // Set display clock divide ratio/oscillator frequency\r
230     //\r
231     0x04, 0x80, 0xd5, 0x80, 0x72,\r
232 \r
233     //\r
234     // Enable mono mode\r
235     //\r
236     0x04, 0x80, 0xd8, 0x80, 0x00,\r
237 \r
238     //\r
239     // Set pre-charge period\r
240     //\r
241     0x04, 0x80, 0xd9, 0x80, 0x22,\r
242 \r
243     //\r
244     // Set COM pins hardware configuration\r
245     //\r
246     0x04, 0x80, 0xda, 0x80, 0x12,\r
247 \r
248     //\r
249     // Set VCOM deslect level\r
250     //\r
251     0x04, 0x80, 0xdb, 0x80, 0x0f,\r
252 \r
253     //\r
254     // Set DC-DC on\r
255     //\r
256     0x04, 0x80, 0xad, 0x80, 0x8b,\r
257 \r
258     //\r
259     // Turn on the panel\r
260     //\r
261     0x02, 0x80, 0xaf,\r
262 };\r
263 \r
264 //*****************************************************************************\r
265 //\r
266 // The inter-byte delay required by the SSD0303 OLED controller.\r
267 //\r
268 //*****************************************************************************\r
269 static unsigned long g_ulDelay;\r
270 \r
271 //*****************************************************************************\r
272 //\r
273 //! \internal\r
274 //!\r
275 //! Provide a small delay.\r
276 //!\r
277 //! \param ulCount is the number of delay loop iterations to perform.\r
278 //!\r
279 //! Since the SSD0303 controller needs a delay between bytes written to it over\r
280 //! the I2C bus, this function provides a means of generating that delay.  It\r
281 //! is written in assembly to keep the delay consistent across tool chains,\r
282 //! avoiding the need to tune the delay based on the tool chain in use.\r
283 //!\r
284 //! \return None.\r
285 //\r
286 //*****************************************************************************\r
287 #if defined(ewarm)\r
288 static void\r
289 OSRAMDelay(unsigned long ulCount)\r
290 {\r
291     __asm("    subs    r0, #1\n"\r
292           "    bne     OSRAMDelay\n"\r
293           "    bx      lr");\r
294 }\r
295 #endif\r
296 #if defined(gcc)\r
297 static void __attribute__((naked))\r
298 OSRAMDelay(unsigned long ulCount)\r
299 {\r
300     __asm("    subs    r0, #1\n"\r
301           "    bne     OSRAMDelay\n"\r
302           "    bx      lr");\r
303 }\r
304 #endif\r
305 #if defined(rvmdk) || defined(__ARMCC_VERSION)\r
306 __asm void\r
307 OSRAMDelay(unsigned long ulCount)\r
308 {\r
309     subs    r0, #1;\r
310     bne     OSRAMDelay;\r
311     bx      lr;\r
312 }\r
313 #endif\r
314 \r
315 //*****************************************************************************\r
316 //\r
317 //! \internal\r
318 //!\r
319 //! Start a transfer to the SSD0303 controller.\r
320 //!\r
321 //! \param ucChar is the first byte to be written to the controller.\r
322 //!\r
323 //! This function will start a transfer to the SSD0303 controller via the I2C\r
324 //! bus.\r
325 //!\r
326 //! The data is written in a polled fashion; this function will not return\r
327 //! until the byte has been written to the controller.\r
328 //!\r
329 //! \return None.\r
330 //\r
331 //*****************************************************************************\r
332 static void\r
333 OSRAMWriteFirst(unsigned char ucChar)\r
334 {\r
335     //\r
336     // Set the slave address.\r
337     //\r
338     I2CMasterSlaveAddrSet(I2C_MASTER_BASE, SSD0303_ADDR, false);\r
339 \r
340     //\r
341     // Write the first byte to the controller.\r
342     //\r
343     I2CMasterDataPut(I2C_MASTER_BASE, ucChar);\r
344 \r
345     //\r
346     // Start the transfer.\r
347     //\r
348     I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);\r
349 }\r
350 \r
351 //*****************************************************************************\r
352 //\r
353 //! \internal\r
354 //!\r
355 //! Write a byte to the SSD0303 controller.\r
356 //!\r
357 //! \param ucChar is the byte to be transmitted to the controller.\r
358 //!\r
359 //! This function continues a transfer to the SSD0303 controller by writing\r
360 //! another byte over the I2C bus.  This must only be called after calling\r
361 //! OSRAMWriteFirst(), but before calling OSRAMWriteFinal().\r
362 //!\r
363 //! The data is written in a polled faashion; this function will not return\r
364 //! until the byte has been written to the controller.\r
365 //!\r
366 //! \return None.\r
367 //\r
368 //*****************************************************************************\r
369 static void\r
370 OSRAMWriteByte(unsigned char ucChar)\r
371 {\r
372     //\r
373     // Wait until the current byte has been transferred.\r
374     //\r
375     while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)\r
376     {\r
377     }\r
378 \r
379     //\r
380     // Provide the required inter-byte delay.\r
381     //\r
382     OSRAMDelay(g_ulDelay);\r
383 \r
384     //\r
385     // Write the next byte to the controller.\r
386     //\r
387     I2CMasterDataPut(I2C_MASTER_BASE, ucChar);\r
388 \r
389     //\r
390     // Continue the transfer.\r
391     //\r
392     I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);\r
393 }\r
394 \r
395 //*****************************************************************************\r
396 //\r
397 //! \internal\r
398 //!\r
399 //! Write a sequence of bytes to the SSD0303 controller.\r
400 //!\r
401 //! This function continues a transfer to the SSD0303 controller by writing a\r
402 //! sequence of bytes over the I2C bus.  This must only be called after calling\r
403 //! OSRAMWriteFirst(), but before calling OSRAMWriteFinal().\r
404 //!\r
405 //! The data is written in a polled fashion; this function will not return\r
406 //! until the entire byte sequence has been written to the controller.\r
407 //!\r
408 //! \return None.\r
409 //\r
410 //*****************************************************************************\r
411 static void\r
412 OSRAMWriteArray(const unsigned char *pucBuffer, unsigned long ulCount)\r
413 {\r
414     //\r
415     // Loop while there are more bytes left to be transferred.\r
416     //\r
417     while(ulCount != 0)\r
418     {\r
419         //\r
420         // Wait until the current byte has been transferred.\r
421         //\r
422         while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)\r
423         {\r
424         }\r
425 \r
426         //\r
427         // Provide the required inter-byte delay.\r
428         //\r
429         OSRAMDelay(g_ulDelay);\r
430 \r
431         //\r
432         // Write the next byte to the controller.\r
433         //\r
434         I2CMasterDataPut(I2C_MASTER_BASE, *pucBuffer++);\r
435         ulCount--;\r
436 \r
437         //\r
438         // Continue the transfer.\r
439         //\r
440         I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);\r
441     }\r
442 }\r
443 \r
444 //*****************************************************************************\r
445 //\r
446 //! \internal\r
447 //!\r
448 //! Finish a transfer to the SSD0303 controller.\r
449 //!\r
450 //! \param ucChar is the final byte to be written to the controller.\r
451 //!\r
452 //! This function will finish a transfer to the SSD0303 controller via the I2C\r
453 //! bus.  This must only be called after calling OSRAMWriteFirst().\r
454 //!\r
455 //! The data is written in a polled fashion; this function will not return\r
456 //! until the byte has been written to the controller.\r
457 //!\r
458 //! \return None.\r
459 //\r
460 //*****************************************************************************\r
461 static void\r
462 OSRAMWriteFinal(unsigned char ucChar)\r
463 {\r
464     //\r
465     // Wait until the current byte has been transferred.\r
466     //\r
467     while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)\r
468     {\r
469     }\r
470 \r
471     //\r
472     // Provide the required inter-byte delay.\r
473     //\r
474     OSRAMDelay(g_ulDelay);\r
475 \r
476     //\r
477     // Write the final byte to the controller.\r
478     //\r
479     I2CMasterDataPut(I2C_MASTER_BASE, ucChar);\r
480 \r
481     //\r
482     // Finish the transfer.\r
483     //\r
484     I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);\r
485 \r
486     //\r
487     // Wait until the final byte has been transferred.\r
488     //\r
489     while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)\r
490     {\r
491     }\r
492 \r
493     //\r
494     // Provide the required inter-byte delay.\r
495     //\r
496     OSRAMDelay(g_ulDelay);\r
497 }\r
498 \r
499 //*****************************************************************************\r
500 //\r
501 //! Clears the OLED display.\r
502 //!\r
503 //! This function will clear the display.  All pixels in the display will be\r
504 //! turned off.\r
505 //!\r
506 //! \return None.\r
507 //\r
508 //*****************************************************************************\r
509 void\r
510 OSRAMClear(void)\r
511 {\r
512     static const unsigned char pucRow1[] =\r
513     {\r
514         0xb0, 0x80, 0x04, 0x80, 0x12, 0x40\r
515     };\r
516     static const unsigned char pucRow2[] =\r
517     {\r
518         0xb1, 0x80, 0x04, 0x80, 0x12, 0x40\r
519     };\r
520     unsigned long ulIdx;\r
521 \r
522     //\r
523     // Move the display cursor to the first column of the first row.\r
524     //\r
525     OSRAMWriteFirst(0x80);\r
526     OSRAMWriteArray(pucRow1, sizeof(pucRow1));\r
527 \r
528     //\r
529     // Fill this row with zeros.\r
530     //\r
531     for(ulIdx = 0; ulIdx < 95; ulIdx++)\r
532     {\r
533         OSRAMWriteByte(0x00);\r
534     }\r
535     OSRAMWriteFinal(0x00);\r
536 \r
537     //\r
538     // Move the display cursor to the first column of the second row.\r
539     //\r
540     OSRAMWriteFirst(0x80);\r
541     OSRAMWriteArray(pucRow2, sizeof(pucRow2));\r
542 \r
543     //\r
544     // Fill this row with zeros.\r
545     //\r
546     for(ulIdx = 0; ulIdx < 95; ulIdx++)\r
547     {\r
548         OSRAMWriteByte(0x00);\r
549     }\r
550     OSRAMWriteFinal(0x00);\r
551 }\r
552 \r
553 //*****************************************************************************\r
554 //\r
555 //! Displays a string on the OLED display.\r
556 //!\r
557 //! \param pcStr is a pointer to the string to display.\r
558 //! \param ulX is the horizontal position to display the string, specified in\r
559 //! columns from the left edge of the display.\r
560 //! \param ulY is the vertical position to display the string, specified in\r
561 //! eight scan line blocks from the top of the display (i.e. only 0 and 1 are\r
562 //! valid).\r
563 //!\r
564 //! This function will draw a string on the display.  Only the ASCII characters\r
565 //! between 32 (space) and 126 (tilde) are supported; other characters will\r
566 //! result in random data being draw on the display (based on whatever appears\r
567 //! before/after the font in memory).  The font is mono-spaced, so characters\r
568 //! such as "i" and "l" have more white space around them than characters such\r
569 //! as "m" or "w".\r
570 //!\r
571 //! If the drawing of the string reaches the right edge of the display, no more\r
572 //! characters will be drawn.  Therefore, special care is not required to avoid\r
573 //! supplying a string that is "too long" to display.\r
574 //!\r
575 //! \return None.\r
576 //\r
577 //*****************************************************************************\r
578 void\r
579 OSRAMStringDraw(const char *pcStr, unsigned long ulX, unsigned long ulY)\r
580 {\r
581     //\r
582     // Check the arguments.\r
583     //\r
584     ASSERT(ulX < 96);\r
585     ASSERT(ulY < 2);\r
586 \r
587     //\r
588     // Move the display cursor to the requested position on the display.\r
589     //\r
590     OSRAMWriteFirst(0x80);\r
591     OSRAMWriteByte((ulY == 0) ? 0xb0 : 0xb1);\r
592     OSRAMWriteByte(0x80);\r
593     OSRAMWriteByte((ulX + 36) & 0x0f);\r
594     OSRAMWriteByte(0x80);\r
595     OSRAMWriteByte(0x10 | (((ulX + 36) >> 4) & 0x0f));\r
596     OSRAMWriteByte(0x40);\r
597 \r
598     //\r
599     // Loop while there are more characters in the string.\r
600     //\r
601     while(*pcStr != 0)\r
602     {\r
603         //\r
604         // See if there is enough space on the display for this entire\r
605         // character.\r
606         //\r
607         if(ulX <= 90)\r
608         {\r
609             //\r
610             // Write the contents of this character to the display.\r
611             //\r
612             OSRAMWriteArray(g_pucFont[*pcStr - ' '], 5);\r
613 \r
614             //\r
615             // See if this is the last character to display (either because the\r
616             // right edge has been reached or because there are no more\r
617             // characters).\r
618             //\r
619             if((ulX == 90) || (pcStr[1] == 0))\r
620             {\r
621                 //\r
622                 // Write the final column of the display.\r
623                 //\r
624                 OSRAMWriteFinal(0x00);\r
625 \r
626                 //\r
627                 // The string has been displayed.\r
628                 //\r
629                 return;\r
630             }\r
631 \r
632             //\r
633             // Write the inter-character padding column.\r
634             //\r
635             OSRAMWriteByte(0x00);\r
636         }\r
637         else\r
638         {\r
639             //\r
640             // Write the portion of the character that will fit onto the\r
641             // display.\r
642             //\r
643             OSRAMWriteArray(g_pucFont[*pcStr - ' '], 95 - ulX);\r
644             OSRAMWriteFinal(g_pucFont[*pcStr - ' '][95 - ulX]);\r
645 \r
646             //\r
647             // The string has been displayed.\r
648             //\r
649             return;\r
650         }\r
651 \r
652         //\r
653         // Advance to the next character.\r
654         //\r
655         pcStr++;\r
656 \r
657         //\r
658         // Increment the X coordinate by the six columns that were just\r
659         // written.\r
660         //\r
661         ulX += 6;\r
662     }\r
663 }\r
664 \r
665 //*****************************************************************************\r
666 //\r
667 //! Displays an image on the OLED display.\r
668 //!\r
669 //! \param pucImage is a pointer to the image data.\r
670 //! \param ulX is the horizontal position to display this image, specified in\r
671 //! columns from the left edge of the display.\r
672 //! \param ulY is the vertical position to display this image, specified in\r
673 //! eight scan line blocks from the top of the display (i.e. only 0 and 1 are\r
674 //! valid).\r
675 //! \param ulWidth is the width of the image, specified in columns.\r
676 //! \param ulHeight is the height of the image, specified in eight row blocks\r
677 //! (i.e. only 1 and 2 are valid).\r
678 //!\r
679 //! This function will display a bitmap graphic on the display.  The image to\r
680 //! be displayed must be a multiple of eight scan lines high (i.e. one row) and\r
681 //! will be drawn at a vertical position that is a multiple of eight scan lines\r
682 //! (i.e. scan line zero or scan line eight, corresponding to row zero or row\r
683 //! one).\r
684 //!\r
685 //! The image data is organized with the first row of image data appearing left\r
686 //! to right, followed immediately by the second row of image data.  Each byte\r
687 //! contains the data for the eight scan lines of the column, with the top scan\r
688 //! line being in the least significant bit of the byte and the bottom scan\r
689 //! line being in the most significant bit of the byte.\r
690 //!\r
691 //! For example, an image four columns wide and sixteen scan lines tall would\r
692 //! be arranged as follows (showing how the eight bytes of the image would\r
693 //! appear on the display):\r
694 //!\r
695 //! \verbatim\r
696 //!     +-------+  +-------+  +-------+  +-------+\r
697 //!     |   | 0 |  |   | 0 |  |   | 0 |  |   | 0 |\r
698 //!     | B | 1 |  | B | 1 |  | B | 1 |  | B | 1 |\r
699 //!     | y | 2 |  | y | 2 |  | y | 2 |  | y | 2 |\r
700 //!     | t | 3 |  | t | 3 |  | t | 3 |  | t | 3 |\r
701 //!     | e | 4 |  | e | 4 |  | e | 4 |  | e | 4 |\r
702 //!     |   | 5 |  |   | 5 |  |   | 5 |  |   | 5 |\r
703 //!     | 0 | 6 |  | 1 | 6 |  | 2 | 6 |  | 3 | 6 |\r
704 //!     |   | 7 |  |   | 7 |  |   | 7 |  |   | 7 |\r
705 //!     +-------+  +-------+  +-------+  +-------+\r
706 //!\r
707 //!     +-------+  +-------+  +-------+  +-------+\r
708 //!     |   | 0 |  |   | 0 |  |   | 0 |  |   | 0 |\r
709 //!     | B | 1 |  | B | 1 |  | B | 1 |  | B | 1 |\r
710 //!     | y | 2 |  | y | 2 |  | y | 2 |  | y | 2 |\r
711 //!     | t | 3 |  | t | 3 |  | t | 3 |  | t | 3 |\r
712 //!     | e | 4 |  | e | 4 |  | e | 4 |  | e | 4 |\r
713 //!     |   | 5 |  |   | 5 |  |   | 5 |  |   | 5 |\r
714 //!     | 4 | 6 |  | 5 | 6 |  | 6 | 6 |  | 7 | 6 |\r
715 //!     |   | 7 |  |   | 7 |  |   | 7 |  |   | 7 |\r
716 //!     +-------+  +-------+  +-------+  +-------+\r
717 //! \endverbatim\r
718 //!\r
719 //! \return None.\r
720 //\r
721 //*****************************************************************************\r
722 void\r
723 OSRAMImageDraw(const unsigned char *pucImage, unsigned long ulX,\r
724                unsigned long ulY, unsigned long ulWidth,\r
725                unsigned long ulHeight)\r
726 {\r
727     //\r
728     // Check the arguments.\r
729     //\r
730     ASSERT(ulX < 96);\r
731     ASSERT(ulY < 2);\r
732     ASSERT((ulX + ulWidth) <= 96);\r
733     ASSERT((ulY + ulHeight) <= 2);\r
734 \r
735     //\r
736     // The first 36 columns of the LCD buffer are not displayed, so increment\r
737     // the X coorddinate by 36 to account for the non-displayed frame buffer\r
738     // memory.\r
739     //\r
740     ulX += 36;\r
741 \r
742     //\r
743     // Loop while there are more rows to display.\r
744     //\r
745     while(ulHeight--)\r
746     {\r
747         //\r
748         // Write the starting address within this row.\r
749         //\r
750         OSRAMWriteFirst(0x80);\r
751         OSRAMWriteByte((ulY == 0) ? 0xb0 : 0xb1);\r
752         OSRAMWriteByte(0x80);\r
753         OSRAMWriteByte(ulX & 0x0f);\r
754         OSRAMWriteByte(0x80);\r
755         OSRAMWriteByte(0x10 | ((ulX >> 4) & 0x0f));\r
756         OSRAMWriteByte(0x40);\r
757 \r
758         //\r
759         // Write this row of image data.\r
760         //\r
761         OSRAMWriteArray(pucImage, ulWidth - 1);\r
762         OSRAMWriteFinal(pucImage[ulWidth - 1]);\r
763 \r
764         //\r
765         // Advance to the next row of the image.\r
766         //\r
767         pucImage += ulWidth;\r
768         ulY++;\r
769     }\r
770 }\r
771 \r
772 //*****************************************************************************\r
773 //\r
774 //! Initialize the OLED display.\r
775 //!\r
776 //! \param bFast is a boolean that is \e true if the I2C interface should be\r
777 //! run at 400 kbps and \e false if it should be run at 100 kbps.\r
778 //!\r
779 //! This function initializes the I2C interface to the OLED display and\r
780 //! configures the SSD0303 controller on the panel.\r
781 //!\r
782 //! \return None.\r
783 //\r
784 //*****************************************************************************\r
785 void\r
786 OSRAMInit(tBoolean bFast)\r
787 {\r
788     unsigned long ulIdx;\r
789 \r
790     //\r
791     // Enable the I2C and GPIO port B blocks as they are needed by this driver.\r
792     //\r
793     SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C);\r
794     SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);\r
795 \r
796     //\r
797     // Configure the I2C SCL and SDA pins for I2C operation.\r
798     //\r
799     GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);\r
800 \r
801     //\r
802     // Initialize the I2C master.\r
803     //\r
804     I2CMasterInit(I2C_MASTER_BASE, bFast);\r
805 \r
806     //\r
807     // Compute the inter-byte delay for the SSD0303 controller.  This delay is\r
808     // dependent upon the I2C bus clock rate; the slower the clock the longer\r
809     // the delay required.\r
810     //\r
811     // The derivation of this formula is based on a measured delay of\r
812     // OSRAMDelay(1700) for a 100 kHz I2C bus with the CPU running at 50 MHz\r
813     // (referred to as C).  To scale this to the delay for a different CPU\r
814     // speed (since this is just a CPU-based delay loop) is:\r
815     //\r
816     //           f(CPU)\r
817     //     C * ----------\r
818     //         50,000,000\r
819     //\r
820     // To then scale this to the actual I2C rate (since it won't always be\r
821     // precisely 100 kHz):\r
822     //\r
823     //           f(CPU)     100,000\r
824     //     C * ---------- * -------\r
825     //         50,000,000    f(I2C)\r
826     //\r
827     // This equation will give the inter-byte delay required for any\r
828     // configuration of the I2C master.  But, as arranged it is impossible to\r
829     // directly compute in 32-bit arithmetic (without loosing a lot of\r
830     // accuracy).  So, the equation is simplified.\r
831     //\r
832     // Since f(I2C) is generated by dividing down from f(CPU), replace it with\r
833     // the equivalent (where TPR is the value programmed into the Master Timer\r
834     // Period Register of the I2C master, with the 1 added back):\r
835     //\r
836     //                        100,000\r
837     //           f(CPU)       -------\r
838     //     C * ---------- *    f(CPU)\r
839     //         50,000,000   ------------\r
840     //                      2 * 10 * TPR\r
841     //\r
842     // Inverting the dividend in the last term:\r
843     //\r
844     //           f(CPU)     100,000 * 2 * 10 * TPR\r
845     //     C * ---------- * ----------------------\r
846     //         50,000,000          f(CPU)\r
847     //\r
848     // The f(CPU) now cancels out.\r
849     //\r
850     //         100,000 * 2 * 10 * TPR\r
851     //     C * ----------------------\r
852     //               50,000,000\r
853     //\r
854     // Since there are no clock frequencies left in the equation, this equation\r
855     // also works for 400 kHz bus operation as well, since the 100,000 in the\r
856     // numerator becomes 400,000 but C is 1/4, which cancel out each other.\r
857     // Reducing the constants gives:\r
858     //\r
859     //         TPR              TPR             TPR\r
860     //     C * ---   =   1700 * ---   =   340 * ---\r
861     //         25               25               5\r
862     //\r
863     // Note that the constant C is actually a bit larger than it needs to be in\r
864     // order to provide some safety margin.\r
865     //\r
866     // When the panel is being initialized, the value of C actually needs to be\r
867     // a bit longer (3200 instead of 1700).  So, set the larger value for now.\r
868     //\r
869     g_ulDelay = (640 * (HWREG(I2C_MASTER_BASE + I2C_MASTER_O_TPR) + 1)) / 5;\r
870 \r
871     //\r
872     // Initialize the SSD0303 controller.  Loop through the initialization\r
873     // sequence doing a single I2C transfer for each command.\r
874     //\r
875     for(ulIdx = 0; ulIdx < sizeof(g_pucOSRAMInit);\r
876         ulIdx += g_pucOSRAMInit[ulIdx] + 1)\r
877     {\r
878         //\r
879         // Send this command.\r
880         //\r
881         OSRAMWriteFirst(g_pucOSRAMInit[ulIdx + 1]);\r
882         OSRAMWriteArray(g_pucOSRAMInit + ulIdx + 2, g_pucOSRAMInit[ulIdx] - 2);\r
883         OSRAMWriteFinal(g_pucOSRAMInit[ulIdx + g_pucOSRAMInit[ulIdx]]);\r
884     }\r
885 \r
886     //\r
887     // Now, switch to the actual value of C.\r
888     //\r
889     g_ulDelay = (340 * (HWREG(I2C_MASTER_BASE + I2C_MASTER_O_TPR) + 1)) / 5;\r
890 \r
891     //\r
892     // Clear the frame buffer.\r
893     //\r
894     OSRAMClear();\r
895 }\r
896 \r
897 //*****************************************************************************\r
898 //\r
899 //! Turns on the OLED display.\r
900 //!\r
901 //! This function will turn on the OLED display, causing it to display the\r
902 //! contents of its internal frame buffer.\r
903 //!\r
904 //! \return None.\r
905 //\r
906 //*****************************************************************************\r
907 void\r
908 OSRAMDisplayOn(void)\r
909 {\r
910     //\r
911     // Turn on the DC-DC converter and the display.\r
912     //\r
913     OSRAMWriteFirst(0x80);\r
914     OSRAMWriteByte(0xad);\r
915     OSRAMWriteByte(0x80);\r
916     OSRAMWriteByte(0x8b);\r
917     OSRAMWriteByte(0x80);\r
918     OSRAMWriteFinal(0xaf);\r
919 }\r
920 \r
921 //*****************************************************************************\r
922 //\r
923 //! Turns off the OLED display.\r
924 //!\r
925 //! This function will turn off the OLED display.  This will stop the scanning\r
926 //! of the panel and turn off the on-chip DC-DC converter, preventing damage to\r
927 //! the panel due to burn-in (it has similar characters to a CRT in this\r
928 //! respect).\r
929 //!\r
930 //! \return None.\r
931 //\r
932 //*****************************************************************************\r
933 void\r
934 OSRAMDisplayOff(void)\r
935 {\r
936     //\r
937     // Turn off the DC-DC converter and the display.\r
938     //\r
939     OSRAMWriteFirst(0x80);\r
940     OSRAMWriteByte(0xad);\r
941     OSRAMWriteByte(0x80);\r
942     OSRAMWriteByte(0x8a);\r
943     OSRAMWriteByte(0x80);\r
944     OSRAMWriteFinal(0xae);\r
945 }\r
946 \r
947 //*****************************************************************************\r
948 //\r
949 // Close the Doxygen group.\r
950 //! @}\r
951 //\r
952 //*****************************************************************************\r