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
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__ */
Generated on Tue Jul 12 2022 19:17:11 by 1.7.2