1 //*****************************************************************************
\r
3 // osram96x16.c - Driver for the OSRAM 96x16 graphical OLED display.
\r
5 // Copyright (c) 2006 Luminary Micro, Inc. All rights reserved.
\r
7 // Software License Agreement
\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
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
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
24 // This is part of revision 991 of the Stellaris Driver Library.
\r
26 //*****************************************************************************
\r
28 //*****************************************************************************
\r
30 //! \addtogroup ev_lm3s811_api
\r
33 //*****************************************************************************
\r
35 #include "DriverLib.h"
\r
36 #include "osram96x16.h"
\r
38 //*****************************************************************************
\r
40 // The I2C slave address of the SSD0303 controller on the OLED display.
\r
42 //*****************************************************************************
\r
43 #define SSD0303_ADDR 0x3d
\r
45 //*****************************************************************************
\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
52 //*****************************************************************************
\r
53 static const unsigned char g_pucFont[95][5] =
\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
152 //*****************************************************************************
\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
158 //*****************************************************************************
\r
159 static const unsigned char g_pucOSRAMInit[] =
\r
162 // Turn off the panel
\r
164 0x04, 0x80, 0xae, 0x80, 0xe3,
\r
167 // Set lower column address
\r
169 0x04, 0x80, 0x04, 0x80, 0xe3,
\r
172 // Set higher column address
\r
174 0x04, 0x80, 0x12, 0x80, 0xe3,
\r
177 // Set contrast control register
\r
179 0x06, 0x80, 0x81, 0x80, 0x2b, 0x80, 0xe3,
\r
182 // Set segment re-map
\r
184 0x04, 0x80, 0xa1, 0x80, 0xe3,
\r
187 // Set display start line
\r
189 0x04, 0x80, 0x40, 0x80, 0xe3,
\r
192 // Set display offset
\r
194 0x06, 0x80, 0xd3, 0x80, 0x00, 0x80, 0xe3,
\r
197 // Set multiplex ratio
\r
199 0x06, 0x80, 0xa8, 0x80, 0x0f, 0x80, 0xe3,
\r
202 // Set the display to normal mode
\r
204 0x04, 0x80, 0xa4, 0x80, 0xe3,
\r
207 // Non-inverted display
\r
209 0x04, 0x80, 0xa6, 0x80, 0xe3,
\r
212 // Set the page address
\r
214 0x04, 0x80, 0xb0, 0x80, 0xe3,
\r
217 // Set COM output scan direction
\r
219 0x04, 0x80, 0xc8, 0x80, 0xe3,
\r
222 // Set display clock divide ratio/oscillator frequency
\r
224 0x06, 0x80, 0xd5, 0x80, 0x72, 0x80, 0xe3,
\r
227 // Enable mono mode
\r
229 0x06, 0x80, 0xd8, 0x80, 0x00, 0x80, 0xe3,
\r
232 // Set pre-charge period
\r
234 0x06, 0x80, 0xd9, 0x80, 0x22, 0x80, 0xe3,
\r
237 // Set COM pins hardware configuration
\r
239 0x06, 0x80, 0xda, 0x80, 0x12, 0x80, 0xe3,
\r
242 // Set VCOM deslect level
\r
244 0x06, 0x80, 0xdb, 0x80, 0x0f, 0x80, 0xe3,
\r
249 0x06, 0x80, 0xad, 0x80, 0x8b, 0x80, 0xe3,
\r
252 // Turn on the panel
\r
254 0x04, 0x80, 0xaf, 0x80, 0xe3,
\r
257 //*****************************************************************************
\r
259 // The inter-byte delay required by the SSD0303 OLED controller.
\r
261 //*****************************************************************************
\r
262 static unsigned long g_ulDelay;
\r
264 //*****************************************************************************
\r
268 //! Provide a small delay.
\r
270 //! \param ulCount is the number of delay loop iterations to perform.
\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
279 //*****************************************************************************
\r
282 OSRAMDelay(unsigned long ulCount)
\r
284 __asm(" subs r0, #1\n"
\r
285 " bne.n OSRAMDelay\n"
\r
290 static void __attribute__((naked))
\r
291 OSRAMDelay(unsigned long ulCount)
\r
293 __asm(" subs r0, #1\n"
\r
294 " bne OSRAMDelay\n"
\r
298 #if defined(rvmdk) || defined(__ARMCC_VERSION)
\r
300 OSRAMDelay(unsigned long ulCount)
\r
308 //*****************************************************************************
\r
312 //! Start a transfer to the SSD0303 controller.
\r
314 //! \param ucChar is the first byte to be written to the controller.
\r
316 //! This function will start a transfer to the SSD0303 controller via the I2C
\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
324 //*****************************************************************************
\r
326 OSRAMWriteFirst(unsigned char ucChar)
\r
329 // Set the slave address.
\r
331 I2CMasterSlaveAddrSet(I2C_MASTER_BASE, SSD0303_ADDR, false);
\r
334 // Write the first byte to the controller.
\r
336 I2CMasterDataPut(I2C_MASTER_BASE, ucChar);
\r
339 // Start the transfer.
\r
341 I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);
\r
344 //*****************************************************************************
\r
348 //! Write a byte to the SSD0303 controller.
\r
350 //! \param ucChar is the byte to be transmitted to the controller.
\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
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
361 //*****************************************************************************
\r
363 OSRAMWriteByte(unsigned char ucChar)
\r
366 // Wait until the current byte has been transferred.
\r
368 while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)
\r
373 // Provide the required inter-byte delay.
\r
375 OSRAMDelay(g_ulDelay);
\r
378 // Write the next byte to the controller.
\r
380 I2CMasterDataPut(I2C_MASTER_BASE, ucChar);
\r
383 // Continue the transfer.
\r
385 I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
\r
388 //*****************************************************************************
\r
392 //! Write a sequence of bytes to the SSD0303 controller.
\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
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
403 //*****************************************************************************
\r
405 OSRAMWriteArray(const unsigned char *pucBuffer, unsigned long ulCount)
\r
408 // Loop while there are more bytes left to be transferred.
\r
410 while(ulCount != 0)
\r
413 // Wait until the current byte has been transferred.
\r
415 while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)
\r
420 // Provide the required inter-byte delay.
\r
422 OSRAMDelay(g_ulDelay);
\r
425 // Write the next byte to the controller.
\r
427 I2CMasterDataPut(I2C_MASTER_BASE, *pucBuffer++);
\r
431 // Continue the transfer.
\r
433 I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
\r
437 //*****************************************************************************
\r
441 //! Finish a transfer to the SSD0303 controller.
\r
443 //! \param ucChar is the final byte to be written to the controller.
\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
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
453 //*****************************************************************************
\r
455 OSRAMWriteFinal(unsigned char ucChar)
\r
458 // Wait until the current byte has been transferred.
\r
460 while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)
\r
465 // Provide the required inter-byte delay.
\r
467 OSRAMDelay(g_ulDelay);
\r
470 // Write the final byte to the controller.
\r
472 I2CMasterDataPut(I2C_MASTER_BASE, ucChar);
\r
475 // Finish the transfer.
\r
477 I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
\r
480 // Wait until the final byte has been transferred.
\r
482 while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)
\r
487 // Provide the required inter-byte delay.
\r
489 OSRAMDelay(g_ulDelay);
\r
492 //*****************************************************************************
\r
494 //! Clears the OLED display.
\r
496 //! This function will clear the display. All pixels in the display will be
\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
505 //*****************************************************************************
\r
509 static const unsigned char pucRow1[] =
\r
511 0xb0, 0x80, 0x04, 0x80, 0x12, 0x40
\r
513 static const unsigned char pucRow2[] =
\r
515 0xb1, 0x80, 0x04, 0x80, 0x12, 0x40
\r
517 unsigned long ulIdx;
\r
520 // Move the display cursor to the first column of the first row.
\r
522 OSRAMWriteFirst(0x80);
\r
523 OSRAMWriteArray(pucRow1, sizeof(pucRow1));
\r
526 // Fill this row with zeros.
\r
528 for(ulIdx = 0; ulIdx < 95; ulIdx++)
\r
530 OSRAMWriteByte(0x00);
\r
532 OSRAMWriteFinal(0x00);
\r
535 // Move the display cursor to the first column of the second row.
\r
537 OSRAMWriteFirst(0x80);
\r
538 OSRAMWriteArray(pucRow2, sizeof(pucRow2));
\r
541 // Fill this row with zeros.
\r
543 for(ulIdx = 0; ulIdx < 95; ulIdx++)
\r
545 OSRAMWriteByte(0x00);
\r
547 OSRAMWriteFinal(0x00);
\r
550 //*****************************************************************************
\r
552 //! Displays a string on the OLED display.
\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
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
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
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
578 //*****************************************************************************
\r
580 OSRAMStringDraw(const char *pcStr, unsigned long ulX, unsigned long ulY)
\r
583 // Check the arguments.
\r
589 // Move the display cursor to the requested position on the display.
\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
600 // Loop while there are more characters in the string.
\r
605 // See if there is enough space on the display for this entire
\r
611 // Write the contents of this character to the display.
\r
613 OSRAMWriteArray(g_pucFont[*pcStr - ' '], 5);
\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
620 if((ulX == 90) || (pcStr[1] == 0))
\r
623 // Write the final column of the display.
\r
625 OSRAMWriteFinal(0x00);
\r
628 // The string has been displayed.
\r
634 // Write the inter-character padding column.
\r
636 OSRAMWriteByte(0x00);
\r
641 // Write the portion of the character that will fit onto the
\r
644 OSRAMWriteArray(g_pucFont[*pcStr - ' '], 95 - ulX);
\r
645 OSRAMWriteFinal(g_pucFont[*pcStr - ' '][95 - ulX]);
\r
648 // The string has been displayed.
\r
654 // Advance to the next character.
\r
659 // Increment the X coordinate by the six columns that were just
\r
666 //*****************************************************************************
\r
668 //! Displays an image on the OLED display.
\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
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
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
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
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
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
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
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
726 //*****************************************************************************
\r
728 OSRAMImageDraw(const unsigned char *pucImage, unsigned long ulX,
\r
729 unsigned long ulY, unsigned long ulWidth,
\r
730 unsigned long ulHeight)
\r
733 // Check the arguments.
\r
737 ASSERT((ulX + ulWidth) <= 96);
\r
738 ASSERT((ulY + ulHeight) <= 2);
\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
748 // Loop while there are more rows to display.
\r
753 // Write the starting address within this row.
\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
764 // Write this row of image data.
\r
766 OSRAMWriteArray(pucImage, ulWidth - 1);
\r
767 OSRAMWriteFinal(pucImage[ulWidth - 1]);
\r
770 // Advance to the next row of the image.
\r
772 pucImage += ulWidth;
\r
777 //*****************************************************************************
\r
779 //! Initialize the OLED display.
\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
784 //! This function initializes the I2C interface to the OLED display and
\r
785 //! configures the SSD0303 controller on the panel.
\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
793 //*****************************************************************************
\r
795 OSRAMInit(tBoolean bFast)
\r
797 unsigned long ulIdx;
\r
800 // Enable the I2C and GPIO port B blocks as they are needed by this driver.
\r
802 SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C);
\r
803 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
\r
806 // Configure the I2C SCL and SDA pins for I2C operation.
\r
808 GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
\r
811 // Initialize the I2C master.
\r
813 I2CMasterInitExpClk(I2C_MASTER_BASE, SysCtlClockGet(), bFast);
\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
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
829 // To then scale this to the actual I2C rate (since it won't always be
\r
830 // precisely 100 kHz):
\r
833 // C * ---------- * -------
\r
834 // 50,000,000 f(I2C)
\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
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
847 // C * ---------- * f(CPU)
\r
848 // 50,000,000 ------------
\r
851 // Inverting the dividend in the last term:
\r
853 // f(CPU) 100,000 * 2 * 10 * TPR
\r
854 // C * ---------- * ----------------------
\r
855 // 50,000,000 f(CPU)
\r
857 // The f(CPU) now cancels out.
\r
859 // 100,000 * 2 * 10 * TPR
\r
860 // C * ----------------------
\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
869 // C * --- = 1700 * --- = 340 * --- = 68 * TPR
\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
875 g_ulDelay = 68 * (HWREG(I2C_MASTER_BASE + I2C_MASTER_O_TPR) + 1);
\r
878 // Initialize the SSD0303 controller. Loop through the initialization
\r
879 // sequence doing a single I2C transfer for each command.
\r
881 for(ulIdx = 0; ulIdx < sizeof(g_pucOSRAMInit);
\r
882 ulIdx += g_pucOSRAMInit[ulIdx] + 1)
\r
885 // Send this command.
\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
893 // Clear the frame buffer.
\r
898 //*****************************************************************************
\r
900 //! Turns on the OLED display.
\r
902 //! This function will turn on the OLED display, causing it to display the
\r
903 //! contents of its internal frame buffer.
\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
911 //*****************************************************************************
\r
913 OSRAMDisplayOn(void)
\r
915 unsigned long ulIdx;
\r
918 // Re-initialize the SSD0303 controller. Loop through the initialization
\r
919 // sequence doing a single I2C transfer for each command.
\r
921 for(ulIdx = 0; ulIdx < sizeof(g_pucOSRAMInit);
\r
922 ulIdx += g_pucOSRAMInit[ulIdx] + 1)
\r
925 // Send this command.
\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
933 //*****************************************************************************
\r
935 //! Turns off the OLED display.
\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
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
948 //*****************************************************************************
\r
950 OSRAMDisplayOff(void)
\r
953 // Turn off the DC-DC converter and the display.
\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
963 //*****************************************************************************
\r
965 // Close the Doxygen group.
\r
968 //*****************************************************************************
\r