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