1 //*****************************************************************************
\r
3 // osram96x16.c - Driver for the OSRAM 96x16 graphical OLED display.
\r
5 // Copyright (c) 2006-2007 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 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 1049 of the Stellaris Driver Library.
\r
26 //*****************************************************************************
\r
28 //*****************************************************************************
\r
30 //! \addtogroup ev_lm3s811_api
\r
33 //*****************************************************************************
\r
36 #include "hw_memmap.h"
\r
37 #include "hw_sysctl.h"
\r
38 #include "hw_types.h"
\r
43 #include "osram96x16.h"
\r
45 //*****************************************************************************
\r
47 // The I2C slave address of the SSD0303 controller on the OLED display.
\r
49 //*****************************************************************************
\r
50 #define SSD0303_ADDR 0x3d
\r
52 //*****************************************************************************
\r
54 // A 5x7 font (in a 6x8 cell, where the sixth column is omitted from this
\r
55 // table) for displaying text on the OLED display. The data is organized as
\r
56 // bytes from the left column to the right column, with each byte containing
\r
57 // the top row in the LSB and the bottom row in the MSB.
\r
59 //*****************************************************************************
\r
60 static const unsigned char g_pucFont[95][5] =
\r
62 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // " "
\r
63 { 0x00, 0x00, 0x4f, 0x00, 0x00 }, // !
\r
64 { 0x00, 0x07, 0x00, 0x07, 0x00 }, // "
\r
65 { 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // #
\r
66 { 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $
\r
67 { 0x23, 0x13, 0x08, 0x64, 0x62 }, // %
\r
68 { 0x36, 0x49, 0x55, 0x22, 0x50 }, // &
\r
69 { 0x00, 0x05, 0x03, 0x00, 0x00 }, // '
\r
70 { 0x00, 0x1c, 0x22, 0x41, 0x00 }, // (
\r
71 { 0x00, 0x41, 0x22, 0x1c, 0x00 }, // )
\r
72 { 0x14, 0x08, 0x3e, 0x08, 0x14 }, // *
\r
73 { 0x08, 0x08, 0x3e, 0x08, 0x08 }, // +
\r
74 { 0x00, 0x50, 0x30, 0x00, 0x00 }, // ,
\r
75 { 0x08, 0x08, 0x08, 0x08, 0x08 }, // -
\r
76 { 0x00, 0x60, 0x60, 0x00, 0x00 }, // .
\r
77 { 0x20, 0x10, 0x08, 0x04, 0x02 }, // /
\r
78 { 0x3e, 0x51, 0x49, 0x45, 0x3e }, // 0
\r
79 { 0x00, 0x42, 0x7f, 0x40, 0x00 }, // 1
\r
80 { 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2
\r
81 { 0x21, 0x41, 0x45, 0x4b, 0x31 }, // 3
\r
82 { 0x18, 0x14, 0x12, 0x7f, 0x10 }, // 4
\r
83 { 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5
\r
84 { 0x3c, 0x4a, 0x49, 0x49, 0x30 }, // 6
\r
85 { 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7
\r
86 { 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8
\r
87 { 0x06, 0x49, 0x49, 0x29, 0x1e }, // 9
\r
88 { 0x00, 0x36, 0x36, 0x00, 0x00 }, // :
\r
89 { 0x00, 0x56, 0x36, 0x00, 0x00 }, // ;
\r
90 { 0x08, 0x14, 0x22, 0x41, 0x00 }, // <
\r
91 { 0x14, 0x14, 0x14, 0x14, 0x14 }, // =
\r
92 { 0x00, 0x41, 0x22, 0x14, 0x08 }, // >
\r
93 { 0x02, 0x01, 0x51, 0x09, 0x06 }, // ?
\r
94 { 0x32, 0x49, 0x79, 0x41, 0x3e }, // @
\r
95 { 0x7e, 0x11, 0x11, 0x11, 0x7e }, // A
\r
96 { 0x7f, 0x49, 0x49, 0x49, 0x36 }, // B
\r
97 { 0x3e, 0x41, 0x41, 0x41, 0x22 }, // C
\r
98 { 0x7f, 0x41, 0x41, 0x22, 0x1c }, // D
\r
99 { 0x7f, 0x49, 0x49, 0x49, 0x41 }, // E
\r
100 { 0x7f, 0x09, 0x09, 0x09, 0x01 }, // F
\r
101 { 0x3e, 0x41, 0x49, 0x49, 0x7a }, // G
\r
102 { 0x7f, 0x08, 0x08, 0x08, 0x7f }, // H
\r
103 { 0x00, 0x41, 0x7f, 0x41, 0x00 }, // I
\r
104 { 0x20, 0x40, 0x41, 0x3f, 0x01 }, // J
\r
105 { 0x7f, 0x08, 0x14, 0x22, 0x41 }, // K
\r
106 { 0x7f, 0x40, 0x40, 0x40, 0x40 }, // L
\r
107 { 0x7f, 0x02, 0x0c, 0x02, 0x7f }, // M
\r
108 { 0x7f, 0x04, 0x08, 0x10, 0x7f }, // N
\r
109 { 0x3e, 0x41, 0x41, 0x41, 0x3e }, // O
\r
110 { 0x7f, 0x09, 0x09, 0x09, 0x06 }, // P
\r
111 { 0x3e, 0x41, 0x51, 0x21, 0x5e }, // Q
\r
112 { 0x7f, 0x09, 0x19, 0x29, 0x46 }, // R
\r
113 { 0x46, 0x49, 0x49, 0x49, 0x31 }, // S
\r
114 { 0x01, 0x01, 0x7f, 0x01, 0x01 }, // T
\r
115 { 0x3f, 0x40, 0x40, 0x40, 0x3f }, // U
\r
116 { 0x1f, 0x20, 0x40, 0x20, 0x1f }, // V
\r
117 { 0x3f, 0x40, 0x38, 0x40, 0x3f }, // W
\r
118 { 0x63, 0x14, 0x08, 0x14, 0x63 }, // X
\r
119 { 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y
\r
120 { 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z
\r
121 { 0x00, 0x7f, 0x41, 0x41, 0x00 }, // [
\r
122 { 0x02, 0x04, 0x08, 0x10, 0x20 }, // "\"
\r
123 { 0x00, 0x41, 0x41, 0x7f, 0x00 }, // ]
\r
124 { 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^
\r
125 { 0x40, 0x40, 0x40, 0x40, 0x40 }, // _
\r
126 { 0x00, 0x01, 0x02, 0x04, 0x00 }, // `
\r
127 { 0x20, 0x54, 0x54, 0x54, 0x78 }, // a
\r
128 { 0x7f, 0x48, 0x44, 0x44, 0x38 }, // b
\r
129 { 0x38, 0x44, 0x44, 0x44, 0x20 }, // c
\r
130 { 0x38, 0x44, 0x44, 0x48, 0x7f }, // d
\r
131 { 0x38, 0x54, 0x54, 0x54, 0x18 }, // e
\r
132 { 0x08, 0x7e, 0x09, 0x01, 0x02 }, // f
\r
133 { 0x0c, 0x52, 0x52, 0x52, 0x3e }, // g
\r
134 { 0x7f, 0x08, 0x04, 0x04, 0x78 }, // h
\r
135 { 0x00, 0x44, 0x7d, 0x40, 0x00 }, // i
\r
136 { 0x20, 0x40, 0x44, 0x3d, 0x00 }, // j
\r
137 { 0x7f, 0x10, 0x28, 0x44, 0x00 }, // k
\r
138 { 0x00, 0x41, 0x7f, 0x40, 0x00 }, // l
\r
139 { 0x7c, 0x04, 0x18, 0x04, 0x78 }, // m
\r
140 { 0x7c, 0x08, 0x04, 0x04, 0x78 }, // n
\r
141 { 0x38, 0x44, 0x44, 0x44, 0x38 }, // o
\r
142 { 0x7c, 0x14, 0x14, 0x14, 0x08 }, // p
\r
143 { 0x08, 0x14, 0x14, 0x18, 0x7c }, // q
\r
144 { 0x7c, 0x08, 0x04, 0x04, 0x08 }, // r
\r
145 { 0x48, 0x54, 0x54, 0x54, 0x20 }, // s
\r
146 { 0x04, 0x3f, 0x44, 0x40, 0x20 }, // t
\r
147 { 0x3c, 0x40, 0x40, 0x20, 0x7c }, // u
\r
148 { 0x1c, 0x20, 0x40, 0x20, 0x1c }, // v
\r
149 { 0x3c, 0x40, 0x30, 0x40, 0x3c }, // w
\r
150 { 0x44, 0x28, 0x10, 0x28, 0x44 }, // x
\r
151 { 0x0c, 0x50, 0x50, 0x50, 0x3c }, // y
\r
152 { 0x44, 0x64, 0x54, 0x4c, 0x44 }, // z
\r
153 { 0x00, 0x08, 0x36, 0x41, 0x00 }, // {
\r
154 { 0x00, 0x00, 0x7f, 0x00, 0x00 }, // |
\r
155 { 0x00, 0x41, 0x36, 0x08, 0x00 }, // }
\r
156 { 0x02, 0x01, 0x02, 0x04, 0x02 }, // ~
\r
159 //*****************************************************************************
\r
161 // The sequence of commands used to initialize the SSD0303 controller. Each
\r
162 // command is described as follows: there is a byte specifying the number of
\r
163 // bytes in the I2C transfer, followed by that many bytes of command data.
\r
165 //*****************************************************************************
\r
166 static const unsigned char g_pucOSRAMInit[] =
\r
169 // Turn off the panel
\r
171 0x04, 0x80, 0xae, 0x80, 0xe3,
\r
174 // Set lower column address
\r
176 0x04, 0x80, 0x04, 0x80, 0xe3,
\r
179 // Set higher column address
\r
181 0x04, 0x80, 0x12, 0x80, 0xe3,
\r
184 // Set contrast control register
\r
186 0x06, 0x80, 0x81, 0x80, 0x2b, 0x80, 0xe3,
\r
189 // Set segment re-map
\r
191 0x04, 0x80, 0xa1, 0x80, 0xe3,
\r
194 // Set display start line
\r
196 0x04, 0x80, 0x40, 0x80, 0xe3,
\r
199 // Set display offset
\r
201 0x06, 0x80, 0xd3, 0x80, 0x00, 0x80, 0xe3,
\r
204 // Set multiplex ratio
\r
206 0x06, 0x80, 0xa8, 0x80, 0x0f, 0x80, 0xe3,
\r
209 // Set the display to normal mode
\r
211 0x04, 0x80, 0xa4, 0x80, 0xe3,
\r
214 // Non-inverted display
\r
216 0x04, 0x80, 0xa6, 0x80, 0xe3,
\r
219 // Set the page address
\r
221 0x04, 0x80, 0xb0, 0x80, 0xe3,
\r
224 // Set COM output scan direction
\r
226 0x04, 0x80, 0xc8, 0x80, 0xe3,
\r
229 // Set display clock divide ratio/oscillator frequency
\r
231 0x06, 0x80, 0xd5, 0x80, 0x72, 0x80, 0xe3,
\r
234 // Enable mono mode
\r
236 0x06, 0x80, 0xd8, 0x80, 0x00, 0x80, 0xe3,
\r
239 // Set pre-charge period
\r
241 0x06, 0x80, 0xd9, 0x80, 0x22, 0x80, 0xe3,
\r
244 // Set COM pins hardware configuration
\r
246 0x06, 0x80, 0xda, 0x80, 0x12, 0x80, 0xe3,
\r
249 // Set VCOM deslect level
\r
251 0x06, 0x80, 0xdb, 0x80, 0x0f, 0x80, 0xe3,
\r
256 0x06, 0x80, 0xad, 0x80, 0x8b, 0x80, 0xe3,
\r
259 // Turn on the panel
\r
261 0x04, 0x80, 0xaf, 0x80, 0xe3,
\r
264 //*****************************************************************************
\r
266 // The inter-byte delay required by the SSD0303 OLED controller.
\r
268 //*****************************************************************************
\r
269 static unsigned long g_ulDelay;
\r
271 //*****************************************************************************
\r
275 //! Provide a small delay.
\r
277 //! \param ulCount is the number of delay loop iterations to perform.
\r
279 //! Since the SSD0303 controller needs a delay between bytes written to it over
\r
280 //! the I2C bus, this function provides a means of generating that delay. It
\r
281 //! is written in assembly to keep the delay consistent across tool chains,
\r
282 //! avoiding the need to tune the delay based on the tool chain in use.
\r
286 //*****************************************************************************
\r
289 OSRAMDelay(unsigned long ulCount)
\r
291 __asm(" subs r0, #1\n"
\r
292 " bne OSRAMDelay\n"
\r
297 static void __attribute__((naked))
\r
298 OSRAMDelay(unsigned long ulCount)
\r
300 __asm(" subs r0, #1\n"
\r
301 " bne OSRAMDelay\n"
\r
305 #if defined(rvmdk) || defined(__ARMCC_VERSION)
\r
307 OSRAMDelay(unsigned long ulCount)
\r
315 //*****************************************************************************
\r
319 //! Start a transfer to the SSD0303 controller.
\r
321 //! \param ucChar is the first byte to be written to the controller.
\r
323 //! This function will start a transfer to the SSD0303 controller via the I2C
\r
326 //! The data is written in a polled fashion; this function will not return
\r
327 //! until the byte has been written to the controller.
\r
331 //*****************************************************************************
\r
333 OSRAMWriteFirst(unsigned char ucChar)
\r
336 // Set the slave address.
\r
338 I2CMasterSlaveAddrSet(I2C_MASTER_BASE, SSD0303_ADDR, false);
\r
341 // Write the first byte to the controller.
\r
343 I2CMasterDataPut(I2C_MASTER_BASE, ucChar);
\r
346 // Start the transfer.
\r
348 I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);
\r
351 //*****************************************************************************
\r
355 //! Write a byte to the SSD0303 controller.
\r
357 //! \param ucChar is the byte to be transmitted to the controller.
\r
359 //! This function continues a transfer to the SSD0303 controller by writing
\r
360 //! another byte over the I2C bus. This must only be called after calling
\r
361 //! OSRAMWriteFirst(), but before calling OSRAMWriteFinal().
\r
363 //! The data is written in a polled faashion; this function will not return
\r
364 //! until the byte has been written to the controller.
\r
368 //*****************************************************************************
\r
370 OSRAMWriteByte(unsigned char ucChar)
\r
373 // Wait until the current byte has been transferred.
\r
375 while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)
\r
380 // Provide the required inter-byte delay.
\r
382 OSRAMDelay(g_ulDelay);
\r
385 // Write the next byte to the controller.
\r
387 I2CMasterDataPut(I2C_MASTER_BASE, ucChar);
\r
390 // Continue the transfer.
\r
392 I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
\r
395 //*****************************************************************************
\r
399 //! Write a sequence of bytes to the SSD0303 controller.
\r
401 //! This function continues a transfer to the SSD0303 controller by writing a
\r
402 //! sequence of bytes over the I2C bus. This must only be called after calling
\r
403 //! OSRAMWriteFirst(), but before calling OSRAMWriteFinal().
\r
405 //! The data is written in a polled fashion; this function will not return
\r
406 //! until the entire byte sequence has been written to the controller.
\r
410 //*****************************************************************************
\r
412 OSRAMWriteArray(const unsigned char *pucBuffer, unsigned long ulCount)
\r
415 // Loop while there are more bytes left to be transferred.
\r
417 while(ulCount != 0)
\r
420 // Wait until the current byte has been transferred.
\r
422 while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)
\r
427 // Provide the required inter-byte delay.
\r
429 OSRAMDelay(g_ulDelay);
\r
432 // Write the next byte to the controller.
\r
434 I2CMasterDataPut(I2C_MASTER_BASE, *pucBuffer++);
\r
438 // Continue the transfer.
\r
440 I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
\r
444 //*****************************************************************************
\r
448 //! Finish a transfer to the SSD0303 controller.
\r
450 //! \param ucChar is the final byte to be written to the controller.
\r
452 //! This function will finish a transfer to the SSD0303 controller via the I2C
\r
453 //! bus. This must only be called after calling OSRAMWriteFirst().
\r
455 //! The data is written in a polled fashion; this function will not return
\r
456 //! until the byte has been written to the controller.
\r
460 //*****************************************************************************
\r
462 OSRAMWriteFinal(unsigned char ucChar)
\r
465 // Wait until the current byte has been transferred.
\r
467 while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)
\r
472 // Provide the required inter-byte delay.
\r
474 OSRAMDelay(g_ulDelay);
\r
477 // Write the final byte to the controller.
\r
479 I2CMasterDataPut(I2C_MASTER_BASE, ucChar);
\r
482 // Finish the transfer.
\r
484 I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
\r
487 // Wait until the final byte has been transferred.
\r
489 while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)
\r
494 // Provide the required inter-byte delay.
\r
496 OSRAMDelay(g_ulDelay);
\r
499 //*****************************************************************************
\r
501 //! Clears the OLED display.
\r
503 //! This function will clear the display. All pixels in the display will be
\r
506 //! This function is contained in <tt>osram96x16.c</tt>, with
\r
507 //! <tt>osram96x16.h</tt> containing the API definition for use by
\r
512 //*****************************************************************************
\r
516 static const unsigned char pucRow1[] =
\r
518 0xb0, 0x80, 0x04, 0x80, 0x12, 0x40
\r
520 static const unsigned char pucRow2[] =
\r
522 0xb1, 0x80, 0x04, 0x80, 0x12, 0x40
\r
524 unsigned long ulIdx;
\r
527 // Move the display cursor to the first column of the first row.
\r
529 OSRAMWriteFirst(0x80);
\r
530 OSRAMWriteArray(pucRow1, sizeof(pucRow1));
\r
533 // Fill this row with zeros.
\r
535 for(ulIdx = 0; ulIdx < 95; ulIdx++)
\r
537 OSRAMWriteByte(0x00);
\r
539 OSRAMWriteFinal(0x00);
\r
542 // Move the display cursor to the first column of the second row.
\r
544 OSRAMWriteFirst(0x80);
\r
545 OSRAMWriteArray(pucRow2, sizeof(pucRow2));
\r
548 // Fill this row with zeros.
\r
550 for(ulIdx = 0; ulIdx < 95; ulIdx++)
\r
552 OSRAMWriteByte(0x00);
\r
554 OSRAMWriteFinal(0x00);
\r
557 //*****************************************************************************
\r
559 //! Displays a string on the OLED display.
\r
561 //! \param pcStr is a pointer to the string to display.
\r
562 //! \param ulX is the horizontal position to display the string, specified in
\r
563 //! columns from the left edge of the display.
\r
564 //! \param ulY is the vertical position to display the string, specified in
\r
565 //! eight scan line blocks from the top of the display (i.e. only 0 and 1 are
\r
568 //! This function will draw a string on the display. Only the ASCII characters
\r
569 //! between 32 (space) and 126 (tilde) are supported; other characters will
\r
570 //! result in random data being draw on the display (based on whatever appears
\r
571 //! before/after the font in memory). The font is mono-spaced, so characters
\r
572 //! such as "i" and "l" have more white space around them than characters such
\r
575 //! If the drawing of the string reaches the right edge of the display, no more
\r
576 //! characters will be drawn. Therefore, special care is not required to avoid
\r
577 //! supplying a string that is "too long" to display.
\r
579 //! This function is contained in <tt>osram96x16.c</tt>, with
\r
580 //! <tt>osram96x16.h</tt> containing the API definition for use by
\r
585 //*****************************************************************************
\r
587 OSRAMStringDraw(const char *pcStr, unsigned long ulX, unsigned long ulY)
\r
590 // Check the arguments.
\r
596 // Move the display cursor to the requested position on the display.
\r
598 OSRAMWriteFirst(0x80);
\r
599 OSRAMWriteByte((ulY == 0) ? 0xb0 : 0xb1);
\r
600 OSRAMWriteByte(0x80);
\r
601 OSRAMWriteByte((ulX + 36) & 0x0f);
\r
602 OSRAMWriteByte(0x80);
\r
603 OSRAMWriteByte(0x10 | (((ulX + 36) >> 4) & 0x0f));
\r
604 OSRAMWriteByte(0x40);
\r
607 // Loop while there are more characters in the string.
\r
612 // See if there is enough space on the display for this entire
\r
618 // Write the contents of this character to the display.
\r
620 OSRAMWriteArray(g_pucFont[*pcStr - ' '], 5);
\r
623 // See if this is the last character to display (either because the
\r
624 // right edge has been reached or because there are no more
\r
627 if((ulX == 90) || (pcStr[1] == 0))
\r
630 // Write the final column of the display.
\r
632 OSRAMWriteFinal(0x00);
\r
635 // The string has been displayed.
\r
641 // Write the inter-character padding column.
\r
643 OSRAMWriteByte(0x00);
\r
648 // Write the portion of the character that will fit onto the
\r
651 OSRAMWriteArray(g_pucFont[*pcStr - ' '], 95 - ulX);
\r
652 OSRAMWriteFinal(g_pucFont[*pcStr - ' '][95 - ulX]);
\r
655 // The string has been displayed.
\r
661 // Advance to the next character.
\r
666 // Increment the X coordinate by the six columns that were just
\r
673 //*****************************************************************************
\r
675 //! Displays an image on the OLED display.
\r
677 //! \param pucImage is a pointer to the image data.
\r
678 //! \param ulX is the horizontal position to display this image, specified in
\r
679 //! columns from the left edge of the display.
\r
680 //! \param ulY is the vertical position to display this image, specified in
\r
681 //! eight scan line blocks from the top of the display (i.e. only 0 and 1 are
\r
683 //! \param ulWidth is the width of the image, specified in columns.
\r
684 //! \param ulHeight is the height of the image, specified in eight row blocks
\r
685 //! (i.e. only 1 and 2 are valid).
\r
687 //! This function will display a bitmap graphic on the display. The image to
\r
688 //! be displayed must be a multiple of eight scan lines high (i.e. one row) and
\r
689 //! will be drawn at a vertical position that is a multiple of eight scan lines
\r
690 //! (i.e. scan line zero or scan line eight, corresponding to row zero or row
\r
693 //! The image data is organized with the first row of image data appearing left
\r
694 //! to right, followed immediately by the second row of image data. Each byte
\r
695 //! contains the data for the eight scan lines of the column, with the top scan
\r
696 //! line being in the least significant bit of the byte and the bottom scan
\r
697 //! line being in the most significant bit of the byte.
\r
699 //! For example, an image four columns wide and sixteen scan lines tall would
\r
700 //! be arranged as follows (showing how the eight bytes of the image would
\r
701 //! appear on the display):
\r
704 //! +-------+ +-------+ +-------+ +-------+
\r
705 //! | | 0 | | | 0 | | | 0 | | | 0 |
\r
706 //! | B | 1 | | B | 1 | | B | 1 | | B | 1 |
\r
707 //! | y | 2 | | y | 2 | | y | 2 | | y | 2 |
\r
708 //! | t | 3 | | t | 3 | | t | 3 | | t | 3 |
\r
709 //! | e | 4 | | e | 4 | | e | 4 | | e | 4 |
\r
710 //! | | 5 | | | 5 | | | 5 | | | 5 |
\r
711 //! | 0 | 6 | | 1 | 6 | | 2 | 6 | | 3 | 6 |
\r
712 //! | | 7 | | | 7 | | | 7 | | | 7 |
\r
713 //! +-------+ +-------+ +-------+ +-------+
\r
715 //! +-------+ +-------+ +-------+ +-------+
\r
716 //! | | 0 | | | 0 | | | 0 | | | 0 |
\r
717 //! | B | 1 | | B | 1 | | B | 1 | | B | 1 |
\r
718 //! | y | 2 | | y | 2 | | y | 2 | | y | 2 |
\r
719 //! | t | 3 | | t | 3 | | t | 3 | | t | 3 |
\r
720 //! | e | 4 | | e | 4 | | e | 4 | | e | 4 |
\r
721 //! | | 5 | | | 5 | | | 5 | | | 5 |
\r
722 //! | 4 | 6 | | 5 | 6 | | 6 | 6 | | 7 | 6 |
\r
723 //! | | 7 | | | 7 | | | 7 | | | 7 |
\r
724 //! +-------+ +-------+ +-------+ +-------+
\r
727 //! This function is contained in <tt>osram96x16.c</tt>, with
\r
728 //! <tt>osram96x16.h</tt> containing the API definition for use by
\r
733 //*****************************************************************************
\r
735 OSRAMImageDraw(const unsigned char *pucImage, unsigned long ulX,
\r
736 unsigned long ulY, unsigned long ulWidth,
\r
737 unsigned long ulHeight)
\r
740 // Check the arguments.
\r
744 ASSERT((ulX + ulWidth) <= 96);
\r
745 ASSERT((ulY + ulHeight) <= 2);
\r
748 // The first 36 columns of the LCD buffer are not displayed, so increment
\r
749 // the X coorddinate by 36 to account for the non-displayed frame buffer
\r
755 // Loop while there are more rows to display.
\r
760 // Write the starting address within this row.
\r
762 OSRAMWriteFirst(0x80);
\r
763 OSRAMWriteByte((ulY == 0) ? 0xb0 : 0xb1);
\r
764 OSRAMWriteByte(0x80);
\r
765 OSRAMWriteByte(ulX & 0x0f);
\r
766 OSRAMWriteByte(0x80);
\r
767 OSRAMWriteByte(0x10 | ((ulX >> 4) & 0x0f));
\r
768 OSRAMWriteByte(0x40);
\r
771 // Write this row of image data.
\r
773 OSRAMWriteArray(pucImage, ulWidth - 1);
\r
774 OSRAMWriteFinal(pucImage[ulWidth - 1]);
\r
777 // Advance to the next row of the image.
\r
779 pucImage += ulWidth;
\r
784 //*****************************************************************************
\r
786 //! Initialize the OLED display.
\r
788 //! \param bFast is a boolean that is \e true if the I2C interface should be
\r
789 //! run at 400 kbps and \e false if it should be run at 100 kbps.
\r
791 //! This function initializes the I2C interface to the OLED display and
\r
792 //! configures the SSD0303 controller on the panel.
\r
794 //! This function is contained in <tt>osram96x16.c</tt>, with
\r
795 //! <tt>osram96x16.h</tt> containing the API definition for use by
\r
800 //*****************************************************************************
\r
802 OSRAMInit(tBoolean bFast)
\r
804 unsigned long ulIdx;
\r
807 // Enable the I2C and GPIO port B blocks as they are needed by this driver.
\r
809 SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C);
\r
810 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
\r
813 // Configure the I2C SCL and SDA pins for I2C operation.
\r
815 GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
\r
818 // Initialize the I2C master.
\r
820 I2CMasterInit(I2C_MASTER_BASE, bFast);
\r
823 // Compute the inter-byte delay for the SSD0303 controller. This delay is
\r
824 // dependent upon the I2C bus clock rate; the slower the clock the longer
\r
825 // the delay required.
\r
827 // The derivation of this formula is based on a measured delay of
\r
828 // OSRAMDelay(1700) for a 100 kHz I2C bus with the CPU running at 50 MHz
\r
829 // (referred to as C). To scale this to the delay for a different CPU
\r
830 // speed (since this is just a CPU-based delay loop) is:
\r
836 // To then scale this to the actual I2C rate (since it won't always be
\r
837 // precisely 100 kHz):
\r
840 // C * ---------- * -------
\r
841 // 50,000,000 f(I2C)
\r
843 // This equation will give the inter-byte delay required for any
\r
844 // configuration of the I2C master. But, as arranged it is impossible to
\r
845 // directly compute in 32-bit arithmetic (without loosing a lot of
\r
846 // accuracy). So, the equation is simplified.
\r
848 // Since f(I2C) is generated by dividing down from f(CPU), replace it with
\r
849 // the equivalent (where TPR is the value programmed into the Master Timer
\r
850 // Period Register of the I2C master, with the 1 added back):
\r
854 // C * ---------- * f(CPU)
\r
855 // 50,000,000 ------------
\r
858 // Inverting the dividend in the last term:
\r
860 // f(CPU) 100,000 * 2 * 10 * TPR
\r
861 // C * ---------- * ----------------------
\r
862 // 50,000,000 f(CPU)
\r
864 // The f(CPU) now cancels out.
\r
866 // 100,000 * 2 * 10 * TPR
\r
867 // C * ----------------------
\r
870 // Since there are no clock frequencies left in the equation, this equation
\r
871 // also works for 400 kHz bus operation as well, since the 100,000 in the
\r
872 // numerator becomes 400,000 but C is 1/4, which cancel out each other.
\r
873 // Reducing the constants gives:
\r
876 // C * --- = 1700 * --- = 340 * --- = 68 * TPR
\r
879 // Note that the constant C is actually a bit larger than it needs to be in
\r
880 // order to provide some safety margin.
\r
882 g_ulDelay = 68 * (HWREG(I2C_MASTER_BASE + I2C_MASTER_O_TPR) + 1);
\r
885 // Initialize the SSD0303 controller. Loop through the initialization
\r
886 // sequence doing a single I2C transfer for each command.
\r
888 for(ulIdx = 0; ulIdx < sizeof(g_pucOSRAMInit);
\r
889 ulIdx += g_pucOSRAMInit[ulIdx] + 1)
\r
892 // Send this command.
\r
894 OSRAMWriteFirst(g_pucOSRAMInit[ulIdx + 1]);
\r
895 OSRAMWriteArray(g_pucOSRAMInit + ulIdx + 2, g_pucOSRAMInit[ulIdx] - 2);
\r
896 OSRAMWriteFinal(g_pucOSRAMInit[ulIdx + g_pucOSRAMInit[ulIdx]]);
\r
900 // Clear the frame buffer.
\r
905 //*****************************************************************************
\r
907 //! Turns on the OLED display.
\r
909 //! This function will turn on the OLED display, causing it to display the
\r
910 //! contents of its internal frame buffer.
\r
912 //! This function is contained in <tt>osram96x16.c</tt>, with
\r
913 //! <tt>osram96x16.h</tt> containing the API definition for use by
\r
918 //*****************************************************************************
\r
920 OSRAMDisplayOn(void)
\r
922 unsigned long ulIdx;
\r
925 // Re-initialize the SSD0303 controller. Loop through the initialization
\r
926 // sequence doing a single I2C transfer for each command.
\r
928 for(ulIdx = 0; ulIdx < sizeof(g_pucOSRAMInit);
\r
929 ulIdx += g_pucOSRAMInit[ulIdx] + 1)
\r
932 // Send this command.
\r
934 OSRAMWriteFirst(g_pucOSRAMInit[ulIdx + 1]);
\r
935 OSRAMWriteArray(g_pucOSRAMInit + ulIdx + 2, g_pucOSRAMInit[ulIdx] - 2);
\r
936 OSRAMWriteFinal(g_pucOSRAMInit[ulIdx + g_pucOSRAMInit[ulIdx]]);
\r
940 //*****************************************************************************
\r
942 //! Turns off the OLED display.
\r
944 //! This function will turn off the OLED display. This will stop the scanning
\r
945 //! of the panel and turn off the on-chip DC-DC converter, preventing damage to
\r
946 //! the panel due to burn-in (it has similar characters to a CRT in this
\r
949 //! This function is contained in <tt>osram96x16.c</tt>, with
\r
950 //! <tt>osram96x16.h</tt> containing the API definition for use by
\r
955 //*****************************************************************************
\r
957 OSRAMDisplayOff(void)
\r
960 // Turn off the DC-DC converter and the display.
\r
962 OSRAMWriteFirst(0x80);
\r
963 OSRAMWriteByte(0xae);
\r
964 OSRAMWriteByte(0x80);
\r
965 OSRAMWriteByte(0xad);
\r
966 OSRAMWriteByte(0x80);
\r
967 OSRAMWriteFinal(0x8a);
\r
970 //*****************************************************************************
\r
972 // Close the Doxygen group.
\r
975 //*****************************************************************************
\r