From 7451bef41208dc451f6e34261e23d336a52de4f0 Mon Sep 17 00:00:00 2001 From: Kevin Townsend Date: Fri, 7 Oct 2011 00:19:24 +0200 Subject: [PATCH 1/1] First draft --- drivers/lcd/bitmap/sharpmem/sharpmem.c | 384 +++++++++++++++++++++++++ drivers/lcd/bitmap/sharpmem/sharpmem.h | 95 ++++++ 2 files changed, 479 insertions(+) create mode 100644 drivers/lcd/bitmap/sharpmem/sharpmem.c create mode 100644 drivers/lcd/bitmap/sharpmem/sharpmem.h diff --git a/drivers/lcd/bitmap/sharpmem/sharpmem.c b/drivers/lcd/bitmap/sharpmem/sharpmem.c new file mode 100644 index 0000000..dd829e2 --- /dev/null +++ b/drivers/lcd/bitmap/sharpmem/sharpmem.c @@ -0,0 +1,384 @@ +/**************************************************************************/ +/*! + @file sharpmem.c + @author K. Townsend (microBuilder.eu) + + @section DESCRIPTION + + Driver for Sharp Memory Displays. + + This driver uses a bit-banged 3-pin SPI interface. For the SPI + interface, the select line (CS) is active high, and the clock + line (SCK) is active high. + + Note: The LCD expects the address and data + bits to arrive LSB, though the M3 shifts the bits out MSB so they + need to be switched in SW first. + + @section EXAMPLE + @code + + sharpmemInit(); + sharpmemEnable(true); + + // Render some text and a line into the image buffer + uint32_t i; + sharpmemDrawString(1, 10, "5x8 System", Font_System5x8); + sharpmemDrawString(1, 20, "7x8 System", Font_System7x8); + for (i = 0; i < 96; i++) + { + sharpmemDrawPixel(i, i); + } + + while(1) + { + // Screen must be refreshed at least once per second + sharpmemRefresh(); + systickDelay(1000); + } + + @endcode + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2010, microBuilder SARL + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#include + +#include "sharpmem.h" + +#include "core/systick/systick.h" +#include "core/gpio/gpio.h" +#include "drivers/lcd/smallfonts.h" + +#define TOGGLE_VCOM do { _sharpmem_vcom = _sharpmem_vcom ? 0x00 : SHARPMEM_BIT_VCOM; } while(0); + +static uint8_t _sharpmembuffer[(SHARPMEM_LCDWIDTH * SHARPMEM_LCDHEIGHT) / 8]; +static volatile uint8_t _sharpmem_vcom = SHARPMEM_BIT_VCOM; + +/*************************************************/ +/* Private Methods */ +/*************************************************/ + +/**************************************************************************/ +/*! + @brief Swaps the bit order from MSB to LSB, since the LCD expects LSB, + but the M3 shifts bits out MSB. +*/ +/**************************************************************************/ +uint8_t sharpmemSwap(uint8_t data) +{ + uint8_t out = 0; + if (data) + { + if(data & 0x01) out |= 0x80; + if(data & 0x02) out |= 0x40; + if(data & 0x04) out |= 0x20; + if(data & 0x08) out |= 0x10; + if(data & 0x10) out |= 0x08; + if(data & 0x20) out |= 0x04; + if(data & 0x40) out |= 0x02; + if(data & 0x80) out |= 0x01; + } + + return out; +} + +/*************************************************/ +void sharpmemSendByte(uint8_t data) +{ + uint8_t i = 0; + + // Make sure clock pin starts low + CLR_SCLK; + + // Write from MSB to LSB + // LCD expects LSB first + for (i=0; i<8; i++) + { + if (data & 0x80) + { + SET_MOSI; + } + else + { + CLR_MOSI; + } + // Clock is active high + SET_SCLK; + data <<= 1; + __asm volatile("nop"); + CLR_SCLK; + } +} + +/**************************************************************************/ +/*! + @brief Draws a single graphic character using the supplied font +*/ +/**************************************************************************/ +static void sharpmemDrawChar(uint16_t x, uint16_t y, const char c, struct FONT_DEF font) +{ + uint8_t col, column[font.u8Width]; + + // Check if the requested character is available + if ((c >= font.u8FirstChar) && (c <= font.u8LastChar)) + { + // Retrieve appropriate columns from font data + for (col = 0; col < font.u8Width; col++) + { + column[col] = font.au8FontTable[((c - 32) * font.u8Width) + col]; // Get first column of appropriate character + } + } + else + { + // Requested character is not available in this font ... send a space instead + for (col = 0; col < font.u8Width; col++) + { + column[col] = 0xFF; // Send solid space + } + } + + // Render each column + uint16_t xoffset, yoffset; + for (xoffset = 0; xoffset < font.u8Width; xoffset++) + { + for (yoffset = 0; yoffset < (font.u8Height + 1); yoffset++) + { + uint8_t bit = 0x00; + bit = (column[xoffset] << (8 - (yoffset + 1))); // Shift current row bit left + bit = (bit >> 7); // Shift current row but right (results in 0x01 for black, and 0x00 for white) + if (bit) + { + sharpmemDrawPixel(x + xoffset, y + yoffset); + } + } + } +} + +/*************************************************/ +/* Public Methods */ +/*************************************************/ + +/*************************************************/ +void sharpmemInit(void) +{ + // Set control pins to output + gpioSetDir(SHARPMEM_PORT, SHARPMEM_SCLK_PIN, 1); + gpioSetDir(SHARPMEM_PORT, SHARPMEM_MOSI_PIN, 1); + gpioSetDir(SHARPMEM_PORT, SHARPMEM_CS_PIN, 1); + gpioSetDir(SHARPMEM_PORT, SHARPMEM_DISP_PIN, 1); + + // Set pins to default state + CLR_SCLK; + CLR_MOSI; + CLR_CS; + CLR_DISP; + + // Set the vcom bit to a defined state + _sharpmem_vcom = SHARPMEM_BIT_VCOM; + + // Clear the display and turn it off by default + sharpmemClearScreen(); + sharpmemEnable(false); +} + +/**************************************************************************/ +/*! + @brief Turns the display on or off (memory is retained even when the + display is off) + + @param[in] enabled + Whether the display should be on (TRUE/1) or off (FALSE/0) +*/ +/**************************************************************************/ +void sharpmemEnable(bool enable) +{ + if (enable) + { + SET_DISP; + } + else + { + CLR_DISP; + } +} + +/**************************************************************************/ +/*! + @brief Draws a single pixel in image buffer + + @param[in] x + The x position (0 based) + @param[in] y + The y position (0 based) +*/ +/**************************************************************************/ +void sharpmemDrawPixel(uint16_t x, uint16_t y) +{ + if ((x >= SHARPMEM_LCDWIDTH) || (y >= SHARPMEM_LCDHEIGHT)) + return; + + _sharpmembuffer[(y*SHARPMEM_LCDWIDTH + x) /8] |= (1 << x % 8); +} + +/**************************************************************************/ +/*! + @brief Clears a single pixel in image buffer + + @param[in] x + The x position (0 based) + @param[in] y + The y position (0 based) +*/ +/**************************************************************************/ +void sharpmemClearPixel(uint16_t x, uint16_t y) +{ + if ((x >= SHARPMEM_LCDWIDTH) || (y >= SHARPMEM_LCDHEIGHT)) + return; + + _sharpmembuffer[(y*SHARPMEM_LCDWIDTH + x) /8] &= ~(1 << x % 8); +} + +/**************************************************************************/ +/*! + @brief Gets the value (1 or 0) of the specified pixel from the buffer + + @param[in] x + The x position (0 based) + @param[in] y + The y position (0 based) + + @return 1 if the pixel is enabled, 0 if disabled +*/ +/**************************************************************************/ +uint8_t sharpmemGetPixel(uint16_t x, uint16_t y) +{ + if ((x >=SHARPMEM_LCDWIDTH) || (y >=SHARPMEM_LCDHEIGHT)) return 0; + return _sharpmembuffer[(y*SHARPMEM_LCDWIDTH + x) /8] & (1 << x % 8) ? 1 : 0; +} + +/**************************************************************************/ +/*! + @brief Clears the screen +*/ +/**************************************************************************/ +void sharpmemClearScreen() +{ + memset(_sharpmembuffer, 0x00, (SHARPMEM_LCDWIDTH * SHARPMEM_LCDHEIGHT) / 8); + // Send the clear screen command rather than doing a HW refresh (quicker) + SET_CS; + sharpmemSendByte(_sharpmem_vcom | SHARPMEM_BIT_CLEAR); + sharpmemSendByte(0x00); + TOGGLE_VCOM; + CLR_CS; +} + +/**************************************************************************/ +/*! + @brief Renders the contents of the pixel buffer on the LCD +*/ +/**************************************************************************/ +void sharpmemRefresh(void) +{ + uint16_t i, totalbytes, currentline, oldline; + totalbytes = (SHARPMEM_LCDWIDTH * SHARPMEM_LCDHEIGHT) / 8; + + // Send the write command + SET_CS; + sharpmemSendByte(SHARPMEM_BIT_WRITECMD | _sharpmem_vcom); + TOGGLE_VCOM; + + // Send the address for line 1 + oldline = currentline = 1; + sharpmemSendByte(sharpmemSwap(currentline)); + + // Send image buffer + for (i=0; i