Library for Waveshare 2.7" tri-colour e-Paper display.
Diff: epd2in7b.cpp
- Revision:
- 0:9e6a8e3cd8de
diff -r 000000000000 -r 9e6a8e3cd8de epd2in7b.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/epd2in7b.cpp Fri Dec 06 23:24:50 2019 +0000 @@ -0,0 +1,494 @@ +/** + * @filename : epd2in7b.cpp + * @brief : Implements for Dual-color e-paper library + * @author : Yehui from Waveshare (modified by Mark Roberts / mdroberts1243) + * + * Copyright (C) Waveshare August 10 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. + */ + +/* + * Modified by Kenji Arai / JH1PJL + * + * http://www.page.sannet.ne.jp/kenjia/index.html + * http://mbed.org/users/kenjiArai/ + * Created: April 27th, 2019 + * Revised: April 30th, 2019 + * + * Refrence software + * https://github.com/waveshare/e-Paper + * https://os.mbed.com/users/imachooon/code/epd1in54/ + * + * Technical documents + * https://www.waveshare.com/wiki/2.13inch_e-Paper_HAT_(B) + * + * Product + * http://akizukidenshi.com/catalog/g/gP-13757/ + * https://www.waveshare.com/2.13inch-e-paper-hat-b.htm + * + */ + +#include "epd2in7b.h" + +Epd::Epd(PinName mosi, + PinName miso, + PinName sclk, + PinName cs, + PinName dc, + PinName rst, + PinName busy, + PinName pwr + ):EpdIf(mosi, miso, sclk, cs, dc, rst, busy, pwr) +{ + horiz = EPD_HORIZ; // MDR -- changed to align with datasheet + vert = EPD_VERT; // MDR -- changed to align with datasheet +}; + +int Epd::Init(void) +{ + /* this calls the peripheral hardware interface, see epdif */ + if (IfInit() != 0) { + return -1; + } + /* EPD hardware init start */ + Reset(); + + SendCommand(POWER_ON); + WaitUntilIdle(); + + SendCommand(PANEL_SETTING); + SendData(0xaf); // 296x160, OTP LUT, B/W/Red mode, scan up, shift right, Booster on, soft reset + + SendCommand(PLL_CONTROL); + SendData(0x3a); //3A 100HZ 29 150Hz 39 200HZ 31 171HZ + + SendCommand(POWER_SETTING); + SendData(0x03); // VDS_EN, VDG_EN + SendData(0x00); // VCOM_HV, VGHL_LV[1], VGHL_LV[0] + SendData(0x2b); // VDH + SendData(0x2b); // VDL + SendData(0x09); // VDHR + + SendCommand(BOOSTER_SOFT_START); + SendData(0x07); + SendData(0x07); + SendData(0x17); // defaults 10ms start, strength 3, 6.58uS off time + + // Power optimization + SendCommand(0xF8); + SendData(0x60); + SendData(0xA5); + + // Power optimization + SendCommand(0xF8); + SendData(0x89); + SendData(0xA5); + + // Power optimization + SendCommand(0xF8); + SendData(0x90); + SendData(0x00); + + // Power optimization + SendCommand(0xF8); + SendData(0x93); + SendData(0x2A); + + // Power optimization + SendCommand(0xF8); + SendData(0x73); + SendData(0x41); + + SendCommand(VCM_DC_SETTING); + SendData(0x12); + + SendCommand(VCOM_AND_DATA_INTERVAL_SETTING); + SendData(0x87); // Define by OTP +/* + SendCommand(RESOLUTION_SETTING); // done in the display refresh and clear + SendData(0x01); + SendData(0x08); // horiz: 264 + SendData(0x00); + SendData(0xB0); // vert: 176 +*/ + SetLut(); + + SendCommand(PARTIAL_DISPLAY_REFRESH); + SendData(0x00); + + /* EPD hardware init end */ + return 0; +} + +/** + * @brief: basic function for sending commands + */ +void Epd::SendCommand(unsigned char command) +{ + DigitalWrite(m_dc, LOW); + SpiTransfer(command); +} + +/** + * @brief: basic function for sending data + */ +void Epd::SendData(unsigned char data) +{ + DigitalWrite(m_dc, HIGH); + SpiTransfer(data); +} + +/** + * @brief: Wait until the busy_pin goes HIGH + */ +void Epd::WaitUntilIdle(void) +{ + while(DigitalRead(m_busy) == 0) { //0: busy, 1: idle + DelayMs(100); + } +} + +/** + * @brief: module reset. + * often used to awaken the module in deep sleep, + * see Epd::Sleep(); + */ +void Epd::Reset(void) +{ + DigitalWrite(m_rst,HIGH); + DelayMs(200); + DigitalWrite(m_rst, LOW); + DelayMs(10); + DigitalWrite(m_rst, HIGH); + DelayMs(200); +} + +/** + * @brief: set the look-up tables + */ +void Epd::SetLut(void) { + unsigned int count; + SendCommand(VCOM_LUT); //vcom + for(count = 0; count < 44; count++) { + SendData(lut_vcom_dc[count]); + } + + SendCommand(W2W_LUT); //ww -- + for(count = 0; count < 42; count++) { + SendData(lut_ww[count]); + } + + SendCommand(B2W_LUT); //bw r + for(count = 0; count < 42; count++) { + SendData(lut_bw[count]); + } + + SendCommand(W2B_LUT); //wb w + for(count = 0; count < 42; count++) { + SendData(lut_bb[count]); + } + + SendCommand(B2B_LUT); //bb b + for(count = 0; count < 42; count++) { + SendData(lut_wb[count]); + } +} + +/** + * @brief: transmit partial data to the SRAM (both black and red) + * MDR -- Partial stuff all rewritten for 2.7 display + */ +void Epd::SetPartialWindow(const unsigned char* buffer_black, const unsigned char* buffer_red, int x, int y, int w, int l) +{ + SendCommand(PARTIAL_DATA_START_TRANSMISSION_1); // the black stuff + // x upper bit and lower byte + SendData(x >> 8); + SendData(x & 0xf8); // x should be the multiple of 8, the last 3 bit will always be ignored + // y upper bit and lower byte + SendData(y >> 8); + SendData(y & 0xff); + // w upper bit and lower byte + SendData(w >> 8); + SendData(w & 0xf8); // lower three bits zero, multiple of 8 + // l upper bit and lower byte + SendData(l >> 8); + SendData(l & 0xff); + // all the data (KPixel 1 ... KPixel n) + DelayMs(2); + if (buffer_black != NULL) { + for(int i = 0; i < w / 8 * l; i++) { + SendData(buffer_black[i]); + } + } else { + for(int i = 0; i < w / 8 * l; i++) { + SendData(0x00); + } + } + DelayMs(2); +// SendCommand(DATA_STOP); + + SendCommand(PARTIAL_DATA_START_TRANSMISSION_2); // the red stuff + // x upper bit and lower byte + SendData(x >> 8); + SendData(x & 0xf8); // x should be the multiple of 8, the last 3 bit will always be ignored + // y upper bit and lower byte + SendData(y >> 8); + SendData(y & 0xff); + // w upper bit and lower byte + SendData(w >> 8); + SendData(w & 0xf8); // lower three bits zero, multiple of 8 + // l upper bit and lower byte + SendData(l >> 8); + SendData(l & 0xff); + // all the data (KPixel 1 ... KPixel n) + DelayMs(2); + if (buffer_red != NULL) { + for(int i = 0; i < w / 8 * l; i++) { + SendData(buffer_red[i]); + } + } else { + for(int i = 0; i < w / 8 * l; i++) { + SendData(0x00); + } + } + DelayMs(2); +// SendCommand(DATA_STOP); +} + +/** + * @brief: transmit partial data to the black part of SRAM + */ +void Epd::SetPartialWindowBlack(const unsigned char* buffer_black, int x, int y, int w, int l) +{ + SendCommand(PARTIAL_DATA_START_TRANSMISSION_1); // the black stuff + // x upper bit and lower byte + SendData(x >> 8); + SendData(x & 0xf8); // x should be the multiple of 8, the last 3 bit will always be ignored + // y upper bit and lower byte + SendData(y >> 8); + SendData(y & 0xff); + // w upper bit and lower byte + SendData(w >> 8); + SendData(w & 0xf8); // lower three bits zero, multiple of 8 + // l upper bit and lower byte + SendData(l >> 8); + SendData(l & 0xff); + // all the data (KPixel 1 ... KPixel n) + DelayMs(2); + if (buffer_black != NULL) { + for(int i = 0; i < w / 8 * l; i++) { + SendData(buffer_black[i]); + } + } else { + for(int i = 0; i < w / 8 * l; i++) { + SendData(0x00); + } + } + DelayMs(2); +} + +/** + * @brief: transmit partial data to the red part of SRAM + */ +void Epd::SetPartialWindowRed(const unsigned char* buffer_red, int x, int y, int w, int l) +{ + SendCommand(PARTIAL_DATA_START_TRANSMISSION_2); // the red stuff + // x upper bit and lower byte + SendData(x >> 8); + SendData(x & 0xf8); // x should be the multiple of 8, the last 3 bit will always be ignored + // y upper bit and lower byte + SendData(y >> 8); + SendData(y & 0xff); + // w upper bit and lower byte + SendData(w >> 8); + SendData(w & 0xf8); // lower three bits zero, multiple of 8 + // l upper bit and lower byte + SendData(l >> 8); + SendData(l & 0xff); + // all the data (KPixel 1 ... KPixel n) + DelayMs(2); + if (buffer_red != NULL) { + for(int i = 0; i < w / 8 * l; i++) { + SendData(buffer_red[i]); + } + } else { + for(int i = 0; i < w / 8 * l; i++) { + SendData(0x00); + } + } + DelayMs(2); +// SendCommand(DATA_STOP); +} + +/** + * @brief: refresh and displays the frame + */ +void Epd::DisplayFrame(const unsigned char* frame_buffer_black, const unsigned char* frame_buffer_red) +{ + SendCommand(RESOLUTION_SETTING); + SendData(horiz >> 8); + SendData(horiz & 0xff); //176 + SendData(vert >> 8); + SendData(vert & 0xff); //264 + + if (frame_buffer_black != NULL) { + SendCommand(DATA_START_TRANSMISSION_1); + DelayMs(2); + for (int i = 0; i < this->horiz * this->vert / 8; i++) { + SendData(*(frame_buffer_black + i)); + } + DelayMs(2); + } + if (frame_buffer_red != NULL) { + SendCommand(DATA_START_TRANSMISSION_2); + DelayMs(2); + for (int i = 0; i < this->horiz * this->vert / 8; i++) { + SendData(*(frame_buffer_red + i)); + } + DelayMs(2); + } + SendCommand(DISPLAY_REFRESH); + WaitUntilIdle(); +} + +/** + * @brief: clear the frame data from the SRAM, this won't refresh the display + */ +void Epd::ClearFrame(void) +{ + SendCommand(RESOLUTION_SETTING); + SendData(horiz >> 8); + SendData(horiz & 0xff); //176 + SendData(vert >> 8); + SendData(vert & 0xff); //264 + + SendCommand(DATA_START_TRANSMISSION_1); + DelayMs(2); + for(int i = 0; i < horiz * vert / 8; i++) { + SendData(0xFF); + } + DelayMs(2); + SendCommand(DATA_START_TRANSMISSION_2); + DelayMs(2); + for(int i = 0; i < horiz * vert / 8; i++) { + SendData(0xFF); + } + DelayMs(2); +} + +/** + * @brief: This displays the frame data from SRAM + */ +void Epd::DisplayFrame(void) +{ + SendCommand(DISPLAY_REFRESH); + 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. The only one parameter is a + * check code, the command would be executed if check code = 0xA5. + * You can use Epd::Reset() to awaken and use Epd::Init() to initialize. + */ +void Epd::Sleep() +{ + SendCommand(POWER_OFF); + WaitUntilIdle(); + SendCommand(DEEP_SLEEP); + SendData(0xA5); // hardware reset to recover to standby +} + +/** + * @brief: e-Paper power control + * MDR -- maybe should check if NC! + */ +void Epd::PwrOn() +{ + //DigitalWrite(m_pwr, 1); +} + +void Epd::PwrOff() +{ + //DigitalWrite(m_pwr, 0); +} + +const unsigned char lut_vcom_dc[] = +{ +0x00, 0x00, +0x00, 0x1A, 0x1A, 0x00, 0x00, 0x01, +0x00, 0x0A, 0x0A, 0x00, 0x00, 0x08, +0x00, 0x0E, 0x01, 0x0E, 0x01, 0x10, +0x00, 0x0A, 0x0A, 0x00, 0x00, 0x08, +0x00, 0x04, 0x10, 0x00, 0x00, 0x05, +0x00, 0x03, 0x0E, 0x00, 0x00, 0x0A, +0x00, 0x23, 0x00, 0x00, 0x00, 0x01 +}; + +//R21H +const unsigned char lut_ww[] = +{ +0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, +0x40, 0x0A, 0x0A, 0x00, 0x00, 0x08, +0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, +0x80, 0x0A, 0x0A, 0x00, 0x00, 0x08, +0x00, 0x04, 0x10, 0x00, 0x00, 0x05, +0x00, 0x03, 0x0E, 0x00, 0x00, 0x0A, +0x00, 0x23, 0x00, 0x00, 0x00, 0x01 +}; + +//R22H r +const unsigned char lut_bw[] = +{ +0xA0, 0x1A, 0x1A, 0x00, 0x00, 0x01, +0x00, 0x0A, 0x0A, 0x00, 0x00, 0x08, +0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, +0x90, 0x0A, 0x0A, 0x00, 0x00, 0x08, +0xB0, 0x04, 0x10, 0x00, 0x00, 0x05, +0xB0, 0x03, 0x0E, 0x00, 0x00, 0x0A, +0xC0, 0x23, 0x00, 0x00, 0x00, 0x01 +}; + +//R23H w +const unsigned char lut_bb[] = +{ +0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, +0x40, 0x0A, 0x0A, 0x00, 0x00, 0x08, +0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, +0x80, 0x0A, 0x0A, 0x00, 0x00, 0x08, +0x00, 0x04, 0x10, 0x00, 0x00, 0x05, +0x00, 0x03, 0x0E, 0x00, 0x00, 0x0A, +0x00, 0x23, 0x00, 0x00, 0x00, 0x01 +}; + +//R24H b +const unsigned char lut_wb[] = +{ +0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, +0x20, 0x0A, 0x0A, 0x00, 0x00, 0x08, +0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, +0x10, 0x0A, 0x0A, 0x00, 0x00, 0x08, +0x00, 0x04, 0x10, 0x00, 0x00, 0x05, +0x00, 0x03, 0x0E, 0x00, 0x00, 0x0A, +0x00, 0x23, 0x00, 0x00, 0x00, 0x01 +}; + + +/* END OF FILE */