This driver is meant for the monochrome LCD display (model no: LS013B4DN04) from Sharp; but it should be easily adaptable to other Sharp displays.

Dependents:   sharpLCD-demo

Revision:
0:62d7cfac67ca
Child:
1:ffc1d1d55581
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SharpLCD.hpp	Wed Jul 23 10:40:35 2014 +0000
@@ -0,0 +1,345 @@
+/* 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__ */