Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Sample_program_Font72
epd1in54.cpp
00001 /** 00002 * @filename : epd1in54.cpp 00003 * @brief : Implements for e-paper library 00004 * @author : Yehui from Waveshare 00005 * 00006 * Copyright (C) Waveshare August 10 2017 00007 * 00008 * Permission is hereby granted, free of charge, to any person obtaining a copy 00009 * of this software and associated documnetation files (the "Software"), to deal 00010 * in the Software without restriction, including without limitation the rights 00011 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00012 * copies of the Software, and to permit persons to whom the Software is 00013 * furished to do so, subject to the following conditions: 00014 * 00015 * The above copyright notice and this permission notice shall be included in 00016 * all copies or substantial portions of the Software. 00017 * 00018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00019 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00020 * FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00021 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00022 * LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00023 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00024 * THE SOFTWARE. 00025 */ 00026 00027 #include <stdlib.h> 00028 #include "epd1in54.h" 00029 00030 const unsigned char lut_full_update[] = 00031 { 00032 0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22, 00033 0x66, 0x69, 0x69, 0x59, 0x58, 0x99, 0x99, 0x88, 00034 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB4, 0x13, 0x51, 00035 0x35, 0x51, 0x51, 0x19, 0x01, 0x00 00036 }; 00037 00038 const unsigned char lut_partial_update[] = 00039 { 00040 0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00, 00041 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00042 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 00043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 00044 }; 00045 00046 00047 00048 Epd::~Epd() { 00049 }; 00050 00051 00052 Epd::Epd(PinName mosi, 00053 PinName miso, 00054 PinName sclk, 00055 PinName cs, 00056 PinName dc, 00057 PinName rst, 00058 PinName busy 00059 ):EpdIf(mosi, miso, sclk, cs, dc, rst, busy){ 00060 00061 width = EPD_WIDTH; 00062 height= EPD_HEIGHT; 00063 rotate = ROTATE_270; 00064 00065 } 00066 00067 int Epd::Init(const unsigned char* lut) { 00068 00069 if(IfInit() != 0){ 00070 return -1; 00071 } 00072 00073 /* EPD hardware init start */ 00074 Reset(); 00075 SendCommand(DRIVER_OUTPUT_CONTROL); 00076 SendData((EPD_HEIGHT - 1) & 0xFF); 00077 SendData(((EPD_HEIGHT - 1) >> 8) & 0xFF); 00078 SendData(0x00); // GD = 0; SM = 0; TB = 0; 00079 SendCommand(BOOSTER_SOFT_START_CONTROL); 00080 SendData(0xD7); 00081 SendData(0xD6); 00082 SendData(0x9D); 00083 SendCommand(WRITE_VCOM_REGISTER); 00084 SendData(0xA8); // VCOM 7C 00085 SendCommand(SET_DUMMY_LINE_PERIOD); 00086 SendData(0x1A); // 4 dummy lines per gate 00087 SendCommand(SET_GATE_TIME); 00088 SendData(0x08); // 2us per line 00089 SendCommand(DATA_ENTRY_MODE_SETTING); 00090 SendData(0x03); // X increment; Y increment 00091 SetLut(lut); 00092 /* EPD hardware init end */ 00093 return 0; 00094 } 00095 00096 /** 00097 * @brief: basic function for sending commands 00098 */ 00099 void Epd::SendCommand(unsigned char command) { 00100 DigitalWrite(m_dc, LOW); 00101 SpiTransfer(command); 00102 } 00103 00104 /** 00105 * @brief: basic function for sending data 00106 */ 00107 void Epd::SendData(unsigned char data) { 00108 DigitalWrite(m_dc, HIGH); 00109 SpiTransfer(data); 00110 } 00111 00112 /** 00113 * @brief: Wait until the m_busy goes HIGH 00114 */ 00115 void Epd::WaitUntilIdle(void) { 00116 while(DigitalRead(m_busy) == 1) { //0: busy, 1: idle 00117 DelayMs(100); 00118 } 00119 } 00120 00121 /** 00122 * @brief: module reset. 00123 * often used to awaken the module in deep sleep, 00124 * see Epd::Sleep(); 00125 */ 00126 void Epd::Reset(void) { 00127 DigitalWrite(m_rst, LOW); //module reset 00128 DelayMs(200); 00129 DigitalWrite(m_rst, HIGH); 00130 DelayMs(200); 00131 } 00132 00133 00134 /** 00135 * @brief: set the look-up table register 00136 */ 00137 void Epd::SetLut(const unsigned char* lut) { 00138 SendCommand(WRITE_LUT_REGISTER); 00139 /* the length of look-up table is 30 bytes */ 00140 for (int i = 0; i < 30; i++) { 00141 SendData(lut[i]); 00142 } 00143 } 00144 00145 00146 /** 00147 * @brief: put an image buffer to the frame memory. 00148 * this won't update the display. 00149 */ 00150 void Epd::SetFrameMemory( 00151 const unsigned char* image_buffer, 00152 int x, 00153 int y, 00154 int image_width, 00155 int image_height 00156 ) { 00157 int x_end; 00158 int y_end; 00159 00160 if ( 00161 image_buffer == NULL || 00162 x < 0 || image_width < 0 || 00163 y < 0 || image_height < 0 00164 ) { 00165 return; 00166 } 00167 /* x point must be the multiple of 8 or the last 3 bits will be ignored */ 00168 x &= 0xF8; 00169 image_width &= 0xF8; 00170 if (x + image_width >= this->width) { 00171 x_end = this->width - 1; 00172 } else { 00173 x_end = x + image_width - 1; 00174 } 00175 if (y + image_height >= this->height) { 00176 y_end = this->height - 1; 00177 } else { 00178 y_end = y + image_height - 1; 00179 } 00180 SetMemoryArea(x, y, x_end, y_end); 00181 SetMemoryPointer(x, y); 00182 SendCommand(WRITE_RAM); 00183 /* send the image data */ 00184 for (int j = 0; j < y_end - y + 1; j++) { 00185 for (int i = 0; i < (x_end - x + 1) / 8; i++) { 00186 SendData(image_buffer[i + j * (image_width / 8)]); 00187 } 00188 } 00189 } 00190 00191 /** 00192 * @brief: clear the frame memory with the specified color. 00193 * this won't update the display. 00194 */ 00195 void Epd::ClearFrameMemory(unsigned char color) { 00196 SetMemoryArea(0, 0, this->width - 1, this->height - 1); 00197 SetMemoryPointer(0, 0); 00198 SendCommand(WRITE_RAM); 00199 /* send the color data */ 00200 for (int i = 0; i < this->width / 8 * this->height; i++) { 00201 SendData(color); 00202 } 00203 } 00204 00205 /** 00206 * @brief: update the display 00207 * there are 2 memory areas embedded in the e-paper display 00208 * but once this function is called, 00209 * the the next action of SetFrameMemory or ClearFrame will 00210 * set the other memory area. 00211 */ 00212 void Epd::DisplayFrame(void) { 00213 SendCommand(DISPLAY_UPDATE_CONTROL_2); 00214 SendData(0xC4); 00215 SendCommand(MASTER_ACTIVATION); 00216 SendCommand(TERMINATE_FRAME_READ_WRITE); 00217 WaitUntilIdle(); 00218 } 00219 00220 /** 00221 * @brief: private function to specify the memory area for data R/W 00222 */ 00223 void Epd::SetMemoryArea(int x_start, int y_start, int x_end, int y_end) { 00224 SendCommand(SET_RAM_X_ADDRESS_START_END_POSITION); 00225 /* x point must be the multiple of 8 or the last 3 bits will be ignored */ 00226 SendData((x_start >> 3) & 0xFF); 00227 SendData((x_end >> 3) & 0xFF); 00228 SendCommand(SET_RAM_Y_ADDRESS_START_END_POSITION); 00229 SendData(y_start & 0xFF); 00230 SendData((y_start >> 8) & 0xFF); 00231 SendData(y_end & 0xFF); 00232 SendData((y_end >> 8) & 0xFF); 00233 } 00234 00235 /** 00236 * @brief: private function to specify the start point for data R/W 00237 */ 00238 void Epd::SetMemoryPointer(int x, int y) { 00239 SendCommand(SET_RAM_X_ADDRESS_COUNTER); 00240 /* x point must be the multiple of 8 or the last 3 bits will be ignored */ 00241 SendData((x >> 3) & 0xFF); 00242 SendCommand(SET_RAM_Y_ADDRESS_COUNTER); 00243 SendData(y & 0xFF); 00244 SendData((y >> 8) & 0xFF); 00245 WaitUntilIdle(); 00246 } 00247 00248 00249 /** 00250 * @brief: After this command is transmitted, the chip would enter the 00251 * deep-sleep mode to save power. 00252 * The deep sleep mode would return to standby by hardware reset. 00253 * You can use Epd::Init() to awaken 00254 */ 00255 void Epd::Sleep() { 00256 SendCommand(DEEP_SLEEP_MODE); 00257 WaitUntilIdle(); 00258 } 00259 00260 00261 void Epd::SetRotate(int rotate){ 00262 if (rotate == ROTATE_0){ 00263 rotate = ROTATE_0; 00264 width = EPD_WIDTH; 00265 height = EPD_HEIGHT; 00266 } 00267 else if (rotate == ROTATE_90){ 00268 rotate = ROTATE_90; 00269 width = EPD_HEIGHT; 00270 height = EPD_WIDTH; 00271 } 00272 else if (rotate == ROTATE_180){ 00273 rotate = ROTATE_180; 00274 width = EPD_WIDTH; 00275 height = EPD_HEIGHT; 00276 } 00277 else if (rotate == ROTATE_270){ 00278 rotate = ROTATE_270; 00279 width = EPD_HEIGHT; 00280 height = EPD_WIDTH; 00281 } 00282 } 00283 00284 00285 void Epd::SetPixel(unsigned char* frame_buffer, int x, int y, int colored){ 00286 if (x < 0 || x >= width || y < 0 || y >= height){ 00287 return; 00288 } 00289 if (rotate == ROTATE_0){ 00290 SetAbsolutePixel(frame_buffer, x, y, colored); 00291 } 00292 else if (rotate == ROTATE_90){ 00293 int point_temp = x; 00294 x = EPD_WIDTH - y; 00295 y = point_temp; 00296 SetAbsolutePixel(frame_buffer, x, y, colored); 00297 } 00298 else if (rotate == ROTATE_180){ 00299 x = EPD_WIDTH - x; 00300 y = EPD_HEIGHT- y; 00301 SetAbsolutePixel(frame_buffer, x, y, colored); 00302 } 00303 else if (rotate == ROTATE_270){ 00304 int point_temp = x; 00305 x = y; 00306 y = EPD_HEIGHT - point_temp; 00307 SetAbsolutePixel(frame_buffer, x, y, colored); 00308 } 00309 } 00310 00311 void Epd::SetAbsolutePixel(unsigned char *frame_buffer, int x, int y, int colored){ 00312 // To avoid display orientation effects 00313 // use EPD_WIDTH instead of self.width 00314 // use EPD_HEIGHT instead of self.height 00315 if (x < 0 || x >= EPD_WIDTH || y < 0 || y >= EPD_HEIGHT){ 00316 return; 00317 } 00318 if (colored){ 00319 frame_buffer[(x + y * EPD_WIDTH) / 8] &= ~(0x80 >> (x % 8)); 00320 } 00321 else{ 00322 frame_buffer[(x + y * EPD_WIDTH) / 8] |= 0x80 >> (x % 8); 00323 } 00324 } 00325 00326 void Epd::DrawLine(unsigned char*frame_buffer, int x0, int y0, int x1, int y1, int colored){ 00327 // Bresenham algorithm 00328 int dx = x1 - x0 >= 0 ? x1 - x0 : x0 - x1; 00329 int sx = x0 < x1 ? 1 : -1; 00330 int dy = y1 - y0 <= 0 ? y1 - y0 : y0 - y1; 00331 int sy = y0 < y1 ? 1 : -1; 00332 int err = dx + dy; 00333 while((x0 != x1) && (y0 != y1)){ 00334 SetPixel(frame_buffer, x0, y0 , colored); 00335 if (2 * err >= dy){ 00336 err += dy; 00337 x0 += sx; 00338 } 00339 if (2 * err <= dx){ 00340 err += dx; 00341 y0 += sy; 00342 } 00343 } 00344 } 00345 00346 void Epd::DrawHorizontalLine(unsigned char *frame_buffer, int x, int y, int width, int colored){ 00347 for (int i=x; i<x + width; i++){ 00348 SetPixel(frame_buffer, i, y, colored); 00349 } 00350 } 00351 00352 void Epd::DrawVerticalLine(unsigned char *frame_buffer, int x, int y, int height, int colored){ 00353 for (int i=y; i<y + height; i++){ 00354 SetPixel(frame_buffer, x, i, colored); 00355 } 00356 } 00357 00358 void Epd::DrawRectangle(unsigned char *frame_buffer, int x0, int y0, int x1, int y1, int colored){ 00359 int min_x = x1 > x0 ? x0 : x1; 00360 int max_x = x1 > x0 ? x1 : x0; 00361 int min_y = y1 > y0 ? y0 : y1; 00362 int max_y = y1 > y0 ? y1 : y0; 00363 DrawHorizontalLine(frame_buffer, min_x, min_y, max_x - min_x + 1, colored); 00364 DrawHorizontalLine(frame_buffer, min_x, max_y, max_x - min_x + 1, colored); 00365 DrawVerticalLine(frame_buffer, min_x, min_y, max_y - min_y + 1, colored); 00366 DrawVerticalLine(frame_buffer, max_x, min_y, max_y - min_y + 1, colored); 00367 } 00368 00369 00370 void Epd::DrawFilledRectangle(unsigned char *frame_buffer, int x0, int y0, int x1, int y1, int colored){ 00371 int min_x = x1 > x0 ? x0 : x1; 00372 int max_x = x1 > x0 ? x1 : x0; 00373 int min_y = y1 > y0 ? y0 : y1; 00374 int max_y = y1 > y0 ? y1 : y0; 00375 00376 for (int i=min_x; i < max_x+1; i++){ 00377 DrawVerticalLine(frame_buffer, i, min_y, max_y - min_y + 1, colored); 00378 } 00379 } 00380 00381 void Epd::DrawCircle(unsigned char *frame_buffer, int x, int y, int radius, int colored){ 00382 // Bresenham algorithm 00383 int x_pos = -radius; 00384 int y_pos = 0; 00385 int err = 2 - 2 * radius; 00386 if (x >= width || y >= height){ 00387 return; 00388 } 00389 while ( 1 ){ 00390 SetPixel(frame_buffer, x - x_pos, y + y_pos, colored); 00391 SetPixel(frame_buffer, x + x_pos, y + y_pos, colored); 00392 SetPixel(frame_buffer, x + x_pos, y - y_pos, colored); 00393 SetPixel(frame_buffer, x - x_pos, y - y_pos, colored); 00394 int e2 = err; 00395 if (e2 <= y_pos){ 00396 y_pos += 1; 00397 err += y_pos * 2 + 1; 00398 if(-x_pos == y_pos && e2 <= x_pos){ 00399 e2 = 0; 00400 } 00401 } 00402 if (e2 > x_pos){ 00403 x_pos += 1; 00404 err += x_pos * 2 + 1; 00405 } 00406 if (x_pos > 0){ 00407 break; 00408 } 00409 } 00410 } 00411 00412 void Epd::DrawFilledCircle(unsigned char* frame_buffer, int x, int y, int radius, int colored){ 00413 // Bresenham algorithm 00414 int x_pos = -radius; 00415 int y_pos = 0; 00416 int err = 2 - 2 * radius; 00417 if (x >= width || y >= height){ 00418 return; 00419 } 00420 while ( 1 ){ 00421 SetPixel(frame_buffer, x - x_pos, y + y_pos, colored); 00422 SetPixel(frame_buffer, x + x_pos, y + y_pos, colored); 00423 SetPixel(frame_buffer, x + x_pos, y - y_pos, colored); 00424 SetPixel(frame_buffer, x - x_pos, y - y_pos, colored); 00425 DrawHorizontalLine(frame_buffer, x + x_pos, y + y_pos, 2 * (-x_pos) + 1, colored); 00426 DrawHorizontalLine(frame_buffer, x + x_pos, y - y_pos, 2 * (-x_pos) + 1, colored); 00427 int e2 = err; 00428 if (e2 <= y_pos){ 00429 y_pos += 1; 00430 err += y_pos * 2 + 1; 00431 if(-x_pos == y_pos && e2 <= x_pos){ 00432 e2 = 0; 00433 } 00434 } 00435 if (e2 > x_pos){ 00436 x_pos += 1; 00437 err += x_pos * 2 + 1; 00438 } 00439 if (x_pos > 0){ 00440 break; 00441 } 00442 } 00443 } 00444 00445 00446 00447 /** 00448 * @brief: this draws a charactor on the frame buffer but not refresh 00449 */ 00450 void Epd::DrawCharAt(unsigned char *frame_buffer, int x, int y, char ascii_char, sFONT* font, int colored) { 00451 int i, j; 00452 unsigned int char_offset = (ascii_char - ' ') * font->Height * (font->Width / 8 + (font->Width % 8 ? 1 : 0)); 00453 const unsigned char* ptr = &font->table[char_offset]; 00454 00455 for (j = 0; j < font->Height; j++) { 00456 for (i = 0; i < font->Width; i++) { 00457 if (*ptr & (0x80 >> (i % 8))) { 00458 SetPixel(frame_buffer, x + i, y + j, colored); 00459 } 00460 if (i % 8 == 7) { 00461 ptr++; 00462 } 00463 } 00464 if (font->Width % 8 != 0) { 00465 ptr++; 00466 } 00467 } 00468 } 00469 00470 /** 00471 * @brief: this displays a string on the frame buffer but not refresh 00472 */ 00473 void Epd::DrawStringAt(unsigned char *frame_buffer, int x, int y, const char* text, sFONT* font, int colored) { 00474 const char* p_text = text; 00475 unsigned int counter = 0; 00476 int refcolumn = x; 00477 00478 /* Send the string character by character on EPD */ 00479 while (*p_text != 0) { 00480 /* Display one character on EPD */ 00481 DrawCharAt(frame_buffer, refcolumn, y, *p_text, font, colored); 00482 /* Decrement the column position by 16 */ 00483 refcolumn += font->Width; 00484 /* Point on the next character */ 00485 p_text++; 00486 counter++; 00487 } 00488 }
Generated on Wed Jul 13 2022 16:49:34 by
