Waleed Elmughrabi / epd1in54

Dependents:   Sample_program_Font72

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers epd1in54.cpp Source File

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 }