ePaperDisplay (ePD) gde021a1 driver. This ePD is present on the STMicroelectronics Discovery L053 board (STM32L0538-DISCO).
Dependents: DISCO-L053C8_ePD_demo DISCO-L053C8_ePD_demo Ruche_V1 DISCO-L053C8_ePD_demo ... more
GDE021A1 ePaper display Library.
Diff: EPD_GDE021A1.cpp
- Revision:
- 0:5d8241e6bd3b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EPD_GDE021A1.cpp Tue Apr 28 11:37:05 2015 +0000 @@ -0,0 +1,671 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software +* and associated documentation 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 furnished 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 FOR 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 "EPD_GDE021A1.h" + +/** + * @brief GDE021A1 Size + */ +#define GDE021A1_EPD_PIXEL_WIDTH ((uint16_t)172) +#define GDE021A1_EPD_PIXEL_HEIGHT ((uint16_t)18) + +/** + * @brief GDE021A1 Registers + */ +#define EPD_REG_0 0x00 /* Status Read */ +#define EPD_REG_1 0x01 /* Driver Output Control */ +#define EPD_REG_3 0x03 /* Gate driving voltage control */ +#define EPD_REG_4 0x04 /* Source driving coltage control */ +#define EPD_REG_7 0x07 /* Display Control */ +#define EPD_REG_11 0x0B /* Gate and Sorce non overlap period COntrol */ +#define EPD_REG_15 0x0F /* Gate scan start */ +#define EPD_REG_16 0x10 /* Deep Sleep mode setting */ +#define EPD_REG_17 0x11 /* Data Entry Mode Setting */ +#define EPD_REG_18 0x12 /* SWRESET */ +#define EPD_REG_26 0x1A /* Temperature Sensor Control (Write to Temp Register) */ +#define EPD_REG_27 0x1B /* Temperature Sensor Control(Read from Temp Register) */ +#define EPD_REG_28 0x1C /* Temperature Sensor Control(Write Command to Temp sensor) */ +#define EPD_REG_29 0x1D /* Temperature Sensor Control(Load temperature register with temperature sensor reading) */ +#define EPD_REG_32 0x20 /* Master activation */ +#define EPD_REG_33 0x21 /* Display update */ +#define EPD_REG_34 0x22 /* Display update control 2 */ +#define EPD_REG_36 0x24 /* write RAM */ +#define EPD_REG_37 0x25 /* Read RAM */ +#define EPD_REG_40 0x28 /* VCOM sense */ +#define EPD_REG_41 0x29 /* VCOM Sense duration */ +#define EPD_REG_42 0x2A /* VCOM OTP program */ +#define EPD_REG_44 0x2C /* Write VCOMregister */ +#define EPD_REG_45 0x2D /* Read OTP registers */ +#define EPD_REG_48 0x30 /* Program WS OTP */ +#define EPD_REG_50 0x32 /* Write LUT register */ +#define EPD_REG_51 0x33 /* Read LUT register */ +#define EPD_REG_54 0x36 /* Program OTP selection */ +#define EPD_REG_55 0x37 /* Proceed OTP selection */ +#define EPD_REG_58 0x3A /* Set dummy line pulse period */ +#define EPD_REG_59 0x3B /* Set Gate line width */ +#define EPD_REG_60 0x3C /* Select Border waveform */ +#define EPD_REG_68 0x44 /* Set RAM X - Address Start / End Position */ +#define EPD_REG_69 0x45 /* Set RAM Y - Address Start / End Position */ +#define EPD_REG_78 0x4E /* Set RAM X Address Counter */ +#define EPD_REG_79 0x4F /* Set RAM Y Address Counter */ +#define EPD_REG_240 0xF0 /* Booster Set Internal Feedback Selection */ +#define EPD_REG_255 0xFF /* NOP */ + +/* Look-up table for the epaper (90 bytes) */ +const unsigned char WF_LUT[]={ + 0x82,0x00,0x00,0x00,0xAA,0x00,0x00,0x00, + 0xAA,0xAA,0x00,0x00,0xAA,0xAA,0xAA,0x00, + 0x55,0xAA,0xAA,0x00,0x55,0x55,0x55,0x55, + 0xAA,0xAA,0xAA,0xAA,0x55,0x55,0x55,0x55, + 0xAA,0xAA,0xAA,0xAA,0x15,0x15,0x15,0x15, + 0x05,0x05,0x05,0x05,0x01,0x01,0x01,0x01, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x41,0x45,0xF1,0xFF,0x5F,0x55,0x01,0x00, + 0x00,0x00,}; + +// Constructor +EPD_GDE021A1::EPD_GDE021A1(PinName cs, PinName dc, PinName rst, PinName bsy, PinName pwr, PinName spi_mosi, PinName spi_miso, PinName spi_sck) : + _cs(cs, 1), + _dc(dc, 1), + _rst(rst, 1), + _bsy(bsy, PullDown), + _pwr(pwr, 1), + _spi(spi_mosi, spi_miso, spi_sck) +{ + _pwr = 0; + _cs = 0; + _cs = 1; + _rst = 1; + + wait_ms(10); + + _spi.format(8); + _spi.frequency(1000000); + + gde021a1_Init(); + + Clear(EPD_COLOR_WHITE); + + SetFont(&Font12); +} + +// Destructor +EPD_GDE021A1::~EPD_GDE021A1() { } + +//================================================================================================================= +// Public methods +//================================================================================================================= + +uint32_t EPD_GDE021A1::GetXSize(void) +{ + return(gde021a1_GetEpdPixelWidth()); +} + +uint32_t EPD_GDE021A1::GetYSize(void) +{ + return(gde021a1_GetEpdPixelHeight()); +} + +void EPD_GDE021A1::SetFont(sFONT *pFonts) +{ + pFont = pFonts; +} + +sFONT *EPD_GDE021A1::GetFont(void) +{ + return pFont; +} + +void EPD_GDE021A1::Clear(uint16_t Color) +{ + uint32_t index = 0; + + gde021a1_SetDisplayWindow(0, 0, 171, 17); + + for(index = 0; index < 3096; index++) + { + gde021a1_WritePixel(Color); + } +} + +void EPD_GDE021A1::DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii) +{ + Ascii -= 32; + + DrawChar(Xpos, Ypos, &pFont->table[Ascii * ((pFont->Height) * (pFont->Width))]); +} + +void EPD_GDE021A1::DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode) +{ + uint16_t refcolumn = 1, i = 0; + uint32_t size = 0, xsize = 0; + uint8_t *ptr = Text; + + /* Get the text size */ + while (*ptr++) size ++ ; + + /* Characters number per line */ + xsize = (GetXSize()/pFont->Width); + + switch (Mode) + { + case CENTER_MODE: + { + refcolumn = Xpos + ((xsize - size)* pFont->Width) / 2; + break; + } + case LEFT_MODE: + { + refcolumn = Xpos; + break; + } + case RIGHT_MODE: + { + refcolumn = - Xpos + ((xsize - size)*pFont->Width); + break; + } + default: + { + refcolumn = Xpos; + break; + } + } + + /* Send the string character by character on EPD */ + while ((*Text != 0) & (((GetXSize() - (i*pFont->Width)) & 0xFFFF) >= pFont->Width)) + { + /* Display one character on EPD */ + DisplayChar(refcolumn, Ypos, *Text); + /* Decrement the column position by 16 */ + refcolumn += pFont->Width; + /* Point on the next character */ + Text++; + i++; + } +} + +void EPD_GDE021A1::DisplayStringAtLine(uint16_t Line, uint8_t *ptr, Text_AlignModeTypdef Mode) +{ + DisplayStringAt(0, LINE(Line), ptr, Mode); +} + +void EPD_GDE021A1::DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t index = 0; + + gde021a1_SetDisplayWindow(Xpos, Ypos, Xpos + Length, Ypos); + + for(index = 0; index < Length; index++) + { + /* Prepare the register to write data on the RAM */ + gde021a1_WritePixel(0x3F); + } +} + +void EPD_GDE021A1::DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t index = 0; + + gde021a1_SetDisplayWindow(Xpos, Ypos, Xpos, Ypos + Length); + + for(index = 0; index < Length; index++) + { + /* Prepare the register to write data on the RAM */ + gde021a1_WritePixel(0x00); + } +} + +void EPD_GDE021A1::DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Draw horizontal lines */ + DrawHLine(Xpos, Ypos, Width); + DrawHLine(Xpos, (Ypos + Height), (Width + 1)); + + /* Draw vertical lines */ + DrawVLine(Xpos, Ypos, Height); + DrawVLine((Xpos + Width), Ypos , Height); +} + +void EPD_GDE021A1::FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + uint16_t index = 0; + + /* Set the rectangle */ + gde021a1_SetDisplayWindow(Xpos, Ypos, (Xpos + Width), (Ypos + Height)); + + for(index = 0; index < 3096; index++) + { + gde021a1_WritePixel(0xFF); + } +} + +void EPD_GDE021A1::DrawImage(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint16_t Ysize, uint8_t *pdata) +{ + /* Set display window */ + gde021a1_SetDisplayWindow(Xpos, Ypos, (Xpos+Ysize-1), (Ypos+(Xsize/4)-1)); + + gde021a1_DrawImage(Xpos, Ypos, Xsize, Ysize, pdata); + + gde021a1_SetDisplayWindow(0, 0, GetXSize(), GetYSize()); +} + +void EPD_GDE021A1::CloseChargePump(void) +{ + /* Close charge pump */ + gde021a1_CloseChargePump(); + + wait_ms(400); +} + +/** + * @brief Updates the display from the data located into the RAM. + * @param None + * @retval None + */ +void EPD_GDE021A1::RefreshDisplay(void) +{ + gde021a1_RefreshDisplay(); + + /* Poll on the BUSY signal and wait for the EPD to be ready */ + while (_bsy != 0); + + _rst = 1; + + wait_ms(10); +} + +//================================================================================================================= +// Private methods +//================================================================================================================= + +void EPD_GDE021A1::EPD_IO_WriteData(uint16_t RegValue) +{ + _cs = 0; + _dc = 1; + _spi.write(RegValue); + _cs = 1; +} + +void EPD_GDE021A1::EPD_IO_WriteReg(uint8_t Reg) +{ + _cs = 0; + _dc = 0; + _spi.write(Reg); + _cs = 1; +} + +uint16_t EPD_GDE021A1::EPD_IO_ReadData(void) +{ + _cs = 0; + _cs = 1; + return _spi.write(0xFF); +} + +//================================================================================================================= + +/** + * @brief Initialize the GDE021A1 EPD Component. + * @param None + * @retval None + */ +void EPD_GDE021A1::gde021a1_Init(void) +{ + uint8_t nb_bytes = 0; + + EPD_IO_WriteReg(EPD_REG_16); /* Deep sleep mode disable */ + EPD_IO_WriteData(0x00); + EPD_IO_WriteReg(EPD_REG_17); /* Data Entry Mode Setting */ + EPD_IO_WriteData(0x03); + EPD_IO_WriteReg(EPD_REG_68); /* Set the RAM X start/end address */ + EPD_IO_WriteData(0x00); /* RAM X address start = 00h */ + EPD_IO_WriteData(0x11); /* RAM X adress end = 11h (17 * 4pixels by address = 72 pixels) */ + EPD_IO_WriteReg(EPD_REG_69); /* Set the RAM Y start/end address */ + EPD_IO_WriteData(0x00); /* RAM Y address start = 0 */ + EPD_IO_WriteData(0xAB); /* RAM Y adress end = 171 */ + EPD_IO_WriteReg(EPD_REG_78); /* Set RAM X Address counter */ + EPD_IO_WriteData(0x00); + EPD_IO_WriteReg(EPD_REG_79); /* Set RAM Y Address counter */ + EPD_IO_WriteData(0x00); + EPD_IO_WriteReg(EPD_REG_240); /* Booster Set Internal Feedback Selection */ + EPD_IO_WriteData(0x1F); + EPD_IO_WriteReg(EPD_REG_33); /* Disable RAM bypass and set GS transition to GSA = GS0 and GSB = GS3 */ + EPD_IO_WriteData(0x03); + EPD_IO_WriteReg(EPD_REG_44); /* Write VCOMregister */ + EPD_IO_WriteData(0xA0); + EPD_IO_WriteReg(EPD_REG_60); /* Border waveform */ + EPD_IO_WriteData(0x64); + EPD_IO_WriteReg(EPD_REG_50); /* Write LUT register */ + + for (nb_bytes=0; nb_bytes<90; nb_bytes++) + { + EPD_IO_WriteData(WF_LUT[nb_bytes]); + } +} + +/** + * @brief Writes to the selected EPD register. + * @param EPD_Reg: Address of the selected register. + * @param EPD_RegValue: value to write to the selected register. + * @retval None + */ +void EPD_GDE021A1::gde021a1_WriteReg(uint8_t EPD_Reg, uint8_t EPD_RegValue) +{ + EPD_IO_WriteReg(EPD_Reg); + + EPD_IO_WriteData(EPD_RegValue); +} + +/** + * @brief Reads the selected EPD Register. + * @param EPD_Reg: address of the selected register + * @retval EPD Register Value + */ +uint8_t EPD_GDE021A1::gde021a1_ReadReg(uint8_t EPD_Reg) +{ + /* Write 8-bit Index (then Read Reg) */ + EPD_IO_WriteReg(EPD_Reg); + + /* Read 8-bit Reg */ + return (EPD_IO_ReadData()); +} + +/** + * @brief Writes 4 dots. + * @param HEX_Code: specifies the Data to write. + * @retval None + */ +void EPD_GDE021A1::gde021a1_WritePixel(uint8_t HEX_Code) +{ + /* Prepare the register to write data on the RAM */ + EPD_IO_WriteReg(EPD_REG_36); + + /* Send the data to write */ + EPD_IO_WriteData(HEX_Code); +} + +/** + * @brief Displays picture.. + * @param pdata: picture address. + * @param Xpos: Image X position in the EPD + * @param Ypos: Image Y position in the EPD + * @param Xsize: Image X size in the EPD + * @note Xsize have to be a multiple of 4 + * @param Ysize: Image Y size in the EPD + * @retval None + */ +void EPD_GDE021A1::gde021a1_DrawImage(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint16_t Ysize, uint8_t *pdata) +{ + uint32_t i, j = 0; + uint8_t pixels_4 = 0; + uint8_t pixels_4_grey[4] = {0}; + uint8_t nb_4_pixels, data_res = 0; + + /* Prepare the register to write data on the RAM */ + EPD_IO_WriteReg(EPD_REG_36); + + /* X size is a multiple of 8 */ + if ((Xsize % 8) == 0) + { + for (i= 0; i< ((((Ysize) * (Xsize/4)))/2) ; i++) + { + /* Get the current data */ + pixels_4 = pdata[i]; + if (pixels_4 !=0) + { + /* One byte read codes 8 pixels in 1-bit bitmap */ + for (nb_4_pixels = 0; nb_4_pixels < 2; nb_4_pixels++) + { + /* Processing 8 pixels */ + /* Preparing the 4 pixels coded with 4 grey level per pixel + from a monochrome xbm file */ + for (j= 0; j<4; j++) + { + if (((pixels_4) & 0x01) == 1) + { + /* Two LSB is coding black in 4 grey level */ + pixels_4_grey[j] &= 0xFC; + } + else + { + /* Two LSB is coded white in 4 grey level */ + pixels_4_grey[j] |= 0x03; + } + pixels_4 = pixels_4 >> 1; + } + + /* Processing 4 pixels */ + /* Format the data to have the Lower pixel number sent on the MSB for the SPI to fit with the RAM + EPD topology */ + data_res = pixels_4_grey[0] << 6 | pixels_4_grey[1] << 4 | pixels_4_grey[2] << 2 | pixels_4_grey[3] << 0; + + /* Send the data to the EPD's RAM through SPI */ + EPD_IO_WriteData(data_res); + } + } + else + { + /* 1 byte read from xbm files is equivalent to 8 pixels in the + other words 2 bytes to be transferred */ + EPD_IO_WriteData(0xFF); + EPD_IO_WriteData(0xFF); + } + } + } + + /* X size is a multiple of 4 */ + else + { + for (i= 0; i< ((((Ysize) * ((Xsize/4)+1))/2)) ; i++) + { + /* Get the current data */ + pixels_4 = pdata[i]; + if (((i+1) % (((Xsize/4)+1)/2)) != 0) + { + if (pixels_4 !=0) + { + /* One byte read codes 8 pixels in 1-bit bitmap */ + for (nb_4_pixels = 0; nb_4_pixels < 2; nb_4_pixels++) + { + /* Processing 8 pixels */ + /* Preparing the 4 pixels coded with 4 grey level per pixel + from a monochrome xbm file */ + for (j= 0; j<4; j++) + { + if (((pixels_4) & 0x01) == 1) + { + /* Two LSB is coding black in 4 grey level */ + pixels_4_grey[j] &= 0xFC; + } + else + { + /* Two LSB is coded white in 4 grey level */ + pixels_4_grey[j] |= 0x03; + } + pixels_4 = pixels_4 >> 1; + } + + /* Processing 4 pixels */ + /* Format the data to have the Lower pixel number sent on the MSB for the SPI to fit with the RAM + EPD topology */ + data_res = pixels_4_grey[0] << 6 | pixels_4_grey[1] << 4 | pixels_4_grey[2] << 2 | pixels_4_grey[3] << 0; + + /* Send the data to the EPD's RAM through SPI */ + EPD_IO_WriteData(data_res); + } + } + else if (pixels_4 == 0) + { + /* One byte read from xbm files is equivalent to 8 pixels in the + other words Two bytes to be transferred */ + EPD_IO_WriteData(0xFF); + EPD_IO_WriteData(0xFF); + } + } + + else if (((i+1) % (((Xsize/4)+1)/2)) == 0) + { + if (pixels_4 !=0xf0) + { + /* Processing 8 pixels */ + /* Preparing the 4 pixels coded with 4 grey level per pixel + from a monochrome xbm file */ + for (j= 0; j<4; j++) + { + if (((pixels_4) & 0x01) == 1) + { + /* 2 LSB is coding black in 4 grey level */ + pixels_4_grey[j] &= 0xFC; + } + else + { + /* 2 LSB is coded white in 4 grey level */ + pixels_4_grey[j] |= 0x03; + } + pixels_4 = pixels_4 >> 1; + } + + /* Processing 4 pixels */ + /* Format the data to have the Lower pixel number sent on the MSB for the SPI to fit with the RAM + EPD topology */ + data_res = pixels_4_grey[0] << 6 | pixels_4_grey[1] << 4 | pixels_4_grey[2] << 2 | pixels_4_grey[3] << 0; + + /* Send the data to the EPD's RAM through SPI */ + EPD_IO_WriteData(data_res); + } + else if (pixels_4 == 0xf0) + { + /* One byte to be transferred */ + EPD_IO_WriteData(0xFF); + } + } + } + } +} + +/** + * @brief Activates display update sequence. + * @param None + * @retval None + */ +void EPD_GDE021A1::gde021a1_RefreshDisplay(void) +{ + /* Write on the Display update control register */ + EPD_IO_WriteReg(EPD_REG_34); + + /* Display update data sequence option */ + EPD_IO_WriteData(0xC4); + + /* Launching the update: Nothing should interrupt this sequence in order + to avoid display corruption */ + EPD_IO_WriteReg(EPD_REG_32); +} + +/** + * @brief Disables the clock and the charge pump. + * @param None + * @retval None + */ +void EPD_GDE021A1::gde021a1_CloseChargePump(void) +{ + /* Write on the Display update control register */ + EPD_IO_WriteReg(EPD_REG_34); + + /* Disable CP then Disable Clock signal */ + EPD_IO_WriteData(0x03); + + /* Launching the update: Nothing should interrupt this sequence in order + to avoid display corruption */ + EPD_IO_WriteReg(EPD_REG_32); +} + +/** + * @brief Sets a display window. + * @param Xpos: specifies the X bottom left position. + * @param Ypos: specifies the Y bottom left position. + * @param Width: display window width. + * @param Height: display window height. + * @retval None +*/ +void EPD_GDE021A1::gde021a1_SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Set Y position and the height */ + EPD_IO_WriteReg(EPD_REG_68); + EPD_IO_WriteData(Ypos); + EPD_IO_WriteData(Height); + /* Set X position and the width */ + EPD_IO_WriteReg(EPD_REG_69); + EPD_IO_WriteData(Xpos); + EPD_IO_WriteData(Width); + /* Set the height counter */ + EPD_IO_WriteReg(EPD_REG_78); + EPD_IO_WriteData(Ypos); + /* Set the width counter */ + EPD_IO_WriteReg(EPD_REG_79); + EPD_IO_WriteData(Xpos); +} + +/** + * @brief Gets the EPD pixel Width. + * @param None + * @retval The EPD Pixel Width + */ +uint16_t EPD_GDE021A1::gde021a1_GetEpdPixelWidth(void) +{ + return GDE021A1_EPD_PIXEL_WIDTH; +} + +/** + * @brief Gets the EPD pixel Height. + * @param None + * @retval The EPD Pixel Height + */ +uint16_t EPD_GDE021A1::gde021a1_GetEpdPixelHeight(void) +{ + return GDE021A1_EPD_PIXEL_HEIGHT; +} + +/** + * @brief Draws a character on EPD. + * @param Xpos: specifies the X position, can be a value from 0 to 171 + * @param Ypos: specifies the Y position, can be a value from 0 to 17 + * @param c: pointer to the character data + * @retval None + */ +void EPD_GDE021A1::DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c) +{ + uint32_t index = 0; + uint32_t data_length = 0; + uint16_t height = 0; + uint16_t width = 0; + + width = pFont->Width; + height = pFont->Height; + + /* Set the Character display window */ + gde021a1_SetDisplayWindow(Xpos, Ypos, (Xpos + width - 1), (Ypos + height - 1)); + + data_length = (height * width); + + for(index = 0; index < data_length; index++) + { + gde021a1_WritePixel(c[index]); + } +}