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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SharpLCD.hpp Source File

SharpLCD.hpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "mbed.h"
00018 #include "core_cmInstr.h"
00019 #include "font.h"
00020 
00021 #ifndef __SHARP_LCD_HPP__
00022 #define __SHARP_LCD_HPP__
00023 
00024 /**
00025  * This driver is meant for the monochrome LCD display (model
00026  * no: LS013B4DN04) from Sharp.
00027  *
00028  * The LCD has the following pixel dimensions: width=96pixels,
00029  * height=96pixels. This is a monochrome display with an inbuilt
00030  * memory of 1 bit per pixel. If a pixel-bit is set to one, the
00031  * corresponding pixel will show as black.
00032  *
00033  * The LCD memory is accessible to the micro-controller only through a
00034  * serial interface; and <i>only for write operations</i>. It is
00035  * necessary for the application to maintain its own frame-buffer
00036  * memory in the micro-controller's SRAM (see fb_alloc())---the
00037  * application is not restricted to a single framebuffer; if SRAM size
00038  * permits, multiple buffers may be employed. In order to update the
00039  * LCD, the application first draws (bitmaps or text) into some
00040  * framebuffer memory, and then flushes the framebuffer to the LCD
00041  * over the serial interface.
00042  *
00043  * Here's some sample code to drive the LCD display:
00044  *
00045  *     DigitalOut led1(LED1);
00046  *     SharpLCD lcd(p9, MBED_SPI0);
00047  *
00048  *     uint8_t framebuffer[SharpLCD::SIZEOF_FRAMEBUFFER_FOR_ALLOC];
00049  *
00050  *     int main(void)
00051  *     {
00052  *         SharpLCD::FrameBuffer fb(framebuffer);
00053  *
00054  *         lcd.enableDisplay();
00055  *         lcd.clear();
00056  *         fb.printString(lookupFontFace("DejaVu Serif", 8),
00057  *                        20,
00058  *                        40,
00059  *                        BLACK,
00060  *                        "Rohit");
00061  *         lcd.drawFrameBuffer(fb);
00062  *
00063  *         led1 = 1;
00064  *         while (true) {
00065  *             wait(0.5);
00066  *             led1 = !led1;
00067  *         }
00068  *     }
00069  */
00070 
00071 class SharpLCD {
00072 public:
00073     class FrameBuffer {
00074     public:
00075         /**
00076          * \brief initialize the hardware dependent component of a given
00077          * framebuffer; and set it up to show all-white.
00078          *
00079          * \note This does not update the LCD automatically; it only
00080          * initializes a framebuffer.
00081          *
00082          * \param[in] fb
00083          *     A memory buffer to initialize.
00084          */
00085         FrameBuffer(uint8_t *fb);
00086 
00087         /**
00088          * Clear the framebuffer to prepare for new drawing. The cleared buffer
00089          * still needs to be drawn on the LCD if clearning the LCD is desired.
00090          */
00091         void clear(void);
00092 
00093         /**
00094          * \brief Copy over a bitmap to a specified location into the framebuffer.
00095          *
00096          * This is the main work-horse for displaying bitmaps on the LCD. We
00097          * only support mono-chrome bitmaps with an encoding of 1 for white
00098          * and 0 for black. We have rendering tools to convert a bitmap into
00099          * the required encoding.
00100 
00101          * \note The placement of the target bitmap is limited to the LCD's
00102          * boundary--otherwise this routine fails.
00103          *
00104          * In case you are wondering, 'blit' stands for Block Image Transfer.
00105          *
00106          * Sample code:
00107          * <pre>
00108                 fb_bitBlit(fb,
00109                            (const uint8_t *)pixel_data,
00110                            width,
00111                            height,
00112                            0, // posx
00113                            0  // posy
00114                            );
00115                 lcd_drawFrameBuffer(fb);
00116         </pre>
00117          */
00118         void bitBlit(const uint8_t *bitmap,
00119                      unsigned int   width,  /*!< width of the bitmap */
00120                      unsigned int   height, /*!< height of the bitmap */
00121                      unsigned int   posx,   /*!< x-offset for the
00122                                              * placement of the top-left
00123                                              * corner of the bitmap
00124                                              * w.r.t. the top-left
00125                                              * corner of the screen */
00126                      unsigned int   posy    /*!< y-offset for the
00127                                              * placement of the top-left
00128                                              * corner of the bitmap
00129                                              * w.r.t. the top-left
00130                                              * corner of the screen */
00131             );
00132 
00133         /*
00134          * \brief Fetch a byte (8-bit pixel sequence) from a given scan-line
00135          * in the framebuffer.
00136          *
00137          * The scan-line is identified by the row; and pixels are grouped into
00138          * 8-bit bytes within a row.
00139          *
00140          * \note This function is declared inline for a faster implementation.
00141          *
00142          * \param[in] framebuffer
00143          *     The framebuffer to fetch the byte from.
00144          *
00145          * \param[in] row
00146          *     The row index of the scan line.
00147          *
00148          * \param[in] byteIndex
00149          *     The pixel-index expressed as a byte-index.
00150          */
00151         uint8_t
00152         getRowByte(unsigned int row, unsigned int byteIndex) {
00153             return buffer[rowColToIndex(row, byteIndex)];
00154         }
00155 
00156         /*
00157          * \brief Set a byte (8-bit pixel sequence) for a given scan-line in
00158          * the framebuffer.
00159          *
00160          * The scan-line is identified by the row; and pixels are grouped into
00161          * 8-bit bytes within a row.
00162          *
00163          * \note This function is declared inline for a faster implementation.
00164          *
00165          * \param[in] framebuffer
00166          *     The framebuffer to set the byte into.
00167          *
00168          * \param[in] row
00169          *     The row index of the scan line.
00170          *
00171          * \param[in] byteIndex
00172          *     The pixel-index expressed as a byte-index.
00173          *
00174          * \param[in] pixels
00175          *     The actual 8 pixels to set.
00176          */
00177         void
00178         setRowByte(unsigned int row, unsigned int byteIndex, uint8_t pixels) {
00179             buffer[rowColToIndex(row, byteIndex)] = pixels;
00180         }
00181 
00182         /**
00183          * \brief The printf function for the frameBuffer.
00184          *
00185          * This can be used to render strings in a given
00186          * font-face. Internally, it uses fb_bitBlit to bilt the glyphs onto a
00187          * framebuffer. Currently, since bitBlit doesn't handle the case where
00188          * a bitmap exceeds the framebuffer's boundary, you must be very
00189          * careful about the placement of the text string. Later, when
00190          * fb_bitBlit is able to handle bitmaps which fall outside the LCD's
00191          * boundary, the rendered text may be clipped if it doesn't fit the
00192          * frame.
00193          *
00194          * \param[in] face
00195          *     The font-face to be used for rendering the text.
00196          *
00197          * \param[in] baselineX
00198          *     The X-offset from the left corner of the screen of the starting
00199          *     pen position; this defines the X-coordinate of the baseline.
00200          *
00201          * \param[in] baselineY
00202          *     The Y-offset from the top corner of the screen of the starting
00203          *     pen position; this defines the Y-coordinate of the baseline.
00204          *
00205          * \param[in] fgColor
00206          *     The foreground colour.
00207          *
00208          * \param[in] string
00209          *     The text to be rendered.
00210          *
00211          * Sample code:
00212          * <pre>
00213          *      face = lookupFontFace("DejaVu Serif", 9);
00214          *      if (face == NULL) {
00215          *          TRACE_FATAL("failed to find face for DejaVu Serif; 10\n");
00216          *      }
00217          *      fb_printString(fb,
00218          *                     face,
00219          *                     90,      // baselineX
00220          *                     140,     // baselineY
00221          *                     BLACK,   // foregroundColor
00222          *                     "Hello Mr. Obama!");
00223          *      lcd_drawFrameBuffer(fb);
00224          * </pre>
00225          */
00226         void printString(const font_face_t *face,
00227                          unsigned short     baselineX,
00228                          unsigned short     baselineY,
00229                          font_color_t       fgColor,
00230                          const char        *string);
00231 
00232         const uint8_t *getBuffer(void) const {
00233             return (buffer);
00234         }
00235 
00236         uint8_t *getBuffer(void) {
00237             return (buffer);
00238         }
00239 
00240     private:
00241         unsigned rowColToIndex(unsigned row, unsigned col) {
00242             return (row * LCD_FRAMEBUFFER_SIZEOF_SCAN_LINE) + LCD_FRAMEBUFFER_SIZEOF_SCAN_LINE_METADATA + col;
00243         }
00244 
00245     private:
00246         uint8_t *const buffer;
00247     };
00248 
00249 public:
00250     SharpLCD(PinName enable, PinName cs, PinName mosi, PinName miso_unused, PinName sclk, PinName _unused = NC) :
00251         displayEnable(enable, 0), chipSelect(cs, 0), spi(mosi, miso_unused, sclk, _unused) {
00252         spi.frequency(1000000);
00253         spi.format(8, 0);
00254     };
00255 
00256     /**
00257      * \brief Turn on the LCD's display.
00258      *
00259      * \note Updates to the LCD's memory won't show up on the display
00260      * until the display is enabled through this function.
00261      */
00262     void enableDisplay(void);
00263 
00264     /**
00265      * \brief Turn off the LCD's display---i.e. make it go blank.
00266      *
00267      * \note The LCD will retain its memory even when the display is disabled.
00268      *
00269      * This is different from re-initializing the LCD's display, since it does
00270      * not affect the LCD memory. When the display is re-enabled, the LCD
00271      * will show the contents of its memory.
00272      */
00273     void disableDisplay(void);
00274 
00275     /**
00276      * \brief Clear the LCD's display
00277      *
00278      * Write all-white to the LCD's memory.  If a frameBuffer is passed in
00279      * then it is re-initialized as well; otherwise this function does not
00280      * operate on any global frame-buffer and updating any
00281      * application-specific frameBuffer is still the application's
00282      * responsibility.
00283      */
00284     void clear(void);
00285 
00286     static uint8_t bitReverse8(uint8_t byte) {
00287         #if (__CORTEX_M >= 0x03)
00288             return (uint8_t)(__RBIT(byte) >> 24);
00289         #else /* #if (__CORTEX_M < 0x03) */
00290             uint8_t rev8 = 0;
00291 
00292             for (unsigned i = 0; i < 8; i++) {
00293                 if (byte & (1 << i)) {
00294                     rev8 |= 1 << (7 - i);
00295                 }
00296             }
00297 
00298             return rev8;
00299         #endif /* #if (__CORTEX_M >= 0x03) */
00300     }
00301 
00302     /**
00303      * \brief Update LCD using a given framebuffer.
00304      *
00305      * The entire contents of the framebuffer will be DMA'd to the LCD;
00306      * the calling thread will loose the CPU during the transfer, but
00307      * other threads may remain active in that duration.
00308      *
00309      * \param[in] fb
00310      *     The frame buffer to send to the LCD hardware.
00311      */
00312     void drawFrameBuffer(const FrameBuffer &fb);
00313 
00314     /**
00315      * Toggle the VCOM mode of the LCD; it is recommended to trigger this
00316      * periodically. Check the datasheet.
00317      */
00318     void toggleVCOM(void);
00319 
00320 private:
00321     /**
00322      * Helper function to write out a buffer onto the LCD's SPI channel.
00323      */
00324     void writeBuffer(const uint8_t *buffer, unsigned len);
00325 
00326 public:
00327     static const unsigned LCD_WIDTH  = 96;  ///< Constant defining the LCD's geometry.
00328     static const unsigned LCD_HEIGHT = 96;  ///< Constant defining the LCD's geometry.
00329     static const unsigned LCD_END_OF_DUMMY_SIZE = 2;
00330     static const unsigned LCD_FRAMEBUFFER_SIZEOF_SCAN_LINE_METADATA =
00331         (1 + /* mode byte in SPI update command */
00332          1   /* addr byte in SPI update command */);
00333     static const unsigned LCD_FRAMEBUFFER_SIZEOF_SCAN_LINE =
00334         (LCD_FRAMEBUFFER_SIZEOF_SCAN_LINE_METADATA + (LCD_WIDTH / 8));
00335 
00336     static const unsigned SIZEOF_FRAMEBUFFER = (LCD_HEIGHT * LCD_FRAMEBUFFER_SIZEOF_SCAN_LINE);
00337     static const unsigned SIZEOF_FRAMEBUFFER_FOR_ALLOC = SIZEOF_FRAMEBUFFER + LCD_END_OF_DUMMY_SIZE;
00338 
00339 private:
00340     /* Constants for the LCD's command protocol */
00341     static const uint8_t M0_FLAG = 0x80;
00342     static const uint8_t M1_FLAG = 0x40;
00343     static const uint8_t M2_FLAG = 0x20;
00344     static const uint8_t DUMMY8  = 0x00;
00345 
00346 private:
00347     DigitalOut displayEnable;
00348     DigitalOut chipSelect;
00349     SPI        spi;
00350 };
00351 
00352 inline void
00353 SharpLCD::enableDisplay(void) {
00354     displayEnable = 1;
00355 }
00356 
00357 inline void
00358 SharpLCD::disableDisplay(void) {
00359     displayEnable = 0;
00360 }
00361 
00362 #endif /* #ifndef __SHARP_LCD_HPP__ */