This driver is meant for the monochrome LCD display (model no: LS013B4DN04) from Sharp; but it should be easily adaptable to other Sharp displays.
SharpLCD.hpp
- Committer:
- rgrover1
- Date:
- 2014-07-23
- Revision:
- 0:62d7cfac67ca
- Child:
- 1:ffc1d1d55581
File content as of revision 0:62d7cfac67ca:
/* mbed Microcontroller Library * Copyright (c) 2006-2013 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mbed.h" #include "font.h" #ifndef __SHARP_LCD_HPP__ #define __SHARP_LCD_HPP__ /** * This driver is meant for the monochrome LCD display (model * no: LS013B4DN04) from Sharp. * * The LCD has the following pixel dimensions: width=96pixels, * height=96pixels. This is a monochrome display with an inbuilt * memory of 1 bit per pixel. If a pixel-bit is set to one, the * corresponding pixel will show as black. * * The LCD memory is accessible to the micro-controller only through a * serial interface; and <i>only for write operations</i>. It is * necessary for the application to maintain its own frame-buffer * memory in the micro-controller's SRAM (see fb_alloc())---the * application is not restricted to a single framebuffer; if SRAM size * permits, multiple buffers may be employed. In order to update the * LCD, the application first draws (bitmaps or text) into some * framebuffer memory, and then flushes the framebuffer to the LCD * over the serial interface. * * Here's some sample code to drive the LCD display: * * DigitalOut led1(LED1); * SharpLCD lcd(p9, MBED_SPI0); * * uint8_t framebuffer[SharpLCD::SIZEOF_FRAMEBUFFER_FOR_ALLOC]; * * int main(void) * { * SharpLCD::FrameBuffer fb(framebuffer); * * lcd.enableDisplay(); * lcd.clear(); * fb.printString(lookupFontFace("DejaVu Serif", 8), * 20, * 40, * BLACK, * "Rohit"); * lcd.drawFrameBuffer(fb); * * led1 = 1; * while (true) { * wait(0.5); * led1 = !led1; * } * } */ class SharpLCD { public: class FrameBuffer { public: /** * \brief initialize the hardware dependent component of a given * framebuffer; and set it up to show all-white. * * \note This does not update the LCD automatically; it only * initializes a framebuffer. * * \param[in] fb * A memory buffer to initialize. */ FrameBuffer(uint8_t *fb); /** * \brief Copy over a bitmap to a specified location into the framebuffer. * * This is the main work-horse for displaying bitmaps on the LCD. We * only support mono-chrome bitmaps with an encoding of 1 for white * and 0 for black. We have rendering tools to convert a bitmap into * the required encoding. * \note The placement of the target bitmap is limited to the LCD's * boundary--otherwise this routine fails. * * In case you are wondering, 'blit' stands for Block Image Transfer. * * Sample code: * <pre> fb_bitBlit(fb, (const uint8_t *)pixel_data, width, height, 0, // posx 0 // posy ); lcd_drawFrameBuffer(fb); </pre> */ void bitBlit(const uint8_t *bitmap, unsigned int width, /*!< width of the bitmap */ unsigned int height, /*!< height of the bitmap */ unsigned int posx, /*!< x-offset for the * placement of the top-left * corner of the bitmap * w.r.t. the top-left * corner of the screen */ unsigned int posy /*!< y-offset for the * placement of the top-left * corner of the bitmap * w.r.t. the top-left * corner of the screen */ ); /* * \brief Fetch a byte (8-bit pixel sequence) from a given scan-line * in the framebuffer. * * The scan-line is identified by the row; and pixels are grouped into * 8-bit bytes within a row. * * \note This function is declared inline for a faster implementation. * * \param[in] framebuffer * The framebuffer to fetch the byte from. * * \param[in] row * The row index of the scan line. * * \param[in] byteIndex * The pixel-index expressed as a byte-index. */ uint8_t getRowByte(unsigned int row, unsigned int byteIndex) { return buffer[rowColToIndex(row, byteIndex)]; } /* * \brief Set a byte (8-bit pixel sequence) for a given scan-line in * the framebuffer. * * The scan-line is identified by the row; and pixels are grouped into * 8-bit bytes within a row. * * \note This function is declared inline for a faster implementation. * * \param[in] framebuffer * The framebuffer to set the byte into. * * \param[in] row * The row index of the scan line. * * \param[in] byteIndex * The pixel-index expressed as a byte-index. * * \param[in] pixels * The actual 8 pixels to set. */ void setRowByte(unsigned int row, unsigned int byteIndex, uint8_t pixels) { buffer[rowColToIndex(row, byteIndex)] = pixels; } /** * \brief The printf function for the frameBuffer. * * This can be used to render strings in a given * font-face. Internally, it uses fb_bitBlit to bilt the glyphs onto a * framebuffer. Currently, since bitBlit doesn't handle the case where * a bitmap exceeds the framebuffer's boundary, you must be very * careful about the placement of the text string. Later, when * fb_bitBlit is able to handle bitmaps which fall outside the LCD's * boundary, the rendered text may be clipped if it doesn't fit the * frame. * * \param[in] face * The font-face to be used for rendering the text. * * \param[in] baselineX * The X-offset from the left corner of the screen of the starting * pen position; this defines the X-coordinate of the baseline. * * \param[in] baselineY * The Y-offset from the top corner of the screen of the starting * pen position; this defines the Y-coordinate of the baseline. * * \param[in] fgColor * The foreground colour. * * \param[in] string * The text to be rendered. * * Sample code: * <pre> * face = lookupFontFace("DejaVu Serif", 9); * if (face == NULL) { * TRACE_FATAL("failed to find face for DejaVu Serif; 10\n"); * } * fb_printString(fb, * face, * 90, // baselineX * 140, // baselineY * BLACK, // foregroundColor * "Hello Mr. Obama!"); * lcd_drawFrameBuffer(fb); * </pre> */ void printString(const font_face_t *face, unsigned short baselineX, unsigned short baselineY, font_color_t fgColor, const char *string); const uint8_t *getBuffer(void) const { return (buffer); } uint8_t *getBuffer(void) { return (buffer); } private: unsigned rowColToIndex(unsigned row, unsigned col) { return (row * LCD_FRAMEBUFFER_SIZEOF_SCAN_LINE) + LCD_FRAMEBUFFER_SIZEOF_SCAN_LINE_METADATA + col; } private: uint8_t *const buffer; }; public: SharpLCD(PinName _displayEnablePin, PinName mosi, PinName miso_unused, PinName sclk, PinName _unused=NC) : displayEnable(_displayEnablePin), chipSelect(p8), spi(mosi, miso_unused, sclk, _unused) { displayEnable = 0; chipSelect = 0; spi.frequency(1000000); spi.format(8, 0); }; /** * \brief Turn on the LCD's display. * * \note Updates to the LCD's memory won't show up on the display * until the display is enabled through this function. */ void enableDisplay(void); /** * \brief Turn off the LCD's display---i.e. make it go blank. * * \note The LCD will retain its memory even when the display is disabled. * * This is different from re-initializing the LCD's display, since it does * not affect the LCD memory. When the display is re-enabled, the LCD * will show the contents of its memory. */ void disableDisplay(void); /** * \brief Clear the LCD's display * * Write all-white to the LCD's memory. If a frameBuffer is passed in * then it is re-initialized as well; otherwise this function does not * operate on any global frame-buffer and updating any * application-specific frameBuffer is still the application's * responsibility. */ void clear(void); static uint8_t bitReverse8(uint8_t byte) { return (uint8_t)(__RBIT(byte) >> 24); } /** * \brief Update LCD using a given framebuffer. * * The entire contents of the framebuffer will be DMA'd to the LCD; * the calling thread will loose the CPU during the transfer, but * other threads may remain active in that duration. * * \param[in] fb * The frame buffer to send to the LCD hardware. */ void drawFrameBuffer(const FrameBuffer &fb); /** * Toggle the VCOM mode of the LCD; it is recommended to trigger this * periodically. Check the datasheet. */ void toggleVCOM(void); private: /** * Helper function to write out a buffer onto the LCD's SPI channel. */ void writeBuffer(const uint8_t *buffer, unsigned len); public: static const unsigned LCD_WIDTH = 96; ///< Constant defining the LCD's geometry. static const unsigned LCD_HEIGHT = 96; ///< Constant defining the LCD's geometry. static const unsigned LCD_END_OF_DUMMY_SIZE = 2; static const unsigned LCD_FRAMEBUFFER_SIZEOF_SCAN_LINE_METADATA = (1 + /* mode byte in SPI update command */ 1 /* addr byte in SPI update command */); static const unsigned LCD_FRAMEBUFFER_SIZEOF_SCAN_LINE = (LCD_FRAMEBUFFER_SIZEOF_SCAN_LINE_METADATA + (LCD_WIDTH / 8)); static const unsigned SIZEOF_FRAMEBUFFER = (LCD_HEIGHT * LCD_FRAMEBUFFER_SIZEOF_SCAN_LINE); static const unsigned SIZEOF_FRAMEBUFFER_FOR_ALLOC = SIZEOF_FRAMEBUFFER + LCD_END_OF_DUMMY_SIZE; private: /* Constants for the LCD's command protocol */ static const uint8_t M0_FLAG = 0x80; static const uint8_t M1_FLAG = 0x40; static const uint8_t M2_FLAG = 0x20; static const uint8_t DUMMY8 = 0x00; private: DigitalOut displayEnable; DigitalOut chipSelect; SPI spi; }; inline void SharpLCD::enableDisplay(void) { displayEnable = 1; } inline void SharpLCD::disableDisplay(void) { displayEnable = 0; } #endif /* #ifndef __SHARP_LCD_HPP__ */