]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_LM3S811_GCC/hw_include/osram96x16.c
Start to re-arrange files to include FreeRTOS+ in main download.
[freertos] / Demo / CORTEX_LM3S811_GCC / hw_include / osram96x16.c
1 //*****************************************************************************\r
2 //\r
3 // osram96x16.c - Driver for the OSRAM 96x16 graphical OLED display.\r
4 //\r
5 // Copyright (c) 2006-2007 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 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 1049 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 "debug.h"\r
40 #include "gpio.h"\r
41 #include "i2c.h"\r
42 #include "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     0x04, 0x80, 0xae, 0x80, 0xe3,\r
172 \r
173     //\r
174     // Set lower column address\r
175     //\r
176     0x04, 0x80, 0x04, 0x80, 0xe3,\r
177 \r
178     //\r
179     // Set higher column address\r
180     //\r
181     0x04, 0x80, 0x12, 0x80, 0xe3,\r
182 \r
183     //\r
184     // Set contrast control register\r
185     //\r
186     0x06, 0x80, 0x81, 0x80, 0x2b, 0x80, 0xe3,\r
187 \r
188     //\r
189     // Set segment re-map\r
190     //\r
191     0x04, 0x80, 0xa1, 0x80, 0xe3,\r
192 \r
193     //\r
194     // Set display start line\r
195     //\r
196     0x04, 0x80, 0x40, 0x80, 0xe3,\r
197 \r
198     //\r
199     // Set display offset\r
200     //\r
201     0x06, 0x80, 0xd3, 0x80, 0x00, 0x80, 0xe3,\r
202 \r
203     //\r
204     // Set multiplex ratio\r
205     //\r
206     0x06, 0x80, 0xa8, 0x80, 0x0f, 0x80, 0xe3,\r
207 \r
208     //\r
209     // Set the display to normal mode\r
210     //\r
211     0x04, 0x80, 0xa4, 0x80, 0xe3,\r
212 \r
213     //\r
214     // Non-inverted display\r
215     //\r
216     0x04, 0x80, 0xa6, 0x80, 0xe3,\r
217 \r
218     //\r
219     // Set the page address\r
220     //\r
221     0x04, 0x80, 0xb0, 0x80, 0xe3,\r
222 \r
223     //\r
224     // Set COM output scan direction\r
225     //\r
226     0x04, 0x80, 0xc8, 0x80, 0xe3,\r
227 \r
228     //\r
229     // Set display clock divide ratio/oscillator frequency\r
230     //\r
231     0x06, 0x80, 0xd5, 0x80, 0x72, 0x80, 0xe3,\r
232 \r
233     //\r
234     // Enable mono mode\r
235     //\r
236     0x06, 0x80, 0xd8, 0x80, 0x00, 0x80, 0xe3,\r
237 \r
238     //\r
239     // Set pre-charge period\r
240     //\r
241     0x06, 0x80, 0xd9, 0x80, 0x22, 0x80, 0xe3,\r
242 \r
243     //\r
244     // Set COM pins hardware configuration\r
245     //\r
246     0x06, 0x80, 0xda, 0x80, 0x12, 0x80, 0xe3,\r
247 \r
248     //\r
249     // Set VCOM deslect level\r
250     //\r
251     0x06, 0x80, 0xdb, 0x80, 0x0f, 0x80, 0xe3,\r
252 \r
253     //\r
254     // Set DC-DC on\r
255     //\r
256     0x06, 0x80, 0xad, 0x80, 0x8b, 0x80, 0xe3,\r
257 \r
258     //\r
259     // Turn on the panel\r
260     //\r
261     0x04, 0x80, 0xaf, 0x80, 0xe3,\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 //! This function is contained in <tt>osram96x16.c</tt>, with\r
507 //! <tt>osram96x16.h</tt> containing the API definition for use by\r
508 //! applications.\r
509 //!\r
510 //! \return None.\r
511 //\r
512 //*****************************************************************************\r
513 void\r
514 OSRAMClear(void)\r
515 {\r
516     static const unsigned char pucRow1[] =\r
517     {\r
518         0xb0, 0x80, 0x04, 0x80, 0x12, 0x40\r
519     };\r
520     static const unsigned char pucRow2[] =\r
521     {\r
522         0xb1, 0x80, 0x04, 0x80, 0x12, 0x40\r
523     };\r
524     unsigned long ulIdx;\r
525 \r
526     //\r
527     // Move the display cursor to the first column of the first row.\r
528     //\r
529     OSRAMWriteFirst(0x80);\r
530     OSRAMWriteArray(pucRow1, sizeof(pucRow1));\r
531 \r
532     //\r
533     // Fill this row with zeros.\r
534     //\r
535     for(ulIdx = 0; ulIdx < 95; ulIdx++)\r
536     {\r
537         OSRAMWriteByte(0x00);\r
538     }\r
539     OSRAMWriteFinal(0x00);\r
540 \r
541     //\r
542     // Move the display cursor to the first column of the second row.\r
543     //\r
544     OSRAMWriteFirst(0x80);\r
545     OSRAMWriteArray(pucRow2, sizeof(pucRow2));\r
546 \r
547     //\r
548     // Fill this row with zeros.\r
549     //\r
550     for(ulIdx = 0; ulIdx < 95; ulIdx++)\r
551     {\r
552         OSRAMWriteByte(0x00);\r
553     }\r
554     OSRAMWriteFinal(0x00);\r
555 }\r
556 \r
557 //*****************************************************************************\r
558 //\r
559 //! Displays a string on the OLED display.\r
560 //!\r
561 //! \param pcStr is a pointer to the string to display.\r
562 //! \param ulX is the horizontal position to display the string, specified in\r
563 //! columns from the left edge of the display.\r
564 //! \param ulY is the vertical position to display the string, specified in\r
565 //! eight scan line blocks from the top of the display (i.e. only 0 and 1 are\r
566 //! valid).\r
567 //!\r
568 //! This function will draw a string on the display.  Only the ASCII characters\r
569 //! between 32 (space) and 126 (tilde) are supported; other characters will\r
570 //! result in random data being draw on the display (based on whatever appears\r
571 //! before/after the font in memory).  The font is mono-spaced, so characters\r
572 //! such as "i" and "l" have more white space around them than characters such\r
573 //! as "m" or "w".\r
574 //!\r
575 //! If the drawing of the string reaches the right edge of the display, no more\r
576 //! characters will be drawn.  Therefore, special care is not required to avoid\r
577 //! supplying a string that is "too long" to display.\r
578 //!\r
579 //! This function is contained in <tt>osram96x16.c</tt>, with\r
580 //! <tt>osram96x16.h</tt> containing the API definition for use by\r
581 //! applications.\r
582 //!\r
583 //! \return None.\r
584 //\r
585 //*****************************************************************************\r
586 void\r
587 OSRAMStringDraw(const char *pcStr, unsigned long ulX, unsigned long ulY)\r
588 {\r
589     //\r
590     // Check the arguments.\r
591     //\r
592     ASSERT(ulX < 96);\r
593     ASSERT(ulY < 2);\r
594 \r
595     //\r
596     // Move the display cursor to the requested position on the display.\r
597     //\r
598     OSRAMWriteFirst(0x80);\r
599     OSRAMWriteByte((ulY == 0) ? 0xb0 : 0xb1);\r
600     OSRAMWriteByte(0x80);\r
601     OSRAMWriteByte((ulX + 36) & 0x0f);\r
602     OSRAMWriteByte(0x80);\r
603     OSRAMWriteByte(0x10 | (((ulX + 36) >> 4) & 0x0f));\r
604     OSRAMWriteByte(0x40);\r
605 \r
606     //\r
607     // Loop while there are more characters in the string.\r
608     //\r
609     while(*pcStr != 0)\r
610     {\r
611         //\r
612         // See if there is enough space on the display for this entire\r
613         // character.\r
614         //\r
615         if(ulX <= 90)\r
616         {\r
617             //\r
618             // Write the contents of this character to the display.\r
619             //\r
620             OSRAMWriteArray(g_pucFont[*pcStr - ' '], 5);\r
621 \r
622             //\r
623             // See if this is the last character to display (either because the\r
624             // right edge has been reached or because there are no more\r
625             // characters).\r
626             //\r
627             if((ulX == 90) || (pcStr[1] == 0))\r
628             {\r
629                 //\r
630                 // Write the final column of the display.\r
631                 //\r
632                 OSRAMWriteFinal(0x00);\r
633 \r
634                 //\r
635                 // The string has been displayed.\r
636                 //\r
637                 return;\r
638             }\r
639 \r
640             //\r
641             // Write the inter-character padding column.\r
642             //\r
643             OSRAMWriteByte(0x00);\r
644         }\r
645         else\r
646         {\r
647             //\r
648             // Write the portion of the character that will fit onto the\r
649             // display.\r
650             //\r
651             OSRAMWriteArray(g_pucFont[*pcStr - ' '], 95 - ulX);\r
652             OSRAMWriteFinal(g_pucFont[*pcStr - ' '][95 - ulX]);\r
653 \r
654             //\r
655             // The string has been displayed.\r
656             //\r
657             return;\r
658         }\r
659 \r
660         //\r
661         // Advance to the next character.\r
662         //\r
663         pcStr++;\r
664 \r
665         //\r
666         // Increment the X coordinate by the six columns that were just\r
667         // written.\r
668         //\r
669         ulX += 6;\r
670     }\r
671 }\r
672 \r
673 //*****************************************************************************\r
674 //\r
675 //! Displays an image on the OLED display.\r
676 //!\r
677 //! \param pucImage is a pointer to the image data.\r
678 //! \param ulX is the horizontal position to display this image, specified in\r
679 //! columns from the left edge of the display.\r
680 //! \param ulY is the vertical position to display this image, specified in\r
681 //! eight scan line blocks from the top of the display (i.e. only 0 and 1 are\r
682 //! valid).\r
683 //! \param ulWidth is the width of the image, specified in columns.\r
684 //! \param ulHeight is the height of the image, specified in eight row blocks\r
685 //! (i.e. only 1 and 2 are valid).\r
686 //!\r
687 //! This function will display a bitmap graphic on the display.  The image to\r
688 //! be displayed must be a multiple of eight scan lines high (i.e. one row) and\r
689 //! will be drawn at a vertical position that is a multiple of eight scan lines\r
690 //! (i.e. scan line zero or scan line eight, corresponding to row zero or row\r
691 //! one).\r
692 //!\r
693 //! The image data is organized with the first row of image data appearing left\r
694 //! to right, followed immediately by the second row of image data.  Each byte\r
695 //! contains the data for the eight scan lines of the column, with the top scan\r
696 //! line being in the least significant bit of the byte and the bottom scan\r
697 //! line being in the most significant bit of the byte.\r
698 //!\r
699 //! For example, an image four columns wide and sixteen scan lines tall would\r
700 //! be arranged as follows (showing how the eight bytes of the image would\r
701 //! appear on the display):\r
702 //!\r
703 //! \verbatim\r
704 //!     +-------+  +-------+  +-------+  +-------+\r
705 //!     |   | 0 |  |   | 0 |  |   | 0 |  |   | 0 |\r
706 //!     | B | 1 |  | B | 1 |  | B | 1 |  | B | 1 |\r
707 //!     | y | 2 |  | y | 2 |  | y | 2 |  | y | 2 |\r
708 //!     | t | 3 |  | t | 3 |  | t | 3 |  | t | 3 |\r
709 //!     | e | 4 |  | e | 4 |  | e | 4 |  | e | 4 |\r
710 //!     |   | 5 |  |   | 5 |  |   | 5 |  |   | 5 |\r
711 //!     | 0 | 6 |  | 1 | 6 |  | 2 | 6 |  | 3 | 6 |\r
712 //!     |   | 7 |  |   | 7 |  |   | 7 |  |   | 7 |\r
713 //!     +-------+  +-------+  +-------+  +-------+\r
714 //!\r
715 //!     +-------+  +-------+  +-------+  +-------+\r
716 //!     |   | 0 |  |   | 0 |  |   | 0 |  |   | 0 |\r
717 //!     | B | 1 |  | B | 1 |  | B | 1 |  | B | 1 |\r
718 //!     | y | 2 |  | y | 2 |  | y | 2 |  | y | 2 |\r
719 //!     | t | 3 |  | t | 3 |  | t | 3 |  | t | 3 |\r
720 //!     | e | 4 |  | e | 4 |  | e | 4 |  | e | 4 |\r
721 //!     |   | 5 |  |   | 5 |  |   | 5 |  |   | 5 |\r
722 //!     | 4 | 6 |  | 5 | 6 |  | 6 | 6 |  | 7 | 6 |\r
723 //!     |   | 7 |  |   | 7 |  |   | 7 |  |   | 7 |\r
724 //!     +-------+  +-------+  +-------+  +-------+\r
725 //! \endverbatim\r
726 //!\r
727 //! This function is contained in <tt>osram96x16.c</tt>, with\r
728 //! <tt>osram96x16.h</tt> containing the API definition for use by\r
729 //! applications.\r
730 //!\r
731 //! \return None.\r
732 //\r
733 //*****************************************************************************\r
734 void\r
735 OSRAMImageDraw(const unsigned char *pucImage, unsigned long ulX,\r
736                unsigned long ulY, unsigned long ulWidth,\r
737                unsigned long ulHeight)\r
738 {\r
739     //\r
740     // Check the arguments.\r
741     //\r
742     ASSERT(ulX < 96);\r
743     ASSERT(ulY < 2);\r
744     ASSERT((ulX + ulWidth) <= 96);\r
745     ASSERT((ulY + ulHeight) <= 2);\r
746 \r
747     //\r
748     // The first 36 columns of the LCD buffer are not displayed, so increment\r
749     // the X coorddinate by 36 to account for the non-displayed frame buffer\r
750     // memory.\r
751     //\r
752     ulX += 36;\r
753 \r
754     //\r
755     // Loop while there are more rows to display.\r
756     //\r
757     while(ulHeight--)\r
758     {\r
759         //\r
760         // Write the starting address within this row.\r
761         //\r
762         OSRAMWriteFirst(0x80);\r
763         OSRAMWriteByte((ulY == 0) ? 0xb0 : 0xb1);\r
764         OSRAMWriteByte(0x80);\r
765         OSRAMWriteByte(ulX & 0x0f);\r
766         OSRAMWriteByte(0x80);\r
767         OSRAMWriteByte(0x10 | ((ulX >> 4) & 0x0f));\r
768         OSRAMWriteByte(0x40);\r
769 \r
770         //\r
771         // Write this row of image data.\r
772         //\r
773         OSRAMWriteArray(pucImage, ulWidth - 1);\r
774         OSRAMWriteFinal(pucImage[ulWidth - 1]);\r
775 \r
776         //\r
777         // Advance to the next row of the image.\r
778         //\r
779         pucImage += ulWidth;\r
780         ulY++;\r
781     }\r
782 }\r
783 \r
784 //*****************************************************************************\r
785 //\r
786 //! Initialize the OLED display.\r
787 //!\r
788 //! \param bFast is a boolean that is \e true if the I2C interface should be\r
789 //! run at 400 kbps and \e false if it should be run at 100 kbps.\r
790 //!\r
791 //! This function initializes the I2C interface to the OLED display and\r
792 //! configures the SSD0303 controller on the panel.\r
793 //!\r
794 //! This function is contained in <tt>osram96x16.c</tt>, with\r
795 //! <tt>osram96x16.h</tt> containing the API definition for use by\r
796 //! applications.\r
797 //!\r
798 //! \return None.\r
799 //\r
800 //*****************************************************************************\r
801 void\r
802 OSRAMInit(tBoolean bFast)\r
803 {\r
804     unsigned long ulIdx;\r
805 \r
806     //\r
807     // Enable the I2C and GPIO port B blocks as they are needed by this driver.\r
808     //\r
809     SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C);\r
810     SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);\r
811 \r
812     //\r
813     // Configure the I2C SCL and SDA pins for I2C operation.\r
814     //\r
815     GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);\r
816 \r
817     //\r
818     // Initialize the I2C master.\r
819     //\r
820     I2CMasterInit(I2C_MASTER_BASE, bFast);\r
821 \r
822     //\r
823     // Compute the inter-byte delay for the SSD0303 controller.  This delay is\r
824     // dependent upon the I2C bus clock rate; the slower the clock the longer\r
825     // the delay required.\r
826     //\r
827     // The derivation of this formula is based on a measured delay of\r
828     // OSRAMDelay(1700) for a 100 kHz I2C bus with the CPU running at 50 MHz\r
829     // (referred to as C).  To scale this to the delay for a different CPU\r
830     // speed (since this is just a CPU-based delay loop) is:\r
831     //\r
832     //           f(CPU)\r
833     //     C * ----------\r
834     //         50,000,000\r
835     //\r
836     // To then scale this to the actual I2C rate (since it won't always be\r
837     // precisely 100 kHz):\r
838     //\r
839     //           f(CPU)     100,000\r
840     //     C * ---------- * -------\r
841     //         50,000,000    f(I2C)\r
842     //\r
843     // This equation will give the inter-byte delay required for any\r
844     // configuration of the I2C master.  But, as arranged it is impossible to\r
845     // directly compute in 32-bit arithmetic (without loosing a lot of\r
846     // accuracy).  So, the equation is simplified.\r
847     //\r
848     // Since f(I2C) is generated by dividing down from f(CPU), replace it with\r
849     // the equivalent (where TPR is the value programmed into the Master Timer\r
850     // Period Register of the I2C master, with the 1 added back):\r
851     //\r
852     //                        100,000\r
853     //           f(CPU)       -------\r
854     //     C * ---------- *    f(CPU)\r
855     //         50,000,000   ------------\r
856     //                      2 * 10 * TPR\r
857     //\r
858     // Inverting the dividend in the last term:\r
859     //\r
860     //           f(CPU)     100,000 * 2 * 10 * TPR\r
861     //     C * ---------- * ----------------------\r
862     //         50,000,000          f(CPU)\r
863     //\r
864     // The f(CPU) now cancels out.\r
865     //\r
866     //         100,000 * 2 * 10 * TPR\r
867     //     C * ----------------------\r
868     //               50,000,000\r
869     //\r
870     // Since there are no clock frequencies left in the equation, this equation\r
871     // also works for 400 kHz bus operation as well, since the 100,000 in the\r
872     // numerator becomes 400,000 but C is 1/4, which cancel out each other.\r
873     // Reducing the constants gives:\r
874     //\r
875     //         TPR              TPR             TPR\r
876     //     C * ---   =   1700 * ---   =   340 * ---   = 68 * TPR\r
877     //         25               25               5\r
878     //\r
879     // Note that the constant C is actually a bit larger than it needs to be in\r
880     // order to provide some safety margin.\r
881     //\r
882     g_ulDelay = 68 * (HWREG(I2C_MASTER_BASE + I2C_MASTER_O_TPR) + 1);\r
883 \r
884     //\r
885     // Initialize the SSD0303 controller.  Loop through the initialization\r
886     // sequence doing a single I2C transfer for each command.\r
887     //\r
888     for(ulIdx = 0; ulIdx < sizeof(g_pucOSRAMInit);\r
889         ulIdx += g_pucOSRAMInit[ulIdx] + 1)\r
890     {\r
891         //\r
892         // Send this command.\r
893         //\r
894         OSRAMWriteFirst(g_pucOSRAMInit[ulIdx + 1]);\r
895         OSRAMWriteArray(g_pucOSRAMInit + ulIdx + 2, g_pucOSRAMInit[ulIdx] - 2);\r
896         OSRAMWriteFinal(g_pucOSRAMInit[ulIdx + g_pucOSRAMInit[ulIdx]]);\r
897     }\r
898 \r
899     //\r
900     // Clear the frame buffer.\r
901     //\r
902     OSRAMClear();\r
903 }\r
904 \r
905 //*****************************************************************************\r
906 //\r
907 //! Turns on the OLED display.\r
908 //!\r
909 //! This function will turn on the OLED display, causing it to display the\r
910 //! contents of its internal frame buffer.\r
911 //!\r
912 //! This function is contained in <tt>osram96x16.c</tt>, with\r
913 //! <tt>osram96x16.h</tt> containing the API definition for use by\r
914 //! applications.\r
915 //!\r
916 //! \return None.\r
917 //\r
918 //*****************************************************************************\r
919 void\r
920 OSRAMDisplayOn(void)\r
921 {\r
922     unsigned long ulIdx;\r
923 \r
924     //\r
925     // Re-initialize the SSD0303 controller.  Loop through the initialization\r
926     // sequence doing a single I2C transfer for each command.\r
927     //\r
928     for(ulIdx = 0; ulIdx < sizeof(g_pucOSRAMInit);\r
929         ulIdx += g_pucOSRAMInit[ulIdx] + 1)\r
930     {\r
931         //\r
932         // Send this command.\r
933         //\r
934         OSRAMWriteFirst(g_pucOSRAMInit[ulIdx + 1]);\r
935         OSRAMWriteArray(g_pucOSRAMInit + ulIdx + 2, g_pucOSRAMInit[ulIdx] - 2);\r
936         OSRAMWriteFinal(g_pucOSRAMInit[ulIdx + g_pucOSRAMInit[ulIdx]]);\r
937     }\r
938 }\r
939 \r
940 //*****************************************************************************\r
941 //\r
942 //! Turns off the OLED display.\r
943 //!\r
944 //! This function will turn off the OLED display.  This will stop the scanning\r
945 //! of the panel and turn off the on-chip DC-DC converter, preventing damage to\r
946 //! the panel due to burn-in (it has similar characters to a CRT in this\r
947 //! respect).\r
948 //!\r
949 //! This function is contained in <tt>osram96x16.c</tt>, with\r
950 //! <tt>osram96x16.h</tt> containing the API definition for use by\r
951 //! applications.\r
952 //!\r
953 //! \return None.\r
954 //\r
955 //*****************************************************************************\r
956 void\r
957 OSRAMDisplayOff(void)\r
958 {\r
959     //\r
960     // Turn off the DC-DC converter and the display.\r
961     //\r
962     OSRAMWriteFirst(0x80);\r
963     OSRAMWriteByte(0xae);\r
964     OSRAMWriteByte(0x80);\r
965     OSRAMWriteByte(0xad);\r
966     OSRAMWriteByte(0x80);\r
967     OSRAMWriteFinal(0x8a);\r
968 }\r
969 \r
970 //*****************************************************************************\r
971 //\r
972 // Close the Doxygen group.\r
973 //! @}\r
974 //\r
975 //*****************************************************************************\r