/** * @filename : epd1in54.cpp * @brief : Implements for e-paper library * @author : Yehui from Waveshare * * Copyright (C) Waveshare September 5 2017 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documnetation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "epd1in54.h" Epd::~Epd() { }; Epd::Epd() { reset_pin = RST_PIN; dc_pin = DC_PIN; cs_pin = CS_PIN; busy_pin = BUSY_PIN; width = EPD_WIDTH; height = EPD_HEIGHT; }; int Epd::Init(const unsigned char* lut) { /* this calls the peripheral hardware interface, see epdif */ if (IfInit() != 0) { return -1; } /* EPD hardware init start */ this->lut = lut; Reset(); SendCommand(DRIVER_OUTPUT_CONTROL); SendData((EPD_HEIGHT - 1) & 0xFF); SendData(((EPD_HEIGHT - 1) >> 8) & 0xFF); SendData(0x00); // GD = 0; SM = 0; TB = 0; SendCommand(BOOSTER_SOFT_START_CONTROL); SendData(0xD7); SendData(0xD6); SendData(0x9D); SendCommand(WRITE_VCOM_REGISTER); SendData(0xA8); // VCOM 7C SendCommand(SET_DUMMY_LINE_PERIOD); SendData(0x1A); // 4 dummy lines per gate SendCommand(SET_GATE_TIME); SendData(0x08); // 2us per line SendCommand(DATA_ENTRY_MODE_SETTING); SendData(0x03); // X increment; Y increment SetLut(this->lut); /* EPD hardware init end */ return 0; } /** * @brief: basic function for sending commands */ void Epd::SendCommand(unsigned char command) { DigitalWrite(dc_pin, LOW); SpiTransfer(command); } /** * @brief: basic function for sending data */ void Epd::SendData(unsigned char data) { DigitalWrite(dc_pin, HIGH); SpiTransfer(data); } /** * @brief: Wait until the busy_pin goes LOW */ void Epd::WaitUntilIdle(void) { while(DigitalRead(busy_pin) == HIGH) { //LOW: idle, HIGH: busy DelayMs(100); } } /** * @brief: module reset. * often used to awaken the module in deep sleep, * see Epd::Sleep(); */ void Epd::Reset(void) { DigitalWrite(reset_pin, LOW); //module reset DelayMs(200); DigitalWrite(reset_pin, HIGH); DelayMs(200); } /** * @brief: set the look-up table register */ void Epd::SetLut(const unsigned char* lut) { this->lut = lut; SendCommand(WRITE_LUT_REGISTER); /* the length of look-up table is 30 bytes */ for (int i = 0; i < 30; i++) { SendData(this->lut[i]); } } /** * @brief: put an image buffer to the frame memory. * this won't update the display. */ void Epd::SetFrameMemory( const unsigned char* image_buffer, int x, int y, int image_width, int image_height ) { int x_end; int y_end; if ( image_buffer == NULL || x < 0 || image_width < 0 || y < 0 || image_height < 0 ) { return; } /* x point must be the multiple of 8 or the last 3 bits will be ignored */ x &= 0xF8; image_width &= 0xF8; if (x + image_width >= this->width) { x_end = this->width - 1; } else { x_end = x + image_width - 1; } if (y + image_height >= this->height) { y_end = this->height - 1; } else { y_end = y + image_height - 1; } SetMemoryArea(x, y, x_end, y_end); SetMemoryPointer(x, y); SendCommand(WRITE_RAM); /* send the image data */ for (int j = 0; j < y_end - y + 1; j++) { for (int i = 0; i < (x_end - x + 1) / 8; i++) { SendData(image_buffer[i + j * (image_width / 8)]); } } } /** * @brief: put an image buffer to the frame memory. * this won't update the display. * * Question: When do you use this function instead of * void SetFrameMemory( * const unsigned char* image_buffer, * int x, * int y, * int image_width, * int image_height * ); * Answer: SetFrameMemory with parameters only reads image data * from the RAM but not from the flash in AVR chips (for AVR chips, * you have to use the function pgm_read_byte to read buffers * from the flash). */ void Epd::SetFrameMemory(const unsigned char* image_buffer) { SetMemoryArea(0, 0, this->width - 1, this->height - 1); SetMemoryPointer(0, 0); SendCommand(WRITE_RAM); /* send the image data */ for (int i = 0; i < this->width / 8 * this->height; i++) { SendData(pgm_read_byte(&image_buffer[i])); } } /** * @brief: clear the frame memory with the specified color. * this won't update the display. */ void Epd::ClearFrameMemory(unsigned char color) { SetMemoryArea(0, 0, this->width - 1, this->height - 1); SetMemoryPointer(0, 0); SendCommand(WRITE_RAM); /* send the color data */ for (int i = 0; i < this->width / 8 * this->height; i++) { SendData(color); } } /** * @brief: update the display * there are 2 memory areas embedded in the e-paper display * but once this function is called, * the the next action of SetFrameMemory or ClearFrame will * set the other memory area. */ void Epd::DisplayFrame(void) { SendCommand(DISPLAY_UPDATE_CONTROL_2); SendData(0xC4); SendCommand(MASTER_ACTIVATION); SendCommand(TERMINATE_FRAME_READ_WRITE); WaitUntilIdle(); } /** * @brief: private function to specify the memory area for data R/W */ void Epd::SetMemoryArea(int x_start, int y_start, int x_end, int y_end) { SendCommand(SET_RAM_X_ADDRESS_START_END_POSITION); /* x point must be the multiple of 8 or the last 3 bits will be ignored */ SendData((x_start >> 3) & 0xFF); SendData((x_end >> 3) & 0xFF); SendCommand(SET_RAM_Y_ADDRESS_START_END_POSITION); SendData(y_start & 0xFF); SendData((y_start >> 8) & 0xFF); SendData(y_end & 0xFF); SendData((y_end >> 8) & 0xFF); } /** * @brief: private function to specify the start point for data R/W */ void Epd::SetMemoryPointer(int x, int y) { SendCommand(SET_RAM_X_ADDRESS_COUNTER); /* x point must be the multiple of 8 or the last 3 bits will be ignored */ SendData((x >> 3) & 0xFF); SendCommand(SET_RAM_Y_ADDRESS_COUNTER); SendData(y & 0xFF); SendData((y >> 8) & 0xFF); WaitUntilIdle(); } /** * @brief: After this command is transmitted, the chip would enter the * deep-sleep mode to save power. * The deep sleep mode would return to standby by hardware reset. * You can use Epd::Init() to awaken */ void Epd::Sleep() { SendCommand(DEEP_SLEEP_MODE); WaitUntilIdle(); } const unsigned char lut_full_update[] = { 0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22, 0x66, 0x69, 0x69, 0x59, 0x58, 0x99, 0x99, 0x88, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB4, 0x13, 0x51, 0x35, 0x51, 0x51, 0x19, 0x01, 0x00 }; const unsigned char lut_partial_update[] = { 0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* END OF FILE */