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