--- /dev/null
+//*****************************************************************************\r
+//\r
+// osram96x16.c - Driver for the OSRAM 96x16 graphical OLED display.\r
+//\r
+// Copyright (c) 2006 Luminary Micro, Inc. All rights reserved.\r
+//\r
+// Software License Agreement\r
+//\r
+// Luminary Micro, Inc. (LMI) is supplying this software for use solely and\r
+// exclusively on LMI's Stellaris Family of microcontroller products.\r
+//\r
+// The software is owned by LMI and/or its suppliers, and is protected under\r
+// applicable copyright laws. All rights are reserved. Any use in violation\r
+// of the foregoing restrictions may subject the user to criminal sanctions\r
+// under applicable laws, as well as to civil liability for the breach of the\r
+// terms and conditions of this license.\r
+//\r
+// THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED\r
+// OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF\r
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.\r
+// LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR\r
+// CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.\r
+//\r
+// This is part of revision 991 of the Stellaris Driver Library.\r
+//\r
+//*****************************************************************************\r
+\r
+//*****************************************************************************\r
+//\r
+//! \addtogroup ev_lm3s811_api\r
+//! @{\r
+//\r
+//*****************************************************************************\r
+\r
+#include "DriverLib.h"\r
+#include "osram96x16.h"\r
+#define ewarm\r
+//*****************************************************************************\r
+//\r
+// The I2C slave address of the SSD0303 controller on the OLED display.\r
+//\r
+//*****************************************************************************\r
+#define SSD0303_ADDR 0x3d\r
+\r
+//*****************************************************************************\r
+//\r
+// A 5x7 font (in a 6x8 cell, where the sixth column is omitted from this\r
+// table) for displaying text on the OLED display. The data is organized as\r
+// bytes from the left column to the right column, with each byte containing\r
+// the top row in the LSB and the bottom row in the MSB.\r
+//\r
+//*****************************************************************************\r
+static const unsigned char g_pucFont[95][5] =\r
+{\r
+ { 0x00, 0x00, 0x00, 0x00, 0x00 }, // " "\r
+ { 0x00, 0x00, 0x4f, 0x00, 0x00 }, // !\r
+ { 0x00, 0x07, 0x00, 0x07, 0x00 }, // "\r
+ { 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // #\r
+ { 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $\r
+ { 0x23, 0x13, 0x08, 0x64, 0x62 }, // %\r
+ { 0x36, 0x49, 0x55, 0x22, 0x50 }, // &\r
+ { 0x00, 0x05, 0x03, 0x00, 0x00 }, // '\r
+ { 0x00, 0x1c, 0x22, 0x41, 0x00 }, // (\r
+ { 0x00, 0x41, 0x22, 0x1c, 0x00 }, // )\r
+ { 0x14, 0x08, 0x3e, 0x08, 0x14 }, // *\r
+ { 0x08, 0x08, 0x3e, 0x08, 0x08 }, // +\r
+ { 0x00, 0x50, 0x30, 0x00, 0x00 }, // ,\r
+ { 0x08, 0x08, 0x08, 0x08, 0x08 }, // -\r
+ { 0x00, 0x60, 0x60, 0x00, 0x00 }, // .\r
+ { 0x20, 0x10, 0x08, 0x04, 0x02 }, // /\r
+ { 0x3e, 0x51, 0x49, 0x45, 0x3e }, // 0\r
+ { 0x00, 0x42, 0x7f, 0x40, 0x00 }, // 1\r
+ { 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2\r
+ { 0x21, 0x41, 0x45, 0x4b, 0x31 }, // 3\r
+ { 0x18, 0x14, 0x12, 0x7f, 0x10 }, // 4\r
+ { 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5\r
+ { 0x3c, 0x4a, 0x49, 0x49, 0x30 }, // 6\r
+ { 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7\r
+ { 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8\r
+ { 0x06, 0x49, 0x49, 0x29, 0x1e }, // 9\r
+ { 0x00, 0x36, 0x36, 0x00, 0x00 }, // :\r
+ { 0x00, 0x56, 0x36, 0x00, 0x00 }, // ;\r
+ { 0x08, 0x14, 0x22, 0x41, 0x00 }, // <\r
+ { 0x14, 0x14, 0x14, 0x14, 0x14 }, // =\r
+ { 0x00, 0x41, 0x22, 0x14, 0x08 }, // >\r
+ { 0x02, 0x01, 0x51, 0x09, 0x06 }, // ?\r
+ { 0x32, 0x49, 0x79, 0x41, 0x3e }, // @\r
+ { 0x7e, 0x11, 0x11, 0x11, 0x7e }, // A\r
+ { 0x7f, 0x49, 0x49, 0x49, 0x36 }, // B\r
+ { 0x3e, 0x41, 0x41, 0x41, 0x22 }, // C\r
+ { 0x7f, 0x41, 0x41, 0x22, 0x1c }, // D\r
+ { 0x7f, 0x49, 0x49, 0x49, 0x41 }, // E\r
+ { 0x7f, 0x09, 0x09, 0x09, 0x01 }, // F\r
+ { 0x3e, 0x41, 0x49, 0x49, 0x7a }, // G\r
+ { 0x7f, 0x08, 0x08, 0x08, 0x7f }, // H\r
+ { 0x00, 0x41, 0x7f, 0x41, 0x00 }, // I\r
+ { 0x20, 0x40, 0x41, 0x3f, 0x01 }, // J\r
+ { 0x7f, 0x08, 0x14, 0x22, 0x41 }, // K\r
+ { 0x7f, 0x40, 0x40, 0x40, 0x40 }, // L\r
+ { 0x7f, 0x02, 0x0c, 0x02, 0x7f }, // M\r
+ { 0x7f, 0x04, 0x08, 0x10, 0x7f }, // N\r
+ { 0x3e, 0x41, 0x41, 0x41, 0x3e }, // O\r
+ { 0x7f, 0x09, 0x09, 0x09, 0x06 }, // P\r
+ { 0x3e, 0x41, 0x51, 0x21, 0x5e }, // Q\r
+ { 0x7f, 0x09, 0x19, 0x29, 0x46 }, // R\r
+ { 0x46, 0x49, 0x49, 0x49, 0x31 }, // S\r
+ { 0x01, 0x01, 0x7f, 0x01, 0x01 }, // T\r
+ { 0x3f, 0x40, 0x40, 0x40, 0x3f }, // U\r
+ { 0x1f, 0x20, 0x40, 0x20, 0x1f }, // V\r
+ { 0x3f, 0x40, 0x38, 0x40, 0x3f }, // W\r
+ { 0x63, 0x14, 0x08, 0x14, 0x63 }, // X\r
+ { 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y\r
+ { 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z\r
+ { 0x00, 0x7f, 0x41, 0x41, 0x00 }, // [\r
+ { 0x02, 0x04, 0x08, 0x10, 0x20 }, // "\"\r
+ { 0x00, 0x41, 0x41, 0x7f, 0x00 }, // ]\r
+ { 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^\r
+ { 0x40, 0x40, 0x40, 0x40, 0x40 }, // _\r
+ { 0x00, 0x01, 0x02, 0x04, 0x00 }, // `\r
+ { 0x20, 0x54, 0x54, 0x54, 0x78 }, // a\r
+ { 0x7f, 0x48, 0x44, 0x44, 0x38 }, // b\r
+ { 0x38, 0x44, 0x44, 0x44, 0x20 }, // c\r
+ { 0x38, 0x44, 0x44, 0x48, 0x7f }, // d\r
+ { 0x38, 0x54, 0x54, 0x54, 0x18 }, // e\r
+ { 0x08, 0x7e, 0x09, 0x01, 0x02 }, // f\r
+ { 0x0c, 0x52, 0x52, 0x52, 0x3e }, // g\r
+ { 0x7f, 0x08, 0x04, 0x04, 0x78 }, // h\r
+ { 0x00, 0x44, 0x7d, 0x40, 0x00 }, // i\r
+ { 0x20, 0x40, 0x44, 0x3d, 0x00 }, // j\r
+ { 0x7f, 0x10, 0x28, 0x44, 0x00 }, // k\r
+ { 0x00, 0x41, 0x7f, 0x40, 0x00 }, // l\r
+ { 0x7c, 0x04, 0x18, 0x04, 0x78 }, // m\r
+ { 0x7c, 0x08, 0x04, 0x04, 0x78 }, // n\r
+ { 0x38, 0x44, 0x44, 0x44, 0x38 }, // o\r
+ { 0x7c, 0x14, 0x14, 0x14, 0x08 }, // p\r
+ { 0x08, 0x14, 0x14, 0x18, 0x7c }, // q\r
+ { 0x7c, 0x08, 0x04, 0x04, 0x08 }, // r\r
+ { 0x48, 0x54, 0x54, 0x54, 0x20 }, // s\r
+ { 0x04, 0x3f, 0x44, 0x40, 0x20 }, // t\r
+ { 0x3c, 0x40, 0x40, 0x20, 0x7c }, // u\r
+ { 0x1c, 0x20, 0x40, 0x20, 0x1c }, // v\r
+ { 0x3c, 0x40, 0x30, 0x40, 0x3c }, // w\r
+ { 0x44, 0x28, 0x10, 0x28, 0x44 }, // x\r
+ { 0x0c, 0x50, 0x50, 0x50, 0x3c }, // y\r
+ { 0x44, 0x64, 0x54, 0x4c, 0x44 }, // z\r
+ { 0x00, 0x08, 0x36, 0x41, 0x00 }, // {\r
+ { 0x00, 0x00, 0x7f, 0x00, 0x00 }, // |\r
+ { 0x00, 0x41, 0x36, 0x08, 0x00 }, // }\r
+ { 0x02, 0x01, 0x02, 0x04, 0x02 }, // ~\r
+};\r
+\r
+//*****************************************************************************\r
+//\r
+// The sequence of commands used to initialize the SSD0303 controller. Each\r
+// command is described as follows: there is a byte specifying the number of\r
+// bytes in the I2C transfer, followed by that many bytes of command data.\r
+//\r
+//*****************************************************************************\r
+static const unsigned char g_pucOSRAMInit[] =\r
+{\r
+ //\r
+ // Turn off the panel\r
+ //\r
+ 0x04, 0x80, 0xae, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set lower column address\r
+ //\r
+ 0x04, 0x80, 0x04, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set higher column address\r
+ //\r
+ 0x04, 0x80, 0x12, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set contrast control register\r
+ //\r
+ 0x06, 0x80, 0x81, 0x80, 0x2b, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set segment re-map\r
+ //\r
+ 0x04, 0x80, 0xa1, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set display start line\r
+ //\r
+ 0x04, 0x80, 0x40, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set display offset\r
+ //\r
+ 0x06, 0x80, 0xd3, 0x80, 0x00, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set multiplex ratio\r
+ //\r
+ 0x06, 0x80, 0xa8, 0x80, 0x0f, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set the display to normal mode\r
+ //\r
+ 0x04, 0x80, 0xa4, 0x80, 0xe3,\r
+\r
+ //\r
+ // Non-inverted display\r
+ //\r
+ 0x04, 0x80, 0xa6, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set the page address\r
+ //\r
+ 0x04, 0x80, 0xb0, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set COM output scan direction\r
+ //\r
+ 0x04, 0x80, 0xc8, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set display clock divide ratio/oscillator frequency\r
+ //\r
+ 0x06, 0x80, 0xd5, 0x80, 0x72, 0x80, 0xe3,\r
+\r
+ //\r
+ // Enable mono mode\r
+ //\r
+ 0x06, 0x80, 0xd8, 0x80, 0x00, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set pre-charge period\r
+ //\r
+ 0x06, 0x80, 0xd9, 0x80, 0x22, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set COM pins hardware configuration\r
+ //\r
+ 0x06, 0x80, 0xda, 0x80, 0x12, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set VCOM deslect level\r
+ //\r
+ 0x06, 0x80, 0xdb, 0x80, 0x0f, 0x80, 0xe3,\r
+\r
+ //\r
+ // Set DC-DC on\r
+ //\r
+ 0x06, 0x80, 0xad, 0x80, 0x8b, 0x80, 0xe3,\r
+\r
+ //\r
+ // Turn on the panel\r
+ //\r
+ 0x04, 0x80, 0xaf, 0x80, 0xe3,\r
+};\r
+\r
+//*****************************************************************************\r
+//\r
+// The inter-byte delay required by the SSD0303 OLED controller.\r
+//\r
+//*****************************************************************************\r
+static unsigned long g_ulDelay;\r
+\r
+//*****************************************************************************\r
+//\r
+//! \internal\r
+//!\r
+//! Provide a small delay.\r
+//!\r
+//! \param ulCount is the number of delay loop iterations to perform.\r
+//!\r
+//! Since the SSD0303 controller needs a delay between bytes written to it over\r
+//! the I2C bus, this function provides a means of generating that delay. It\r
+//! is written in assembly to keep the delay consistent across tool chains,\r
+//! avoiding the need to tune the delay based on the tool chain in use.\r
+//!\r
+//! \return None.\r
+//\r
+//*****************************************************************************\r
+#if defined(ewarm)\r
+static void\r
+OSRAMDelay(unsigned long ulCount)\r
+{\r
+ __asm(" subs r0, #1\n"\r
+ " bne OSRAMDelay\n"\r
+ " bx lr");\r
+}\r
+#endif\r
+#if defined(gcc)\r
+static void __attribute__((naked))\r
+OSRAMDelay(unsigned long ulCount)\r
+{\r
+ __asm(" subs r0, #1\n"\r
+ " bne OSRAMDelay\n"\r
+ " bx lr");\r
+}\r
+#endif\r
+#if defined(rvmdk) || defined(__ARMCC_VERSION)\r
+__asm void\r
+OSRAMDelay(unsigned long ulCount)\r
+{\r
+ subs r0, #1;\r
+ bne OSRAMDelay;\r
+ bx lr;\r
+}\r
+#endif\r
+\r
+//*****************************************************************************\r
+//\r
+//! \internal\r
+//!\r
+//! Start a transfer to the SSD0303 controller.\r
+//!\r
+//! \param ucChar is the first byte to be written to the controller.\r
+//!\r
+//! This function will start a transfer to the SSD0303 controller via the I2C\r
+//! bus.\r
+//!\r
+//! The data is written in a polled fashion; this function will not return\r
+//! until the byte has been written to the controller.\r
+//!\r
+//! \return None.\r
+//\r
+//*****************************************************************************\r
+static void\r
+OSRAMWriteFirst(unsigned char ucChar)\r
+{\r
+ //\r
+ // Set the slave address.\r
+ //\r
+ I2CMasterSlaveAddrSet(I2C_MASTER_BASE, SSD0303_ADDR, false);\r
+\r
+ //\r
+ // Write the first byte to the controller.\r
+ //\r
+ I2CMasterDataPut(I2C_MASTER_BASE, ucChar);\r
+\r
+ //\r
+ // Start the transfer.\r
+ //\r
+ I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);\r
+}\r
+\r
+//*****************************************************************************\r
+//\r
+//! \internal\r
+//!\r
+//! Write a byte to the SSD0303 controller.\r
+//!\r
+//! \param ucChar is the byte to be transmitted to the controller.\r
+//!\r
+//! This function continues a transfer to the SSD0303 controller by writing\r
+//! another byte over the I2C bus. This must only be called after calling\r
+//! OSRAMWriteFirst(), but before calling OSRAMWriteFinal().\r
+//!\r
+//! The data is written in a polled faashion; this function will not return\r
+//! until the byte has been written to the controller.\r
+//!\r
+//! \return None.\r
+//\r
+//*****************************************************************************\r
+static void\r
+OSRAMWriteByte(unsigned char ucChar)\r
+{\r
+ //\r
+ // Wait until the current byte has been transferred.\r
+ //\r
+ while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)\r
+ {\r
+ }\r
+\r
+ //\r
+ // Provide the required inter-byte delay.\r
+ //\r
+ OSRAMDelay(g_ulDelay);\r
+\r
+ //\r
+ // Write the next byte to the controller.\r
+ //\r
+ I2CMasterDataPut(I2C_MASTER_BASE, ucChar);\r
+\r
+ //\r
+ // Continue the transfer.\r
+ //\r
+ I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);\r
+}\r
+\r
+//*****************************************************************************\r
+//\r
+//! \internal\r
+//!\r
+//! Write a sequence of bytes to the SSD0303 controller.\r
+//!\r
+//! This function continues a transfer to the SSD0303 controller by writing a\r
+//! sequence of bytes over the I2C bus. This must only be called after calling\r
+//! OSRAMWriteFirst(), but before calling OSRAMWriteFinal().\r
+//!\r
+//! The data is written in a polled fashion; this function will not return\r
+//! until the entire byte sequence has been written to the controller.\r
+//!\r
+//! \return None.\r
+//\r
+//*****************************************************************************\r
+static void\r
+OSRAMWriteArray(const unsigned char *pucBuffer, unsigned long ulCount)\r
+{\r
+ //\r
+ // Loop while there are more bytes left to be transferred.\r
+ //\r
+ while(ulCount != 0)\r
+ {\r
+ //\r
+ // Wait until the current byte has been transferred.\r
+ //\r
+ while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)\r
+ {\r
+ }\r
+\r
+ //\r
+ // Provide the required inter-byte delay.\r
+ //\r
+ OSRAMDelay(g_ulDelay);\r
+\r
+ //\r
+ // Write the next byte to the controller.\r
+ //\r
+ I2CMasterDataPut(I2C_MASTER_BASE, *pucBuffer++);\r
+ ulCount--;\r
+\r
+ //\r
+ // Continue the transfer.\r
+ //\r
+ I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);\r
+ }\r
+}\r
+\r
+//*****************************************************************************\r
+//\r
+//! \internal\r
+//!\r
+//! Finish a transfer to the SSD0303 controller.\r
+//!\r
+//! \param ucChar is the final byte to be written to the controller.\r
+//!\r
+//! This function will finish a transfer to the SSD0303 controller via the I2C\r
+//! bus. This must only be called after calling OSRAMWriteFirst().\r
+//!\r
+//! The data is written in a polled fashion; this function will not return\r
+//! until the byte has been written to the controller.\r
+//!\r
+//! \return None.\r
+//\r
+//*****************************************************************************\r
+static void\r
+OSRAMWriteFinal(unsigned char ucChar)\r
+{\r
+ //\r
+ // Wait until the current byte has been transferred.\r
+ //\r
+ while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)\r
+ {\r
+ }\r
+\r
+ //\r
+ // Provide the required inter-byte delay.\r
+ //\r
+ OSRAMDelay(g_ulDelay);\r
+\r
+ //\r
+ // Write the final byte to the controller.\r
+ //\r
+ I2CMasterDataPut(I2C_MASTER_BASE, ucChar);\r
+\r
+ //\r
+ // Finish the transfer.\r
+ //\r
+ I2CMasterControl(I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);\r
+\r
+ //\r
+ // Wait until the final byte has been transferred.\r
+ //\r
+ while(I2CMasterIntStatus(I2C_MASTER_BASE, false) == 0)\r
+ {\r
+ }\r
+\r
+ //\r
+ // Provide the required inter-byte delay.\r
+ //\r
+ OSRAMDelay(g_ulDelay);\r
+}\r
+\r
+//*****************************************************************************\r
+//\r
+//! Clears the OLED display.\r
+//!\r
+//! This function will clear the display. All pixels in the display will be\r
+//! turned off.\r
+//!\r
+//! This function is contained in <tt>osram96x16.c</tt>, with\r
+//! <tt>osram96x16.h</tt> containing the API definition for use by\r
+//! applications.\r
+//!\r
+//! \return None.\r
+//\r
+//*****************************************************************************\r
+void\r
+OSRAMClear(void)\r
+{\r
+ static const unsigned char pucRow1[] =\r
+ {\r
+ 0xb0, 0x80, 0x04, 0x80, 0x12, 0x40\r
+ };\r
+ static const unsigned char pucRow2[] =\r
+ {\r
+ 0xb1, 0x80, 0x04, 0x80, 0x12, 0x40\r
+ };\r
+ unsigned long ulIdx;\r
+\r
+ //\r
+ // Move the display cursor to the first column of the first row.\r
+ //\r
+ OSRAMWriteFirst(0x80);\r
+ OSRAMWriteArray(pucRow1, sizeof(pucRow1));\r
+\r
+ //\r
+ // Fill this row with zeros.\r
+ //\r
+ for(ulIdx = 0; ulIdx < 95; ulIdx++)\r
+ {\r
+ OSRAMWriteByte(0x00);\r
+ }\r
+ OSRAMWriteFinal(0x00);\r
+\r
+ //\r
+ // Move the display cursor to the first column of the second row.\r
+ //\r
+ OSRAMWriteFirst(0x80);\r
+ OSRAMWriteArray(pucRow2, sizeof(pucRow2));\r
+\r
+ //\r
+ // Fill this row with zeros.\r
+ //\r
+ for(ulIdx = 0; ulIdx < 95; ulIdx++)\r
+ {\r
+ OSRAMWriteByte(0x00);\r
+ }\r
+ OSRAMWriteFinal(0x00);\r
+}\r
+\r
+//*****************************************************************************\r
+//\r
+//! Displays a string on the OLED display.\r
+//!\r
+//! \param pcStr is a pointer to the string to display.\r
+//! \param ulX is the horizontal position to display the string, specified in\r
+//! columns from the left edge of the display.\r
+//! \param ulY is the vertical position to display the string, specified in\r
+//! eight scan line blocks from the top of the display (i.e. only 0 and 1 are\r
+//! valid).\r
+//!\r
+//! This function will draw a string on the display. Only the ASCII characters\r
+//! between 32 (space) and 126 (tilde) are supported; other characters will\r
+//! result in random data being draw on the display (based on whatever appears\r
+//! before/after the font in memory). The font is mono-spaced, so characters\r
+//! such as "i" and "l" have more white space around them than characters such\r
+//! as "m" or "w".\r
+//!\r
+//! If the drawing of the string reaches the right edge of the display, no more\r
+//! characters will be drawn. Therefore, special care is not required to avoid\r
+//! supplying a string that is "too long" to display.\r
+//!\r
+//! This function is contained in <tt>osram96x16.c</tt>, with\r
+//! <tt>osram96x16.h</tt> containing the API definition for use by\r
+//! applications.\r
+//!\r
+//! \return None.\r
+//\r
+//*****************************************************************************\r
+void\r
+OSRAMStringDraw(const char *pcStr, unsigned long ulX, unsigned long ulY)\r
+{\r
+ //\r
+ // Check the arguments.\r
+ //\r
+ ASSERT(ulX < 96);\r
+ ASSERT(ulY < 2);\r
+\r
+ //\r
+ // Move the display cursor to the requested position on the display.\r
+ //\r
+ OSRAMWriteFirst(0x80);\r
+ OSRAMWriteByte((ulY == 0) ? 0xb0 : 0xb1);\r
+ OSRAMWriteByte(0x80);\r
+ OSRAMWriteByte((ulX + 36) & 0x0f);\r
+ OSRAMWriteByte(0x80);\r
+ OSRAMWriteByte(0x10 | (((ulX + 36) >> 4) & 0x0f));\r
+ OSRAMWriteByte(0x40);\r
+\r
+ //\r
+ // Loop while there are more characters in the string.\r
+ //\r
+ while(*pcStr != 0)\r
+ {\r
+ //\r
+ // See if there is enough space on the display for this entire\r
+ // character.\r
+ //\r
+ if(ulX <= 90)\r
+ {\r
+ //\r
+ // Write the contents of this character to the display.\r
+ //\r
+ OSRAMWriteArray(g_pucFont[*pcStr - ' '], 5);\r
+\r
+ //\r
+ // See if this is the last character to display (either because the\r
+ // right edge has been reached or because there are no more\r
+ // characters).\r
+ //\r
+ if((ulX == 90) || (pcStr[1] == 0))\r
+ {\r
+ //\r
+ // Write the final column of the display.\r
+ //\r
+ OSRAMWriteFinal(0x00);\r
+\r
+ //\r
+ // The string has been displayed.\r
+ //\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Write the inter-character padding column.\r
+ //\r
+ OSRAMWriteByte(0x00);\r
+ }\r
+ else\r
+ {\r
+ //\r
+ // Write the portion of the character that will fit onto the\r
+ // display.\r
+ //\r
+ OSRAMWriteArray(g_pucFont[*pcStr - ' '], 95 - ulX);\r
+ OSRAMWriteFinal(g_pucFont[*pcStr - ' '][95 - ulX]);\r
+\r
+ //\r
+ // The string has been displayed.\r
+ //\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Advance to the next character.\r
+ //\r
+ pcStr++;\r
+\r
+ //\r
+ // Increment the X coordinate by the six columns that were just\r
+ // written.\r
+ //\r
+ ulX += 6;\r
+ }\r
+}\r
+\r
+//*****************************************************************************\r
+//\r
+//! Displays an image on the OLED display.\r
+//!\r
+//! \param pucImage is a pointer to the image data.\r
+//! \param ulX is the horizontal position to display this image, specified in\r
+//! columns from the left edge of the display.\r
+//! \param ulY is the vertical position to display this image, specified in\r
+//! eight scan line blocks from the top of the display (i.e. only 0 and 1 are\r
+//! valid).\r
+//! \param ulWidth is the width of the image, specified in columns.\r
+//! \param ulHeight is the height of the image, specified in eight row blocks\r
+//! (i.e. only 1 and 2 are valid).\r
+//!\r
+//! This function will display a bitmap graphic on the display. The image to\r
+//! be displayed must be a multiple of eight scan lines high (i.e. one row) and\r
+//! will be drawn at a vertical position that is a multiple of eight scan lines\r
+//! (i.e. scan line zero or scan line eight, corresponding to row zero or row\r
+//! one).\r
+//!\r
+//! The image data is organized with the first row of image data appearing left\r
+//! to right, followed immediately by the second row of image data. Each byte\r
+//! contains the data for the eight scan lines of the column, with the top scan\r
+//! line being in the least significant bit of the byte and the bottom scan\r
+//! line being in the most significant bit of the byte.\r
+//!\r
+//! For example, an image four columns wide and sixteen scan lines tall would\r
+//! be arranged as follows (showing how the eight bytes of the image would\r
+//! appear on the display):\r
+//!\r
+//! \verbatim\r
+//! +-------+ +-------+ +-------+ +-------+\r
+//! | | 0 | | | 0 | | | 0 | | | 0 |\r
+//! | B | 1 | | B | 1 | | B | 1 | | B | 1 |\r
+//! | y | 2 | | y | 2 | | y | 2 | | y | 2 |\r
+//! | t | 3 | | t | 3 | | t | 3 | | t | 3 |\r
+//! | e | 4 | | e | 4 | | e | 4 | | e | 4 |\r
+//! | | 5 | | | 5 | | | 5 | | | 5 |\r
+//! | 0 | 6 | | 1 | 6 | | 2 | 6 | | 3 | 6 |\r
+//! | | 7 | | | 7 | | | 7 | | | 7 |\r
+//! +-------+ +-------+ +-------+ +-------+\r
+//!\r
+//! +-------+ +-------+ +-------+ +-------+\r
+//! | | 0 | | | 0 | | | 0 | | | 0 |\r
+//! | B | 1 | | B | 1 | | B | 1 | | B | 1 |\r
+//! | y | 2 | | y | 2 | | y | 2 | | y | 2 |\r
+//! | t | 3 | | t | 3 | | t | 3 | | t | 3 |\r
+//! | e | 4 | | e | 4 | | e | 4 | | e | 4 |\r
+//! | | 5 | | | 5 | | | 5 | | | 5 |\r
+//! | 4 | 6 | | 5 | 6 | | 6 | 6 | | 7 | 6 |\r
+//! | | 7 | | | 7 | | | 7 | | | 7 |\r
+//! +-------+ +-------+ +-------+ +-------+\r
+//! \endverbatim\r
+//!\r
+//! This function is contained in <tt>osram96x16.c</tt>, with\r
+//! <tt>osram96x16.h</tt> containing the API definition for use by\r
+//! applications.\r
+//!\r
+//! \return None.\r
+//\r
+//*****************************************************************************\r
+void\r
+OSRAMImageDraw(const unsigned char *pucImage, unsigned long ulX,\r
+ unsigned long ulY, unsigned long ulWidth,\r
+ unsigned long ulHeight)\r
+{\r
+ //\r
+ // Check the arguments.\r
+ //\r
+ ASSERT(ulX < 96);\r
+ ASSERT(ulY < 2);\r
+ ASSERT((ulX + ulWidth) <= 96);\r
+ ASSERT((ulY + ulHeight) <= 2);\r
+\r
+ //\r
+ // The first 36 columns of the LCD buffer are not displayed, so increment\r
+ // the X coorddinate by 36 to account for the non-displayed frame buffer\r
+ // memory.\r
+ //\r
+ ulX += 36;\r
+\r
+ //\r
+ // Loop while there are more rows to display.\r
+ //\r
+ while(ulHeight--)\r
+ {\r
+ //\r
+ // Write the starting address within this row.\r
+ //\r
+ OSRAMWriteFirst(0x80);\r
+ OSRAMWriteByte((ulY == 0) ? 0xb0 : 0xb1);\r
+ OSRAMWriteByte(0x80);\r
+ OSRAMWriteByte(ulX & 0x0f);\r
+ OSRAMWriteByte(0x80);\r
+ OSRAMWriteByte(0x10 | ((ulX >> 4) & 0x0f));\r
+ OSRAMWriteByte(0x40);\r
+\r
+ //\r
+ // Write this row of image data.\r
+ //\r
+ OSRAMWriteArray(pucImage, ulWidth - 1);\r
+ OSRAMWriteFinal(pucImage[ulWidth - 1]);\r
+\r
+ //\r
+ // Advance to the next row of the image.\r
+ //\r
+ pucImage += ulWidth;\r
+ ulY++;\r
+ }\r
+}\r
+\r
+//*****************************************************************************\r
+//\r
+//! Initialize the OLED display.\r
+//!\r
+//! \param bFast is a boolean that is \e true if the I2C interface should be\r
+//! run at 400 kbps and \e false if it should be run at 100 kbps.\r
+//!\r
+//! This function initializes the I2C interface to the OLED display and\r
+//! configures the SSD0303 controller on the panel.\r
+//!\r
+//! This function is contained in <tt>osram96x16.c</tt>, with\r
+//! <tt>osram96x16.h</tt> containing the API definition for use by\r
+//! applications.\r
+//!\r
+//! \return None.\r
+//\r
+//*****************************************************************************\r
+void\r
+OSRAMInit(tBoolean bFast)\r
+{\r
+ unsigned long ulIdx;\r
+\r
+ //\r
+ // Enable the I2C and GPIO port B blocks as they are needed by this driver.\r
+ //\r
+ SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C);\r
+ SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);\r
+\r
+ //\r
+ // Configure the I2C SCL and SDA pins for I2C operation.\r
+ //\r
+ GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);\r
+\r
+ //\r
+ // Initialize the I2C master.\r
+ //\r
+ I2CMasterInit(I2C_MASTER_BASE, bFast);\r
+\r
+ //\r
+ // Compute the inter-byte delay for the SSD0303 controller. This delay is\r
+ // dependent upon the I2C bus clock rate; the slower the clock the longer\r
+ // the delay required.\r
+ //\r
+ // The derivation of this formula is based on a measured delay of\r
+ // OSRAMDelay(1700) for a 100 kHz I2C bus with the CPU running at 50 MHz\r
+ // (referred to as C). To scale this to the delay for a different CPU\r
+ // speed (since this is just a CPU-based delay loop) is:\r
+ //\r
+ // f(CPU)\r
+ // C * ----------\r
+ // 50,000,000\r
+ //\r
+ // To then scale this to the actual I2C rate (since it won't always be\r
+ // precisely 100 kHz):\r
+ //\r
+ // f(CPU) 100,000\r
+ // C * ---------- * -------\r
+ // 50,000,000 f(I2C)\r
+ //\r
+ // This equation will give the inter-byte delay required for any\r
+ // configuration of the I2C master. But, as arranged it is impossible to\r
+ // directly compute in 32-bit arithmetic (without loosing a lot of\r
+ // accuracy). So, the equation is simplified.\r
+ //\r
+ // Since f(I2C) is generated by dividing down from f(CPU), replace it with\r
+ // the equivalent (where TPR is the value programmed into the Master Timer\r
+ // Period Register of the I2C master, with the 1 added back):\r
+ //\r
+ // 100,000\r
+ // f(CPU) -------\r
+ // C * ---------- * f(CPU)\r
+ // 50,000,000 ------------\r
+ // 2 * 10 * TPR\r
+ //\r
+ // Inverting the dividend in the last term:\r
+ //\r
+ // f(CPU) 100,000 * 2 * 10 * TPR\r
+ // C * ---------- * ----------------------\r
+ // 50,000,000 f(CPU)\r
+ //\r
+ // The f(CPU) now cancels out.\r
+ //\r
+ // 100,000 * 2 * 10 * TPR\r
+ // C * ----------------------\r
+ // 50,000,000\r
+ //\r
+ // Since there are no clock frequencies left in the equation, this equation\r
+ // also works for 400 kHz bus operation as well, since the 100,000 in the\r
+ // numerator becomes 400,000 but C is 1/4, which cancel out each other.\r
+ // Reducing the constants gives:\r
+ //\r
+ // TPR TPR TPR\r
+ // C * --- = 1700 * --- = 340 * --- = 68 * TPR\r
+ // 25 25 5\r
+ //\r
+ // Note that the constant C is actually a bit larger than it needs to be in\r
+ // order to provide some safety margin.\r
+ //\r
+ g_ulDelay = 68 * (HWREG(I2C_MASTER_BASE + I2C_MASTER_O_TPR) + 1);\r
+\r
+ //\r
+ // Initialize the SSD0303 controller. Loop through the initialization\r
+ // sequence doing a single I2C transfer for each command.\r
+ //\r
+ for(ulIdx = 0; ulIdx < sizeof(g_pucOSRAMInit);\r
+ ulIdx += g_pucOSRAMInit[ulIdx] + 1)\r
+ {\r
+ //\r
+ // Send this command.\r
+ //\r
+ OSRAMWriteFirst(g_pucOSRAMInit[ulIdx + 1]);\r
+ OSRAMWriteArray(g_pucOSRAMInit + ulIdx + 2, g_pucOSRAMInit[ulIdx] - 2);\r
+ OSRAMWriteFinal(g_pucOSRAMInit[ulIdx + g_pucOSRAMInit[ulIdx]]);\r
+ }\r
+\r
+ //\r
+ // Clear the frame buffer.\r
+ //\r
+ OSRAMClear();\r
+}\r
+\r
+//*****************************************************************************\r
+//\r
+//! Turns on the OLED display.\r
+//!\r
+//! This function will turn on the OLED display, causing it to display the\r
+//! contents of its internal frame buffer.\r
+//!\r
+//! This function is contained in <tt>osram96x16.c</tt>, with\r
+//! <tt>osram96x16.h</tt> containing the API definition for use by\r
+//! applications.\r
+//!\r
+//! \return None.\r
+//\r
+//*****************************************************************************\r
+void\r
+OSRAMDisplayOn(void)\r
+{\r
+ unsigned long ulIdx;\r
+\r
+ //\r
+ // Re-initialize the SSD0303 controller. Loop through the initialization\r
+ // sequence doing a single I2C transfer for each command.\r
+ //\r
+ for(ulIdx = 0; ulIdx < sizeof(g_pucOSRAMInit);\r
+ ulIdx += g_pucOSRAMInit[ulIdx] + 1)\r
+ {\r
+ //\r
+ // Send this command.\r
+ //\r
+ OSRAMWriteFirst(g_pucOSRAMInit[ulIdx + 1]);\r
+ OSRAMWriteArray(g_pucOSRAMInit + ulIdx + 2, g_pucOSRAMInit[ulIdx] - 2);\r
+ OSRAMWriteFinal(g_pucOSRAMInit[ulIdx + g_pucOSRAMInit[ulIdx]]);\r
+ }\r
+}\r
+\r
+//*****************************************************************************\r
+//\r
+//! Turns off the OLED display.\r
+//!\r
+//! This function will turn off the OLED display. This will stop the scanning\r
+//! of the panel and turn off the on-chip DC-DC converter, preventing damage to\r
+//! the panel due to burn-in (it has similar characters to a CRT in this\r
+//! respect).\r
+//!\r
+//! This function is contained in <tt>osram96x16.c</tt>, with\r
+//! <tt>osram96x16.h</tt> containing the API definition for use by\r
+//! applications.\r
+//!\r
+//! \return None.\r
+//\r
+//*****************************************************************************\r
+void\r
+OSRAMDisplayOff(void)\r
+{\r
+ //\r
+ // Turn off the DC-DC converter and the display.\r
+ //\r
+ OSRAMWriteFirst(0x80);\r
+ OSRAMWriteByte(0xae);\r
+ OSRAMWriteByte(0x80);\r
+ OSRAMWriteByte(0xad);\r
+ OSRAMWriteByte(0x80);\r
+ OSRAMWriteFinal(0x8a);\r
+}\r
+\r
+//*****************************************************************************\r
+//\r
+// Close the Doxygen group.\r
+//! @}\r
+//\r
+//*****************************************************************************\r