]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_LM3S811_KEIL/LuminaryCode/osram96x16.c
0baa3ed78dee7c09a9cad2c8cf004b4cf3f39cdf
[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.\r
162 //\r
163 //*****************************************************************************\r
164 static const unsigned char g_pucOSRAMInit[] =\r
165 {\r
166     //\r
167     // Turn off the panel\r
168     //\r
169     0x80, 0xae,\r
170 \r
171     //\r
172     // Set lower column address\r
173     //\r
174     0x80, 0x04,\r
175 \r
176     //\r
177     // Set higher column address\r
178     //\r
179     0x80, 0x12,\r
180 \r
181     //\r
182     // Set contrast control register\r
183     //\r
184     0x80, 0x81, 0x80, 0x2b,\r
185 \r
186     //\r
187     // Set segment re-map\r
188     //\r
189     0x80, 0xa1,\r
190 \r
191     //\r
192     // Set display start line\r
193     //\r
194     0x80, 0x40,\r
195 \r
196     //\r
197     // Set display offset\r
198     //\r
199     0x80, 0xd3, 0x80, 0x00,\r
200 \r
201     //\r
202     // Set multiplex ratio\r
203     //\r
204     0x80, 0xa8, 0x80, 0x0f,\r
205 \r
206     //\r
207     // Set the display to normal mode\r
208     //\r
209     0x80, 0xa4,\r
210 \r
211     //\r
212     // Non-inverted display\r
213     //\r
214     0x80, 0xa6,\r
215 \r
216     //\r
217     // Set the page address\r
218     //\r
219     0x80, 0xb0,\r
220 \r
221     //\r
222     // Set COM output scan direction\r
223     //\r
224     0x80, 0xc8,\r
225 \r
226     //\r
227     // Set display clock divide ratio/oscillator frequency\r
228     //\r
229     0x80, 0xd5, 0x80, 0x72,\r
230 \r
231     //\r
232     // Enable mono mode\r
233     //\r
234     0x80, 0xd8, 0x80, 0x00,\r
235 \r
236     //\r
237     // Set pre-charge period\r
238     //\r
239     0x80, 0xd9, 0x80, 0x22,\r
240 \r
241     //\r
242     // Set COM pins hardware configuration\r
243     //\r
244     0x80, 0xda, 0x80, 0x12,\r
245 \r
246     //\r
247     // Set VCOM deslect level\r
248     //\r
249     0x80, 0xdb, 0x80, 0x0f,\r
250 \r
251     //\r
252     // Set DC-DC on\r
253     //\r
254     0x80, 0xad, 0x80, 0x8b,\r
255 \r
256     //\r
257     // Turn on the panel\r
258     //\r
259     0x80, 0xaf,\r
260 };\r
261 \r
262 //*****************************************************************************\r
263 //\r
264 // The inter-byte delay required by the SSD0303 OLED controller.\r
265 //\r
266 //*****************************************************************************\r
267 static unsigned long g_ulDelay;\r
268 \r
269 //*****************************************************************************\r
270 //\r
271 //! \internal\r
272 //!\r
273 //! Provide a small delay.\r
274 //!\r
275 //! \param ulCount is the number of delay loop iterations to perform.\r
276 //!\r
277 //! Since the SSD0303 controller needs a delay between bytes written to it over\r
278 //! the I2C bus, this function provides a means of generating that delay.  It\r
279 //! is written in assembly to keep the delay consistent across tool chains,\r
280 //! avoiding the need to tune the delay based on the tool chain in use.\r
281 //!\r
282 //! \return None.\r
283 //\r
284 //*****************************************************************************\r
285 #if defined(ewarm)\r
286 static void\r
287 OSRAMDelay(unsigned long ulCount)\r
288 {\r
289     __asm("    subs    r0, #1\n"\r
290           "    bne     OSRAMDelay\n"\r
291           "    bx      lr");\r
292 }\r
293 #endif\r
294 #if defined(gcc)\r
295 static void __attribute__((naked))\r
296 OSRAMDelay(unsigned long ulCount)\r
297 {\r
298     __asm("    subs    r0, #1\n"\r
299           "    bne     OSRAMDelay\n"\r
300           "    bx      lr");\r
301 }\r
302 #endif\r
303 #if defined(rvmdk) || defined(__ARMCC_VERSION)\r
304 __asm void\r
305 OSRAMDelay(unsigned long ulCount)\r
306 {\r
307     subs    r0, #1;\r
308     bne     OSRAMDelay;\r
309     bx      lr;\r
310 }\r
311 #endif\r
312 \r
313 //*****************************************************************************\r
314 //\r
315 //! \internal\r
316 //!\r
317 //! Start a transfer to the SSD0303 controller.\r
318 //!\r
319 //! \param ucChar is the first byte to be written to the controller.\r
320 //!\r
321 //! This function will start a transfer to the SSD0303 controller via the I2C\r
322 //! bus.\r
323 //!\r
324 //! The data is written in a polled fashion; this function will not return\r
325 //! until the byte has been written to the controller.\r
326 //!\r
327 //! \return None.\r
328 //\r
329 //*****************************************************************************\r
330 static void\r
331 OSRAMWriteFirst(unsigned char ucChar)\r
332 {\r
333     //\r
334     // Set the slave address.\r
335     //\r
336     I2CMasterSlaveAddrSet(I2C_MASTER_BASE, SSD0303_ADDR, false);\r
337 \r
338     //\r
339     // Write the first byte to the controller.\r
340     //\r
341     I2CMasterDataPut(I2C_MASTER_BASE, ucChar);\r
342 \r
343     //\r
344     // Start the transfer.\r
345     //\r
346     I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);\r
347 }\r
348 \r
349 //*****************************************************************************\r
350 //\r
351 //! \internal\r
352 //!\r
353 //! Write a byte to the SSD0303 controller.\r
354 //!\r
355 //! \param ucChar is the byte to be transmitted to the controller.\r
356 //!\r
357 //! This function continues a transfer to the SSD0303 controller by writing\r
358 //! another byte over the I2C bus.  This must only be called after calling\r
359 //! OSRAMWriteFirst(), but before calling OSRAMWriteFinal().\r
360 //!\r
361 //! The data is written in a polled faashion; this function will not return\r
362 //! until the byte has been written to the controller.\r
363 //!\r
364 //! \return None.\r
365 //\r
366 //*****************************************************************************\r
367 static void\r
368 OSRAMWriteByte(unsigned char ucChar)\r
369 {\r
370     //\r
371     // Wait until the current byte has been transferred.\r
372     //\r
373     while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)\r
374     {\r
375     }\r
376 \r
377     //\r
378     // Provide the required inter-byte delay.\r
379     //\r
380     OSRAMDelay(g_ulDelay);\r
381 \r
382     //\r
383     // Write the next byte to the controller.\r
384     //\r
385     I2CMasterDataPut(I2C_MASTER_BASE, ucChar);\r
386 \r
387     //\r
388     // Continue the transfer.\r
389     //\r
390     I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);\r
391 }\r
392 \r
393 //*****************************************************************************\r
394 //\r
395 //! \internal\r
396 //!\r
397 //! Write a sequence of bytes to the SSD0303 controller.\r
398 //!\r
399 //! This function continues a transfer to the SSD0303 controller by writing a\r
400 //! sequence of bytes over the I2C bus.  This must only be called after calling\r
401 //! OSRAMWriteFirst(), but before calling OSRAMWriteFinal().\r
402 //!\r
403 //! The data is written in a polled fashion; this function will not return\r
404 //! until the entire byte sequence has been written to the controller.\r
405 //!\r
406 //! \return None.\r
407 //\r
408 //*****************************************************************************\r
409 static void\r
410 OSRAMWriteArray(const unsigned char *pucBuffer, unsigned long ulCount)\r
411 {\r
412     //\r
413     // Loop while there are more bytes left to be transferred.\r
414     //\r
415     while(ulCount != 0)\r
416     {\r
417         //\r
418         // Wait until the current byte has been transferred.\r
419         //\r
420         while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)\r
421         {\r
422         }\r
423 \r
424         //\r
425         // Provide the required inter-byte delay.\r
426         //\r
427         OSRAMDelay(g_ulDelay);\r
428 \r
429         //\r
430         // Write the next byte to the controller.\r
431         //\r
432         I2CMasterDataPut(I2C_MASTER_BASE, *pucBuffer++);\r
433         ulCount--;\r
434 \r
435         //\r
436         // Continue the transfer.\r
437         //\r
438         I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);\r
439     }\r
440 }\r
441 \r
442 //*****************************************************************************\r
443 //\r
444 //! \internal\r
445 //!\r
446 //! Finish a transfer to the SSD0303 controller.\r
447 //!\r
448 //! \param ucChar is the final byte to be written to the controller.\r
449 //!\r
450 //! This function will finish a transfer to the SSD0303 controller via the I2C\r
451 //! bus.  This must only be called after calling OSRAMWriteFirst().\r
452 //!\r
453 //! The data is written in a polled fashion; this function will not return\r
454 //! until the byte has been written to the controller.\r
455 //!\r
456 //! \return None.\r
457 //\r
458 //*****************************************************************************\r
459 static void\r
460 OSRAMWriteFinal(unsigned char ucChar)\r
461 {\r
462     //\r
463     // Wait until the current byte has been transferred.\r
464     //\r
465     while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)\r
466     {\r
467     }\r
468 \r
469     //\r
470     // Provide the required inter-byte delay.\r
471     //\r
472     OSRAMDelay(g_ulDelay);\r
473 \r
474     //\r
475     // Write the final byte to the controller.\r
476     //\r
477     I2CMasterDataPut(I2C_MASTER_BASE, ucChar);\r
478 \r
479     //\r
480     // Finish the transfer.\r
481     //\r
482     I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);\r
483 \r
484     //\r
485     // Wait until the final byte has been transferred.\r
486     //\r
487     while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)\r
488     {\r
489     }\r
490 \r
491     //\r
492     // Provide the required inter-byte delay.\r
493     //\r
494     OSRAMDelay(g_ulDelay);\r
495 }\r
496 \r
497 //*****************************************************************************\r
498 //\r
499 //! Clears the OLED display.\r
500 //!\r
501 //! This function will clear the display.  All pixels in the display will be\r
502 //! turned off.\r
503 //!\r
504 //! This function is contained in <tt>osram96x16.c</tt>, with\r
505 //! <tt>osram96x16.h</tt> containing the API definition for use by\r
506 //! applications.\r
507 //!\r
508 //! \return None.\r
509 //\r
510 //*****************************************************************************\r
511 void\r
512 OSRAMClear(void)\r
513 {\r
514     static const unsigned char pucRow1[] =\r
515     {\r
516         0xb0, 0x80, 0x04, 0x80, 0x12, 0x40\r
517     };\r
518     static const unsigned char pucRow2[] =\r
519     {\r
520         0xb1, 0x80, 0x04, 0x80, 0x12, 0x40\r
521     };\r
522     unsigned long ulIdx;\r
523 \r
524     //\r
525     // Move the display cursor to the first column of the first row.\r
526     //\r
527     OSRAMWriteFirst(0x80);\r
528     OSRAMWriteArray(pucRow1, sizeof(pucRow1));\r
529 \r
530     //\r
531     // Fill this row with zeros.\r
532     //\r
533     for(ulIdx = 0; ulIdx < 95; ulIdx++)\r
534     {\r
535         OSRAMWriteByte(0x00);\r
536     }\r
537     OSRAMWriteFinal(0x00);\r
538 \r
539     //\r
540     // Move the display cursor to the first column of the second row.\r
541     //\r
542     OSRAMWriteFirst(0x80);\r
543     OSRAMWriteArray(pucRow2, sizeof(pucRow2));\r
544 \r
545     //\r
546     // Fill this row with zeros.\r
547     //\r
548     for(ulIdx = 0; ulIdx < 95; ulIdx++)\r
549     {\r
550         OSRAMWriteByte(0x00);\r
551     }\r
552     OSRAMWriteFinal(0x00);\r
553 }\r
554 \r
555 //*****************************************************************************\r
556 //\r
557 //! Displays a string on the OLED display.\r
558 //!\r
559 //! \param pcStr is a pointer to the string to display.\r
560 //! \param ulX is the horizontal position to display the string, specified in\r
561 //! columns from the left edge of the display.\r
562 //! \param ulY is the vertical position to display the string, specified in\r
563 //! eight scan line blocks from the top of the display (i.e. only 0 and 1 are\r
564 //! valid).\r
565 //!\r
566 //! This function will draw a string on the display.  Only the ASCII characters\r
567 //! between 32 (space) and 126 (tilde) are supported; other characters will\r
568 //! result in random data being draw on the display (based on whatever appears\r
569 //! before/after the font in memory).  The font is mono-spaced, so characters\r
570 //! such as "i" and "l" have more white space around them than characters such\r
571 //! as "m" or "w".\r
572 //!\r
573 //! If the drawing of the string reaches the right edge of the display, no more\r
574 //! characters will be drawn.  Therefore, special care is not required to avoid\r
575 //! supplying a string that is "too long" to display.\r
576 //!\r
577 //! This function is contained in <tt>osram96x16.c</tt>, with\r
578 //! <tt>osram96x16.h</tt> containing the API definition for use by\r
579 //! applications.\r
580 //!\r
581 //! \return None.\r
582 //\r
583 //*****************************************************************************\r
584 void\r
585 OSRAMStringDraw(const char *pcStr, unsigned long ulX, unsigned long ulY)\r
586 {\r
587     //\r
588     // Check the arguments.\r
589     //\r
590     ASSERT(ulX < 96);\r
591     ASSERT(ulY < 2);\r
592 \r
593     //\r
594     // Move the display cursor to the requested position on the display.\r
595     //\r
596     OSRAMWriteFirst(0x80);\r
597     OSRAMWriteByte((ulY == 0) ? 0xb0 : 0xb1);\r
598     OSRAMWriteByte(0x80);\r
599     OSRAMWriteByte((ulX + 36) & 0x0f);\r
600     OSRAMWriteByte(0x80);\r
601     OSRAMWriteByte(0x10 | (((ulX + 36) >> 4) & 0x0f));\r
602     OSRAMWriteByte(0x40);\r
603 \r
604     //\r
605     // Loop while there are more characters in the string.\r
606     //\r
607     while(*pcStr != 0)\r
608     {\r
609         //\r
610         // See if there is enough space on the display for this entire\r
611         // character.\r
612         //\r
613         if(ulX <= 90)\r
614         {\r
615             //\r
616             // Write the contents of this character to the display.\r
617             //\r
618             OSRAMWriteArray(g_pucFont[*pcStr - ' '], 5);\r
619 \r
620             //\r
621             // See if this is the last character to display (either because the\r
622             // right edge has been reached or because there are no more\r
623             // characters).\r
624             //\r
625             if((ulX == 90) || (pcStr[1] == 0))\r
626             {\r
627                 //\r
628                 // Write the final column of the display.\r
629                 //\r
630                 OSRAMWriteFinal(0x00);\r
631 \r
632                 //\r
633                 // The string has been displayed.\r
634                 //\r
635                 return;\r
636             }\r
637 \r
638             //\r
639             // Write the inter-character padding column.\r
640             //\r
641             OSRAMWriteByte(0x00);\r
642         }\r
643         else\r
644         {\r
645             //\r
646             // Write the portion of the character that will fit onto the\r
647             // display.\r
648             //\r
649             OSRAMWriteArray(g_pucFont[*pcStr - ' '], 95 - ulX);\r
650             OSRAMWriteFinal(g_pucFont[*pcStr - ' '][95 - ulX]);\r
651 \r
652             //\r
653             // The string has been displayed.\r
654             //\r
655             return;\r
656         }\r
657 \r
658         //\r
659         // Advance to the next character.\r
660         //\r
661         pcStr++;\r
662 \r
663         //\r
664         // Increment the X coordinate by the six columns that were just\r
665         // written.\r
666         //\r
667         ulX += 6;\r
668     }\r
669 }\r
670 \r
671 //*****************************************************************************\r
672 //\r
673 //! Displays an image on the OLED display.\r
674 //!\r
675 //! \param pucImage is a pointer to the image data.\r
676 //! \param ulX is the horizontal position to display this image, specified in\r
677 //! columns from the left edge of the display.\r
678 //! \param ulY is the vertical position to display this image, specified in\r
679 //! eight scan line blocks from the top of the display (i.e. only 0 and 1 are\r
680 //! valid).\r
681 //! \param ulWidth is the width of the image, specified in columns.\r
682 //! \param ulHeight is the height of the image, specified in eight row blocks\r
683 //! (i.e. only 1 and 2 are valid).\r
684 //!\r
685 //! This function will display a bitmap graphic on the display.  The image to\r
686 //! be displayed must be a multiple of eight scan lines high (i.e. one row) and\r
687 //! will be drawn at a vertical position that is a multiple of eight scan lines\r
688 //! (i.e. scan line zero or scan line eight, corresponding to row zero or row\r
689 //! one).\r
690 //!\r
691 //! The image data is organized with the first row of image data appearing left\r
692 //! to right, followed immediately by the second row of image data.  Each byte\r
693 //! contains the data for the eight scan lines of the column, with the top scan\r
694 //! line being in the least significant bit of the byte and the bottom scan\r
695 //! line being in the most significat bit of the byte.\r
696 //!\r
697 //! For example, an image four columns wide and sixteen scan lines tall would\r
698 //! be arranged as follows (showing how the eight bytes of the image would\r
699 //! appear on the display):\r
700 //!\r
701 //! \verbatim\r
702 //!     +-------+  +-------+  +-------+  +-------+\r
703 //!     |   | 0 |  |   | 0 |  |   | 0 |  |   | 0 |\r
704 //!     | B | 1 |  | B | 1 |  | B | 1 |  | B | 1 |\r
705 //!     | y | 2 |  | y | 2 |  | y | 2 |  | y | 2 |\r
706 //!     | t | 3 |  | t | 3 |  | t | 3 |  | t | 3 |\r
707 //!     | e | 4 |  | e | 4 |  | e | 4 |  | e | 4 |\r
708 //!     |   | 5 |  |   | 5 |  |   | 5 |  |   | 5 |\r
709 //!     | 0 | 6 |  | 1 | 6 |  | 2 | 6 |  | 3 | 6 |\r
710 //!     |   | 7 |  |   | 7 |  |   | 7 |  |   | 7 |\r
711 //!     +-------+  +-------+  +-------+  +-------+\r
712 //!\r
713 //!     +-------+  +-------+  +-------+  +-------+\r
714 //!     |   | 0 |  |   | 0 |  |   | 0 |  |   | 0 |\r
715 //!     | B | 1 |  | B | 1 |  | B | 1 |  | B | 1 |\r
716 //!     | y | 2 |  | y | 2 |  | y | 2 |  | y | 2 |\r
717 //!     | t | 3 |  | t | 3 |  | t | 3 |  | t | 3 |\r
718 //!     | e | 4 |  | e | 4 |  | e | 4 |  | e | 4 |\r
719 //!     |   | 5 |  |   | 5 |  |   | 5 |  |   | 5 |\r
720 //!     | 4 | 6 |  | 5 | 6 |  | 6 | 6 |  | 7 | 6 |\r
721 //!     |   | 7 |  |   | 7 |  |   | 7 |  |   | 7 |\r
722 //!     +-------+  +-------+  +-------+  +-------+\r
723 //! \endverbatim\r
724 //!\r
725 //! This function is contained in <tt>osram96x16.c</tt>, with\r
726 //! <tt>osram96x16.h</tt> containing the API definition for use by\r
727 //! applications.\r
728 //!\r
729 //! \return None.\r
730 //\r
731 //*****************************************************************************\r
732 void\r
733 OSRAMImageDraw(const unsigned char *pucImage, unsigned long ulX,\r
734                unsigned long ulY, unsigned long ulWidth,\r
735                unsigned long ulHeight)\r
736 {\r
737     //\r
738     // Check the arguments.\r
739     //\r
740     ASSERT(ulX < 96);\r
741     ASSERT(ulY < 2);\r
742     ASSERT((ulX + ulWidth) <= 96);\r
743     ASSERT((ulY + ulHeight) <= 2);\r
744 \r
745     //\r
746     // The first 36 columns of the LCD buffer are not displayed, so increment\r
747     // the X coorddinate by 36 to account for the non-displayed frame buffer\r
748     // memory.\r
749     //\r
750     ulX += 36;\r
751 \r
752     //\r
753     // Loop while there are more rows to display.\r
754     //\r
755     while(ulHeight--)\r
756     {\r
757         //\r
758         // Write the starting address within this row.\r
759         //\r
760         OSRAMWriteFirst(0x80);\r
761         OSRAMWriteByte((ulY == 0) ? 0xb0 : 0xb1);\r
762         OSRAMWriteByte(0x80);\r
763         OSRAMWriteByte(ulX & 0x0f);\r
764         OSRAMWriteByte(0x80);\r
765         OSRAMWriteByte(0x10 | ((ulX >> 4) & 0x0f));\r
766         OSRAMWriteByte(0x40);\r
767 \r
768         //\r
769         // Write this row of image data.\r
770         //\r
771         OSRAMWriteArray(pucImage, ulWidth - 1);\r
772         OSRAMWriteFinal(pucImage[ulWidth - 1]);\r
773 \r
774         //\r
775         // Advance to the next row of the image.\r
776         //\r
777         pucImage += ulWidth;\r
778         ulY++;\r
779     }\r
780 }\r
781 \r
782 //*****************************************************************************\r
783 //\r
784 //! Initialize the OLED display.\r
785 //!\r
786 //! \param bFast is a boolean that is \e true if the I2C interface should be\r
787 //! run at 400 kbps and \e false if it should be run at 100 kbps.\r
788 //!\r
789 //! This function initializes the I2C interface to the OLED display and\r
790 //! configures the SSD0303 controller on the panel.\r
791 //!\r
792 //! This function is contained in <tt>osram96x16.c</tt>, with\r
793 //! <tt>osram96x16.h</tt> containing the API definition for use by\r
794 //! applications.\r
795 //!\r
796 //! \return None.\r
797 //\r
798 //*****************************************************************************\r
799 void\r
800 OSRAMInit(tBoolean bFast)\r
801 {\r
802     //\r
803     // Enable the I2C and GPIO port B blocks as they are needed by this driver.\r
804     //\r
805     SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C);\r
806     SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);\r
807 \r
808     //\r
809     // Configure the I2C SCL and SDA pins for I2C operation.\r
810     //\r
811     GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);\r
812 \r
813     //\r
814     // Initialize the I2C master.\r
815     //\r
816     I2CMasterInit(I2C_MASTER_BASE, bFast);\r
817 \r
818     //\r
819     // Compute the inter-byte delay for the SSD0303 controller.  This delay is\r
820     // dependent upon the I2C bus clock rate; the slower the clock the longer\r
821     // the delay required.\r
822     //\r
823     // The derivation of this formula is based on a measured delay of\r
824     // OSRAMDelay(1640) for a 100 kHz I2C bus with the CPU running at 50 MHz\r
825     // (referred to as C).  To scale this to the delay for a different CPU\r
826     // speed (since this is just a CPU-based delay loop) is:\r
827     //\r
828     //           f(CPU)\r
829     //     C * ----------\r
830     //         50,000,000\r
831     //\r
832     // To then scale this to the actual I2C rate (since it won't always be\r
833     // precisely 100 kHz):\r
834     //\r
835     //           f(CPU)     100,000\r
836     //     C * ---------- * -------\r
837     //         50,000,000    f(I2C)\r
838     //\r
839     // This equation will give the inter-byte delay required for any\r
840     // configuration of the I2C master.  But, as arranged it is impossible to\r
841     // directly compute in 32-bit arithmetic (without loosing a lot of\r
842     // accuracy).  So, the equation is simplified.\r
843     //\r
844     // Since f(I2C) is generated by dividing down from f(CPU), replace it with\r
845     // the equivalent (where TPR is the value programmed into the Master Timer\r
846     // Period Register of the I2C master, with the 1 added back):\r
847     //\r
848     //                        100,000\r
849     //           f(CPU)       -------\r
850     //     C * ---------- *    f(CPU)\r
851     //         50,000,000   ------------\r
852     //                      2 * 10 * TPR\r
853     //\r
854     // Inverting the dividend in the last term:\r
855     //\r
856     //           f(CPU)     100,000 * 2 * 10 * TPR\r
857     //     C * ---------- * ----------------------\r
858     //         50,000,000          f(CPU)\r
859     //\r
860     // The f(CPU) now cancels out.\r
861     //\r
862     //         100,000 * 2 * 10 * TPR\r
863     //     C * ----------------------\r
864     //               50,000,000\r
865     //\r
866     // Since there are no clock frequencies left in the equation, this equation\r
867     // also works for 400 kHz bus operation as well, since the 100,000 in the\r
868     // numerator becomes 400,000 but C is 1/4, which cancel out each other.\r
869     // Reducing the constants gives:\r
870     //\r
871     //         TPR              TPR             TPR\r
872     //     C * ---   =   1640 * ---   =   328 * ---\r
873     //         25               25               5\r
874     //\r
875     // Note that the constant C is actually a bit larger than it needs to be in\r
876     // order to provide some safety margin.\r
877     //\r
878     g_ulDelay = (328 * (HWREG(I2C_MASTER_BASE + I2C_MASTER_O_TPR) + 1)) / 5;\r
879 \r
880     //\r
881     // Initialize the SSD0303 controller.\r
882     //\r
883     OSRAMWriteFirst(g_pucOSRAMInit[0]);\r
884     OSRAMWriteArray(g_pucOSRAMInit + 1, sizeof(g_pucOSRAMInit) - 2);\r
885     OSRAMWriteFinal(g_pucOSRAMInit[sizeof(g_pucOSRAMInit) - 1]);\r
886 \r
887     //\r
888     // Clear the frame buffer.\r
889     //\r
890     OSRAMClear();\r
891 }\r
892 \r
893 //*****************************************************************************\r
894 //\r
895 //! Turns on the OLED display.\r
896 //!\r
897 //! This function will turn on the OLED display, causing it to display the\r
898 //! contents of its internal frame buffer.\r
899 //!\r
900 //! This function is contained in <tt>osram96x16.c</tt>, with\r
901 //! <tt>osram96x16.h</tt> containing the API definition for use by\r
902 //! applications.\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 //! This function is contained in <tt>osram96x16.c</tt>, with\r
931 //! <tt>osram96x16.h</tt> containing the API definition for use by\r
932 //! applications.\r
933 //!\r
934 //! \return None.\r
935 //\r
936 //*****************************************************************************\r
937 void\r
938 OSRAMDisplayOff(void)\r
939 {\r
940     //\r
941     // Turn off the DC-DC converter and the display.\r
942     //\r
943     OSRAMWriteFirst(0x80);\r
944     OSRAMWriteByte(0xad);\r
945     OSRAMWriteByte(0x80);\r
946     OSRAMWriteByte(0x8a);\r
947     OSRAMWriteByte(0x80);\r
948     OSRAMWriteFinal(0xae);\r
949 }\r
950 \r
951 //*****************************************************************************\r
952 //\r
953 // Close the Doxygen group.\r
954 //! @}\r
955 //\r
956 //*****************************************************************************\r