diff --git a/lib/waveshare_epd/DEV_Config_32.so b/lib/waveshare_epd/DEV_Config_32.so new file mode 100644 index 0000000..76251ce Binary files /dev/null and b/lib/waveshare_epd/DEV_Config_32.so differ diff --git a/lib/waveshare_epd/DEV_Config_64.so b/lib/waveshare_epd/DEV_Config_64.so new file mode 100644 index 0000000..c3886c0 Binary files /dev/null and b/lib/waveshare_epd/DEV_Config_64.so differ diff --git a/lib/waveshare_epd/__init__.pyc b/lib/waveshare_epd/__init__.pyc index 8fe76c8..f7d5914 100644 Binary files a/lib/waveshare_epd/__init__.pyc and b/lib/waveshare_epd/__init__.pyc differ diff --git a/lib/waveshare_epd/epd13in3b.py b/lib/waveshare_epd/epd13in3b.py new file mode 100644 index 0000000..f6b677b --- /dev/null +++ b/lib/waveshare_epd/epd13in3b.py @@ -0,0 +1,299 @@ +# ***************************************************************************** +# * | File : epd13in3b.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2024-04-08 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 960 +EPD_HEIGHT = 680 + +GRAY1 = 0xff #white +GRAY2 = 0xC0 +GRAY3 = 0x80 #gray +GRAY4 = 0x00 #Blackest + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + if (epdconfig.module_init() != 0): + return -1 + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.SPI.writebytes2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + busy = epdconfig.digital_read(self.busy_pin) + while(busy == 1): + busy = epdconfig.digital_read(self.busy_pin) + epdconfig.delay_ms(20) + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xF7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Part(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xFF) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def init(self): + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x0C) + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0x80) + + self.send_command(0x01) + self.send_data(0xA7) + self.send_data(0x02) + self.send_data(0x00) + + self.send_command(0x11) + self.send_data(0x03) + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0xBF) + self.send_data(0x03) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0xA7) + self.send_data(0x02) + + self.send_command(0x3C) + self.send_data(0x01) + + self.send_command(0x18) + self.send_data(0x80) + + self.send_command(0x4E) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + # EPD hardware init end + return 0 + + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if imwidth == self.width and imheight == self.height: + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif imwidth == self.height and imheight == self.width: + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def Clear(self): + self.send_command(0x24) + self.send_data2([0xFF] * (int(self.width/8) * self.height)) + self.send_command(0x26) + self.send_data2([0x00] * (int(self.width/8) * self.height)) + + self.TurnOnDisplay() + + def Clear_Base(self): + self.send_command(0x24) + self.send_data2([0xFF] * (int(self.width/8) * self.height)) + self.send_command(0x26) + self.send_data2([0x00] * (int(self.width/8) * self.height)) + + self.TurnOnDisplay() + self.send_command(0x26) + self.send_data2([0xFF] * (int(self.width/8) * self.height)) + + def display(self, blackimage, ryimage): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + if (blackimage != None): + self.send_command(0x24) + self.send_data2(blackimage) + if (ryimage != None): + for j in range(Height): + for i in range(Width): + ryimage[i + j * Width] = ~ryimage[i + j * Width] + self.send_command(0x26) + self.send_data2(ryimage) + + self.TurnOnDisplay() + + def display_Base(self, blackimage, ryimage): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + if (blackimage != None): + self.send_command(0x24) + self.send_data2(blackimage) + if (ryimage != None): + for j in range(Height): + for i in range(Width): + ryimage[i + j * Width] = ~ryimage[i + j * Width] + self.send_command(0x26) + self.send_data2(ryimage) + + self.TurnOnDisplay() + + self.send_command(0x26) + self.send_data2(blackimage) + + def display_Partial(self, Image, Xstart, Ystart, Xend, Yend): + if((Xstart % 8 + Xend % 8 == 8 & Xstart % 8 > Xend % 8) | Xstart % 8 + Xend % 8 == 0 | (Xend - Xstart)%8 == 0): + Xstart = Xstart // 8 + Xend = Xend // 8 + else: + Xstart = Xstart // 8 + if Xend % 8 == 0: + Xend = Xend // 8 + else: + Xend = Xend // 8 + 1 + + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + + Xend -= 1 + Yend -= 1 + + self.send_command(0x3C) + self.send_data(0x80) + + self.send_command(0x44) + self.send_data((Xstart*8) & 0xff) + self.send_data((Xstart>>5) & 0x01) + self.send_data((Xend*8) & 0xff) + self.send_data((Xend>>5) & 0x01) + self.send_command(0x45) + self.send_data(Ystart & 0xff) + self.send_data((Ystart>>8) & 0x01) + self.send_data(Yend & 0xff) + self.send_data((Yend>>8) & 0x01) + + self.send_command(0x4E) + self.send_data((Xstart*8) & 0xff) + self.send_data((Xstart>>5) & 0x01) + self.send_command(0x4F) + self.send_data(Ystart & 0xff) + self.send_data((Ystart>>8) & 0x01) + + self.send_command(0x24) + for j in range(Height): + for i in range(Width): + if((j > Ystart-1) & (j < (Yend + 1)) & (i > Xstart-1) & (i < (Xend + 1))): + self.send_data(Image[i + j * Width]) + self.TurnOnDisplay_Part() + + self.send_command(0x26) + for j in range(Height): + for i in range(Width): + if((j > Ystart-1) & (j < (Yend + 1)) & (i > Xstart-1) & (i < (Xend + 1))): + self.send_data(Image[i + j * Width]) + + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP + self.send_data(0x03) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### diff --git a/lib/waveshare_epd/epd13in3k.py b/lib/waveshare_epd/epd13in3k.py new file mode 100644 index 0000000..9106127 --- /dev/null +++ b/lib/waveshare_epd/epd13in3k.py @@ -0,0 +1,523 @@ +# ***************************************************************************** +# * | File : epd13in3k.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2023-09-08 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 960 +EPD_HEIGHT = 680 + +GRAY1 = 0xff #white +GRAY2 = 0xC0 +GRAY3 = 0x80 #gray +GRAY4 = 0x00 #Blackest + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.GRAY1 = GRAY1 #white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 #gray + self.GRAY4 = GRAY4 #Blackest + + self.Lut_Partial=[ + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, + 0x0A, 0x00, 0x05, 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, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, + 0x22, 0x22, 0x22, 0x22, 0x22, + 0x17, 0x41, 0xA8, 0x32, 0x18, + 0x00, 0x00,] + + self.LUT_DATA_4Gray =[ + 0x80, 0x48, 0x4A, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x48, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x48, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA8, 0x48, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x23, 0x17, 0x02, 0x00, + 0x05, 0x01, 0x05, 0x01, 0x02, + 0x08, 0x02, 0x01, 0x04, 0x04, + 0x00, 0x02, 0x00, 0x02, 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, 0x01, + 0x22, 0x22, 0x22, 0x22, 0x22, + 0x17, 0x41, 0xA8, 0x32, 0x30, + 0x00, 0x00,] + + if (epdconfig.module_init() != 0): + return -1 + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.SPI.writebytes2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + busy = epdconfig.digital_read(self.busy_pin) + while(busy == 1): + busy = epdconfig.digital_read(self.busy_pin) + epdconfig.delay_ms(20) + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xF7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Part(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xCF) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_4GRAY(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xC7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def Lut(self, LUT): + self.send_command(0x32) + for i in range(105): + self.send_data(LUT[i]) + + self.send_command(0x03) + self.send_data(LUT[105]) + + self.send_command(0x04) + self.send_data(LUT[106]) + self.send_data(LUT[107]) + self.send_data(LUT[108]) + + self.send_command(0x2C) + self.send_data(LUT[109]) + + def init(self): + + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x0C) + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0x80) + + self.send_command(0x01) + self.send_data(0xA7) + self.send_data(0x02) + self.send_data(0x00) + + self.send_command(0x11) + self.send_data(0x03) + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0xBF) + self.send_data(0x03) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0xA7) + self.send_data(0x02) + + self.send_command(0x3C) + self.send_data(0x05) + + self.send_command(0x18) + self.send_data(0x80) + + self.send_command(0x4E) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + + # EPD hardware init end + return 0 + + def init_Part(self): + self.reset() + + self.send_command(0x3C) + self.send_data(0x80) + + self.Lut(self.Lut_Partial) + + self.send_command(0x37) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x40) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x3C) + self.send_data(0x80) + + self.send_command(0x22) + self.send_data(0xC0) + self.send_command(0x20) + + self.ReadBusy() + def init_4GRAY(self): + self.reset() + + self.ReadBusy() + self.send_command(0x12) + self.ReadBusy() + + self.send_command(0x0C) + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0x80) + + self.send_command(0x01) + self.send_data(0xA7) + self.send_data(0x02) + self.send_data(0x00) + + self.send_command(0x11) + self.send_data(0x03) + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0xBF) + self.send_data(0x03) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0xA7) + self.send_data(0x02) + + self.send_command(0x3C) + self.send_data(0x00) + + self.send_command(0x18) + self.send_data(0x80) + + self.send_command(0x4E) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + + self.Lut(self.LUT_DATA_4Gray) + + self.ReadBusy() + + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if imwidth == self.width and imheight == self.height: + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif imwidth == self.height and imheight == self.width: + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i=0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = self.height - x - 1 + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + return buf + + def Clear(self): + buf = [0xFF] * (int(self.width/8) * self.height) + self.send_command(0x24) + self.send_data2(buf) + + self.TurnOnDisplay() + + def display(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.TurnOnDisplay() + + def display_Base(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.send_command(0x26) + self.send_data2(image) + + self.TurnOnDisplay() + + def display_Base_color(self, color): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + self.send_command(0x24) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(color) + + self.send_command(0x26) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(color) + # self.TurnOnDisplay() + + def display_Partial(self, Image, Xstart, Ystart, Xend, Yend): + if((Xstart % 8 + Xend % 8 == 8 & Xstart % 8 > Xend % 8) | Xstart % 8 + Xend % 8 == 0 | (Xend - Xstart)%8 == 0): + Xstart = Xstart // 8 + Xend = Xend // 8 + else: + Xstart = Xstart // 8 + if Xend % 8 == 0: + Xend = Xend // 8 + else: + Xend = Xend // 8 + 1 + + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + + Xend -= 1 + Yend -= 1 + + self.send_command(0x44) + self.send_data((Xstart*8) & 0xff) + self.send_data((Xstart>>5) & 0x01) + self.send_data((Xend*8) & 0xff) + self.send_data((Xend>>5) & 0x01) + self.send_command(0x45) + self.send_data(Ystart & 0xff) + self.send_data((Ystart>>8) & 0x01) + self.send_data(Yend & 0xff) + self.send_data((Yend>>8) & 0x01) + + self.send_command(0x4E) + self.send_data((Xstart*8) & 0xff) + self.send_data((Xstart>>5) & 0x01) + self.send_command(0x4F) + self.send_data(Ystart & 0xff) + self.send_data((Ystart>>8) & 0x01) + + self.send_command(0x24) + for j in range(Height): + for i in range(Width): + if((j > Ystart-1) & (j < (Yend + 1)) & (i > Xstart-1) & (i < (Xend + 1))): + self.send_data(Image[i + j * Width]) + self.TurnOnDisplay_Part() + + def display_4Gray(self, image): + self.send_command(0x24) + for i in range(0, 81600): + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else: #0x40 + temp3 |= 0x00 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else : #0x40 + temp3 |= 0x00 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0x26) + for i in range(0, 81600): + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.TurnOnDisplay_4GRAY() + + + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP + self.send_data(0x03) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### diff --git a/lib/waveshare_epd/epd1in02.py b/lib/waveshare_epd/epd1in02.py index 489e549..2118227 100644 --- a/lib/waveshare_epd/epd1in02.py +++ b/lib/waveshare_epd/epd1in02.py @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 80 EPD_HEIGHT = 128 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -109,7 +111,7 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") self.send_command(0x71) busy = epdconfig.digital_read(self.busy_pin) busy =not(busy & 0x01) @@ -118,7 +120,7 @@ class EPD: busy = epdconfig.digital_read(self.busy_pin) busy =not(busy & 0x01) epdconfig.delay_ms(800) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def TurnOnDisplay(self): self.send_command(0x12) @@ -242,14 +244,14 @@ class EPD: imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() if(imwidth == self.width and imheight == self.height): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): newx = y @@ -258,14 +260,14 @@ class EPD: buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) return buf - def Display(self, image): + def display(self, image): if (image == None): return - # Width = (self.width % 8 == 0)? (self.width / 8 ): (self.width / 8 + 1) + # Width = (self.width % 8 == 0)? (self.width // 8 ): (self.width // 8 + 1) if(self.width % 8 == 0): - Width = self.width / 8 + Width = self.width // 8 else: - Width = self.width / 8 + 1 + Width = self.width // 8 + 1 self.send_command(0x10) for j in range(0, self.height): @@ -279,11 +281,11 @@ class EPD: self.TurnOnDisplay() def Clear(self): - # Width = (self.width % 8 == 0)? (self.width / 8 ): (self.width / 8 + 1) + # Width = (self.width % 8 == 0)? (self.width // 8 ): (self.width // 8 + 1) if(self.width % 8 == 0): - Width = self.width / 8 + Width = self.width // 8 else: - Width = self.width / 8 + 1 + Width = self.width // 8 + 1 Height = self.height @@ -310,11 +312,11 @@ class EPD: self.send_data(127) #y-end self.send_data(0x00) - # Width = (self.width % 8 == 0)? (self.width / 8 ): (self.width / 8 + 1) + # Width = (self.width % 8 == 0)? (self.width // 8 ): (self.width // 8 + 1) if(self.width % 8 == 0): - Width = self.width / 8 + Width = self.width // 8 else: - Width = self.width / 8 + 1 + Width = self.width // 8 + 1 Height = self.height # send data diff --git a/lib/waveshare_epd/epd1in54.py b/lib/waveshare_epd/epd1in54.py index 6792fad..7959033 100644 --- a/lib/waveshare_epd/epd1in54.py +++ b/lib/waveshare_epd/epd1in54.py @@ -86,6 +86,8 @@ from . import epdconfig EPD_WIDTH = 200 EPD_HEIGHT = 200 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -131,10 +133,10 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def TurnOnDisplay(self): self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 @@ -206,14 +208,14 @@ class EPD: imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() if(imwidth == self.width and imheight == self.height): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): newx = y @@ -234,7 +236,7 @@ class EPD: self.send_data(image[i + j * int(self.width / 8)]) self.TurnOnDisplay() - def Clear(self, color): + def Clear(self, color=0xFF): # self.SetWindow(0, 0, self.width - 1, self.height - 1) # send the color data self.SetWindow(0, 0, self.width, self.height) diff --git a/lib/waveshare_epd/epd1in54_V2.py b/lib/waveshare_epd/epd1in54_V2.py index 8b5213a..8fc8122 100644 --- a/lib/waveshare_epd/epd1in54_V2.py +++ b/lib/waveshare_epd/epd1in54_V2.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V1 -# * | Date : 2019-06-20 +# * | This version: V1.1 +# * | Date : 2022-08-10 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -34,6 +34,8 @@ from . import epdconfig EPD_WIDTH = 200 EPD_HEIGHT = 200 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -88,29 +90,6 @@ class EPD: 0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0, 0x02,0x17,0x41,0xB0,0x32,0x28, ] - - # waveform partial refresh(quality) - WF_PARTIAL_1IN54_1 = [ - 0x0,0x00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0xA,0x0,0x0,0x0,0x0,0x0,0x1, - 0x1,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0, - 0x22,0x17,0x41,0x0,0x32,0x20, - ] # Hardware reset def reset(self): @@ -132,12 +111,19 @@ class EPD: epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 1): epdconfig.delay_ms(20) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def TurnOnDisplay(self): self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 @@ -153,8 +139,7 @@ class EPD: def lut(self, lut): self.send_command(0x32) # WRITE_LUT_REGISTER - for i in range(0, len(lut)): - self.send_data(lut[i]) + self.send_data2(lut) def set_lut(self, lut): self.lut(lut) @@ -186,19 +171,19 @@ class EPD: def SetCursor(self, Xstart, Ystart): - self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER - self.send_data(Xstart & 0xFF) + self.send_command(0x4E); # SET_RAM_X_ADDRESS_COUNTER + self.send_data(Xstart & 0xFF); - self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER - self.send_data(Ystart & 0xFF) - self.send_data((Ystart >> 8) & 0xFF) + self.send_command(0x4F); # SET_RAM_Y_ADDRESS_COUNTER + self.send_data(Ystart & 0xFF); + self.send_data((Ystart >> 8) & 0xFF); def init(self, isPartial): if (epdconfig.module_init() != 0): return -1 if(isPartial): - logging.debug("partial refresh") + logger.debug("partial refresh") self.reset() self.ReadBusy() @@ -225,7 +210,7 @@ class EPD: self.ReadBusy() else: - logging.debug("full refresh") + logger.debug("full refresh") # EPD hardware init start self.reset() @@ -259,11 +244,14 @@ class EPD: self.set_lut(self.WF_Full_1IN54) # Set lut - def Clear(self, color): + def Clear(self, color=0xFF): + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + self.send_command(0x24) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(color) + self.send_data2([color] * self.height * linewidth) self.TurnOnDisplay() @@ -273,14 +261,14 @@ class EPD: imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() if(imwidth == self.width and imheight == self.height): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): newx = y @@ -294,9 +282,7 @@ class EPD: return self.send_command(0x24) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(image[i + j * int(self.width / 8)]) + self.send_data2(image) self.TurnOnDisplay() def displayPartBaseImage(self, image): @@ -304,25 +290,19 @@ class EPD: return self.send_command(0x24) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(image[i + j * int(self.width / 8)]) + self.send_data2(image) self.send_command(0x26) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(image[i + j * int(self.width / 8)]) + self.send_data2(image) - self.TurnOnDisplayPart() + self.TurnOnDisplay() def displayPart(self, image): if (image == None): return self.send_command(0x24) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(image[i + j * int(self.width / 8)]) + self.send_data2(image) self.TurnOnDisplayPart() diff --git a/lib/waveshare_epd/epd1in54b.py b/lib/waveshare_epd/epd1in54b.py index c240fe3..fe8fa17 100644 --- a/lib/waveshare_epd/epd1in54b.py +++ b/lib/waveshare_epd/epd1in54b.py @@ -34,6 +34,8 @@ from . import epdconfig EPD_WIDTH = 200 EPD_HEIGHT = 200 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -74,10 +76,10 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def set_lut_bw(self): self.send_command(0x20) # vcom diff --git a/lib/waveshare_epd/epd1in54b_V2.py b/lib/waveshare_epd/epd1in54b_V2.py index ae40ba9..1575749 100644 --- a/lib/waveshare_epd/epd1in54b_V2.py +++ b/lib/waveshare_epd/epd1in54b_V2.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V4.0 -# * | Date : 2019-06-20 +# * | This version: V4.1 +# * | Date : 2022-08-10 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -34,6 +34,8 @@ from . import epdconfig EPD_WIDTH = 200 EPD_HEIGHT = 200 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -64,12 +66,19 @@ class EPD: epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 1): epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -132,17 +141,25 @@ class EPD: return buf def display(self, blackimage, redimage): + + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + + buf = [0x00] * self.height * linewidth + # send black data if (blackimage != None): self.send_command(0x24) # DATA_START_TRANSMISSION_1 - for i in range(0, int(self.width * self.height / 8)): - self.send_data(blackimage[i]) + self.send_data2(blackimage) # send red data if (redimage != None): self.send_command(0x26) # DATA_START_TRANSMISSION_2 for i in range(0, int(self.width * self.height / 8)): - self.send_data(~redimage[i]) + buf[i] = ~redimage[i] + self.send_data2(buf) self.send_command(0x22) # DISPLAY_REFRESH self.send_data(0xF7) @@ -150,13 +167,16 @@ class EPD: self.ReadBusy() def Clear(self): + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + self.send_command(0x24) # DATA_START_TRANSMISSION_1 - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xFF) + self.send_data2([0xff] * int(self.height * linewidth)) self.send_command(0x26) # DATA_START_TRANSMISSION_2 - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00) + self.send_data2([0x00] * int(self.height * linewidth)) self.send_command(0x22) # DISPLAY_REFRESH self.send_data(0xF7) diff --git a/lib/waveshare_epd/epd1in54c.py b/lib/waveshare_epd/epd1in54c.py index c809ca8..9b2bbb6 100644 --- a/lib/waveshare_epd/epd1in54c.py +++ b/lib/waveshare_epd/epd1in54c.py @@ -33,6 +33,8 @@ from . import epdconfig EPD_WIDTH = 152 EPD_HEIGHT = 152 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -64,10 +66,10 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy epdconfig.delay_ms(200) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -101,14 +103,14 @@ class EPD: imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() if(imwidth == self.width and imheight == self.height): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): newx = y @@ -119,11 +121,11 @@ class EPD: def display(self, blackimage, yellowimage): self.send_command(0x10) - logging.debug("blackimage") + logger.debug("blackimage") for i in range(0, int(self.width * self.height / 8)): self.send_data(blackimage[i]) self.send_command(0x13) - logging.debug("yellowimage") + logger.debug("yellowimage") for i in range(0, int(self.width * self.height / 8)): self.send_data(yellowimage[i]) diff --git a/lib/waveshare_epd/epd1in64g.py b/lib/waveshare_epd/epd1in64g.py new file mode 100644 index 0000000..433ead8 --- /dev/null +++ b/lib/waveshare_epd/epd1in64g.py @@ -0,0 +1,240 @@ +# ***************************************************************************** +# * | File : epd1in64g.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1 +# * | Date : 2022-07-20 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# ******************************************************************************/ +# 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. +# + +import logging +from . import epdconfig + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 168 +EPD_HEIGHT = 168 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.BLACK = 0x000000 # 00 BGR + self.WHITE = 0xffffff # 01 + self.YELLOW = 0x00ffff # 10 + self.RED = 0x0000ff # 11 + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) # module reset + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusyH(self): + logger.debug("e-Paper busy H") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(5) + logger.debug("e-Paper busy H release") + + def ReadBusyL(self): + logger.debug("e-Paper busy L") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: busy, 1: idle + epdconfig.delay_ms(5) + logger.debug("e-Paper busy L release") + + def TurnOnDisplay(self): + self.send_command(0x12) # DISPLAY_REFRESH + self.send_data(0x01) + self.ReadBusyH() + + self.send_command(0x02) # POWER_OFF + self.send_data(0X00) + self.ReadBusyH() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + + self.reset() + + self.send_command(0x66) + self.send_data(0x49) + self.send_data(0x55) + self.send_data(0x13) + self.send_data(0x5D) + + self.send_command(0x66) + self.send_data(0x49) + self.send_data(0x55) + + self.send_command(0xB0) + self.send_data(0x03) + + self.send_command(0x00) + self.send_data(0x4F) + self.send_data(0x6B) + + self.send_command(0x03) + self.send_data(0x00) + + self.send_command(0xF0) + self.send_data(0xF6) + self.send_data(0x0D) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x06) + self.send_data(0xCF) + self.send_data(0xDF) + self.send_data(0x0F) + + self.send_command(0x41) + self.send_data(0x00) + + self.send_command(0x50) + self.send_data(0x30) + + self.send_command(0x60) + self.send_data(0x0C) + self.send_data(0x05) + + self.send_command(0x61) + self.send_data(0xA8) + self.send_data(0x00) + self.send_data(0xA8) + + self.send_command(0x84) + self.send_data(0x01) + return 0 + + def getbuffer(self, image): + # Create a pallette with the 4 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 255,255,0, 255,0,0) + (0,0,0)*252) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 4 colors, dithering if needed + image_4color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_4color = bytearray(image_4color.tobytes('raw')) + + # into a single byte to transfer to the panel + buf = [0x00] * int(self.width * self.height / 4) + idx = 0 + for i in range(0, len(buf_4color), 4): + buf[idx] = (buf_4color[i] << 6) + (buf_4color[i+1] << 4) + (buf_4color[i+2] << 2) + buf_4color[i+3] + idx += 1 + + return buf + + def display(self, image): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x68) + self.send_data(0x01) + + self.send_command(0x04) + self.ReadBusyH() + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(image[i + j * Width]) + + self.send_command(0x68) + self.send_data(0x00) + + self.TurnOnDisplay() + + def Clear(self, color=0x55): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x68) + self.send_data(0x01) + + self.send_command(0x04) + self.ReadBusyH() + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(color) + + self.send_command(0x68) + self.send_data(0x00) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.send_data(0x00) + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd2in13.py b/lib/waveshare_epd/epd2in13.py index 43868ba..f71726f 100644 --- a/lib/waveshare_epd/epd2in13.py +++ b/lib/waveshare_epd/epd2in13.py @@ -30,12 +30,13 @@ import logging from . import epdconfig -import numpy as np # Display resolution EPD_WIDTH = 122 EPD_HEIGHT = 250 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -90,9 +91,9 @@ class EPD: self.send_command(0x20) # MASTER_ACTIVATION self.send_command(0xFF) # TERMINATE_FRAME_READ_WRITE - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") self.ReadBusy() - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self, lut): if (epdconfig.module_init() != 0): @@ -168,14 +169,14 @@ class EPD: pixels = image_monocolor.load() if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): if pixels[x, y] == 0: # x = imwidth - x buf[int(x / 8) + y * linewidth] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -200,7 +201,7 @@ class EPD: self.send_data(image[i + j * linewidth]) self.TurnOnDisplay() - def Clear(self, color): + def Clear(self, color=0xFF): if self.width%8 == 0: linewidth = int(self.width/8) else: diff --git a/lib/waveshare_epd/epd2in13_V2.py b/lib/waveshare_epd/epd2in13_V2.py index db5970c..7d17603 100644 --- a/lib/waveshare_epd/epd2in13_V2.py +++ b/lib/waveshare_epd/epd2in13_V2.py @@ -30,12 +30,13 @@ import logging from . import epdconfig -import numpy as np # Display resolution EPD_WIDTH = 122 EPD_HEIGHT = 250 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -103,6 +104,13 @@ class EPD: epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy @@ -222,14 +230,14 @@ class EPD: pixels = image_monocolor.load() if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): if pixels[x, y] == 0: x = imwidth - x buf[int(x / 8) + y * linewidth] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -241,15 +249,8 @@ class EPD: def display(self, image): - if self.width%8 == 0: - linewidth = int(self.width/8) - else: - linewidth = int(self.width/8) + 1 - self.send_command(0x24) - for j in range(0, self.height): - for i in range(0, linewidth): - self.send_data(image[i + j * linewidth]) + self.send_data2(image) self.TurnOnDisplay() def displayPartial(self, image): @@ -258,47 +259,41 @@ class EPD: else: linewidth = int(self.width/8) + 1 - self.send_command(0x24) + buf = [0x00] * self.height * linewidth for j in range(0, self.height): for i in range(0, linewidth): - self.send_data(image[i + j * linewidth]) + buf[i + j * linewidth] = ~image[i + j * linewidth] + + self.send_command(0x24) + self.send_data2(image) self.send_command(0x26) - for j in range(0, self.height): - for i in range(0, linewidth): - self.send_data(~image[i + j * linewidth]) + self.send_data2(buf) self.TurnOnDisplayPart() def displayPartBaseImage(self, image): - if self.width%8 == 0: - linewidth = int(self.width/8) - else: - linewidth = int(self.width/8) + 1 - self.send_command(0x24) - for j in range(0, self.height): - for i in range(0, linewidth): - self.send_data(image[i + j * linewidth]) - + self.send_data2(image) self.send_command(0x26) - for j in range(0, self.height): - for i in range(0, linewidth): - self.send_data(image[i + j * linewidth]) + self.send_data2(image) self.TurnOnDisplay() - def Clear(self, color): + def Clear(self, color=0xFF): if self.width%8 == 0: linewidth = int(self.width/8) else: linewidth = int(self.width/8) + 1 - # logging.debug(linewidth) + # logger.debug(linewidth) - self.send_command(0x24) + buf = [0x00] * self.height * linewidth for j in range(0, self.height): for i in range(0, linewidth): - self.send_data(color) + buf[i + j * linewidth] = color + + self.send_command(0x24) + self.send_data2(buf) # self.send_command(0x26) # for j in range(0, self.height): diff --git a/lib/waveshare_epd/epd2in13_V3.py b/lib/waveshare_epd/epd2in13_V3.py new file mode 100644 index 0000000..2ad9cc0 --- /dev/null +++ b/lib/waveshare_epd/epd2in13_V3.py @@ -0,0 +1,387 @@ +# ***************************************************************************** +# * | File : epd2in13_V3.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.2 +# * | Date : 2022-08-9 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 122 +EPD_HEIGHT = 250 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + lut_partial_update= [ + 0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x80,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x40,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x14,0x0,0x0,0x0,0x0,0x0,0x0, + 0x1,0x0,0x0,0x0,0x0,0x0,0x0, + 0x1,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0, + 0x22,0x17,0x41,0x00,0x32,0x36, + ] + + lut_full_update = [ + 0x80,0x4A,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x40,0x4A,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x80,0x4A,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x40,0x4A,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0xF,0x0,0x0,0x0,0x0,0x0,0x0, + 0xF,0x0,0x0,0xF,0x0,0x0,0x2, + 0xF,0x0,0x0,0x0,0x0,0x0,0x0, + 0x1,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0, + 0x22,0x17,0x41,0x0,0x32,0x36, + ] + + ''' + function :Hardware reset + parameter: + ''' + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + ''' + function :send command + parameter: + command : Command register + ''' + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + ''' + function :send data + parameter: + data : Write data + ''' + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + ''' + function :Wait until the busy_pin goes LOW + parameter: + ''' + def ReadBusy(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(10) + logger.debug("e-Paper busy release") + + ''' + function : Turn On Display + parameter: + ''' + def TurnOnDisplay(self): + self.send_command(0x22) # Display Update Control + self.send_data(0xC7) + self.send_command(0x20) # Activate Display Update Sequence + self.ReadBusy() + + ''' + function : Turn On Display Part + parameter: + ''' + def TurnOnDisplayPart(self): + self.send_command(0x22) # Display Update Control + self.send_data(0x0f) # fast:0x0c, quality:0x0f, 0xcf + self.send_command(0x20) # Activate Display Update Sequence + self.ReadBusy() + + ''' + function : Set lut + parameter: + lut : lut data + ''' + def Lut(self, lut): + self.send_command(0x32) + for i in range(0, 153): + self.send_data(lut[i]) + self.ReadBusy() + + ''' + function : Send lut data and configuration + parameter: + lut : lut data + ''' + def SetLut(self, lut): + self.Lut(lut) + self.send_command(0x3f) + self.send_data(lut[153]) + self.send_command(0x03) # gate voltage + self.send_data(lut[154]) + self.send_command(0x04) # source voltage + self.send_data(lut[155]) # VSH + self.send_data(lut[156]) # VSH2 + self.send_data(lut[157]) # VSL + self.send_command(0x2c) # VCOM + self.send_data(lut[158]) + + ''' + function : Setting the display window + parameter: + xstart : X-axis starting position + ystart : Y-axis starting position + xend : End position of X-axis + yend : End position of Y-axis + ''' + def SetWindow(self, x_start, y_start, x_end, y_end): + self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION + # x point must be the multiple of 8 or the last 3 bits will be ignored + self.send_data((x_start>>3) & 0xFF) + self.send_data((x_end>>3) & 0xFF) + + self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION + self.send_data(y_start & 0xFF) + self.send_data((y_start >> 8) & 0xFF) + self.send_data(y_end & 0xFF) + self.send_data((y_end >> 8) & 0xFF) + + ''' + function : Set Cursor + parameter: + x : X-axis starting position + y : Y-axis starting position + ''' + def SetCursor(self, x, y): + self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER + # x point must be the multiple of 8 or the last 3 bits will be ignored + self.send_data(x & 0xFF) + + self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER + self.send_data(y & 0xFF) + self.send_data((y >> 8) & 0xFF) + + ''' + function : Initialize the e-Paper register + parameter: + ''' + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.ReadBusy() + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x01) #Driver output control + self.send_data(0xf9) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x11) #data entry mode + self.send_data(0x03) + + self.SetWindow(0, 0, self.width-1, self.height-1) + self.SetCursor(0, 0) + + self.send_command(0x3c) + self.send_data(0x05) + + self.send_command(0x21) # Display update control + self.send_data(0x00) + self.send_data(0x80) + + self.send_command(0x18) + self.send_data(0x80) + + self.ReadBusy() + + self.SetLut(self.lut_full_update) + return 0 + + ''' + function : Display images + parameter: + image : Image data + ''' + def getbuffer(self, image): + img = image + imwidth, imheight = img.size + if(imwidth == self.width and imheight == self.height): + img = img.convert('1') + elif(imwidth == self.height and imheight == self.width): + # image has correct dimensions, but needs to be rotated + img = img.rotate(90, expand=True).convert('1') + else: + logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) + # return a blank buffer + return [0x00] * (int(self.width/8) * self.height) + + buf = bytearray(img.tobytes('raw')) + return buf + + ''' + function : Sends the image buffer in RAM to e-Paper and displays + parameter: + image : Image data + ''' + def display(self, image): + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + + self.send_command(0x24) + for j in range(0, self.height): + for i in range(0, linewidth): + self.send_data(image[i + j * linewidth]) + self.TurnOnDisplay() + + ''' + function : Sends the image buffer in RAM to e-Paper and partial refresh + parameter: + image : Image data + ''' + def displayPartial(self, image): + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(1) + epdconfig.digital_write(self.reset_pin, 1) + + self.SetLut(self.lut_partial_update) + self.send_command(0x37) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x40) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x3C) #BorderWavefrom + self.send_data(0x80) + + self.send_command(0x22) + self.send_data(0xC0) + self.send_command(0x20) + self.ReadBusy() + + self.SetWindow(0, 0, self.width - 1, self.height - 1) + self.SetCursor(0, 0) + + self.send_command(0x24) # WRITE_RAM + # for j in range(0, self.height): + # for i in range(0, linewidth): + # self.send_data(image[i + j * linewidth]) + self.send_data2(image) + self.TurnOnDisplayPart() + + ''' + function : Refresh a base image + parameter: + image : Image data + ''' + def displayPartBaseImage(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.send_command(0x26) + self.send_data2(image) + self.TurnOnDisplay() + + ''' + function : Clear screen + parameter: + ''' + def Clear(self, color=0xFF): + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + # logger.debug(linewidth) + + self.send_command(0x24) + self.send_data2([color] * int(self.height * linewidth)) + self.TurnOnDisplay() + + ''' + function : Enter sleep mode + parameter: + ''' + def sleep(self): + self.send_command(0x10) #enter deep sleep + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd2in13_V4.py b/lib/waveshare_epd/epd2in13_V4.py index a3fa1a8..a9fd210 100644 --- a/lib/waveshare_epd/epd2in13_V4.py +++ b/lib/waveshare_epd/epd2in13_V4.py @@ -30,7 +30,6 @@ import logging from . import epdconfig -import numpy as np # Display resolution EPD_WIDTH = 122 diff --git a/lib/waveshare_epd/epd2in13b_V3.py b/lib/waveshare_epd/epd2in13b_V3.py index c053996..fa8e3e1 100644 --- a/lib/waveshare_epd/epd2in13b_V3.py +++ b/lib/waveshare_epd/epd2in13b_V3.py @@ -34,6 +34,8 @@ from . import epdconfig EPD_WIDTH = 104 EPD_HEIGHT = 212 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -65,12 +67,12 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") self.send_command(0x71); while(epdconfig.digital_read(self.busy_pin) == 0): self.send_command(0x71); epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -96,21 +98,21 @@ class EPD: return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y diff --git a/lib/waveshare_epd/epd2in13b_V4.py b/lib/waveshare_epd/epd2in13b_V4.py new file mode 100644 index 0000000..21a7f5e --- /dev/null +++ b/lib/waveshare_epd/epd2in13b_V4.py @@ -0,0 +1,203 @@ +# ***************************************************************************** +# * | File : epd2in13b_V4.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2022-04-21 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 122 +EPD_HEIGHT = 250 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + # hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + # send 1 byte command + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + # send 1 byte data + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + # judge e-Paper whether is busy + def busy(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) != 0): + epdconfig.delay_ms(10) + logger.debug("e-Paper busy release") + + # set the display window + def set_windows(self, xstart, ystart, xend, yend): + self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION + self.send_data((xstart>>3) & 0xff) + self.send_data((xend>>3) & 0xff) + + self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION + self.send_data(ystart & 0xff) + self.send_data((ystart >> 8) & 0xff) + self.send_data(yend & 0xff) + self.send_data((yend >> 8) & 0xff) + + # set the display cursor(origin) + def set_cursor(self, xstart, ystart): + self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER + self.send_data(xstart & 0xff) + + self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER + self.send_data(ystart & 0xff) + self.send_data((ystart >> 8) & 0xff) + + # initialize + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.busy() + self.send_command(0x12) # SWRESET + self.busy() + + self.send_command(0x01) # Driver output control + self.send_data(0xf9) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x11) # data entry mode + self.send_data(0x03) + + self.set_windows(0, 0, self.width - 1, self.height - 1) + self.set_cursor(0, 0) + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x05) + + self.send_command(0x18) # Read built-in temperature sensor + self.send_data(0x80) + + self.send_command(0x21) # Display update control + self.send_data(0x80) + self.send_data(0x80) + + self.busy() + + return 0 + + # turn on display + def ondisplay(self): + self.send_command(0x20) + self.busy() + + # image converted to bytearray + def getbuffer(self, image): + img = image + imwidth, imheight = img.size + if(imwidth == self.width and imheight == self.height): + img = img.convert('1') + elif(imwidth == self.height and imheight == self.width): + # image has correct dimensions, but needs to be rotated + img = img.rotate(90, expand=True).convert('1') + else: + logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) + # return a blank buffer + return [0x00] * (int(self.width/8) * self.height) + + buf = bytearray(img.tobytes('raw')) + return buf + + # display image + def display(self, imageblack, imagered): + self.send_command(0x24) + self.send_data2(imageblack) + + self.send_command(0x26) + self.send_data2(imagered) + + self.ondisplay() + + # display white image + def clear(self): + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + + buf = [0xff] * (int(linewidth * self.height)) + + self.send_command(0x24) + self.send_data2(buf) + + self.send_command(0x26) + self.send_data2(buf) + + self.ondisplay() + + # Compatible with older version functions + def Clear(self): + self.clear() + + # sleep + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP + self.send_data(0x01) # check code + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd2in13bc.py b/lib/waveshare_epd/epd2in13bc.py index 8aad8ff..601ebc6 100644 --- a/lib/waveshare_epd/epd2in13bc.py +++ b/lib/waveshare_epd/epd2in13bc.py @@ -34,6 +34,8 @@ from . import epdconfig EPD_WIDTH = 104 EPD_HEIGHT = 212 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -65,10 +67,10 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -97,21 +99,21 @@ class EPD: return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y diff --git a/lib/waveshare_epd/epd2in13d.py b/lib/waveshare_epd/epd2in13d.py index b83c060..bcdd1e9 100644 --- a/lib/waveshare_epd/epd2in13d.py +++ b/lib/waveshare_epd/epd2in13d.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V4.0 -# * | Date : 2019-06-20 +# * | This version: V4.1 +# * | Date : 2022-08-10 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -37,6 +37,8 @@ import RPi.GPIO as GPIO EPD_WIDTH = 104 EPD_HEIGHT = 212 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -169,12 +171,19 @@ class EPD: epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy self.send_command(0x71) epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def TurnOnDisplay(self): self.send_command(0x12) @@ -225,20 +234,15 @@ class EPD: self.send_data(0x97) self.send_command(0x20) # vcom - for count in range(0, 44): - self.send_data(self.lut_vcomDC[count]) + self.send_data2(self.lut_vcomDC) self.send_command(0x21) # ww -- - for count in range(0, 42): - self.send_data(self.lut_ww[count]) + self.send_data2(self.lut_ww) self.send_command(0x22) # bw r - for count in range(0, 42): - self.send_data(self.lut_bw[count]) + self.send_data2(self.lut_bw) self.send_command(0x23) # wb w - for count in range(0, 42): - self.send_data(self.lut_wb[count]) + self.send_data2(self.lut_wb) self.send_command(0x24) # bb b - for count in range(0, 42): - self.send_data(self.lut_bb[count]) + self.send_data2(self.lut_bb) def SetPartReg(self): self.send_command(0x82) @@ -247,37 +251,32 @@ class EPD: self.send_data(0x47) self.send_command(0x20) # vcom - for count in range(0, 44): - self.send_data(self.lut_vcom1[count]) + self.send_data2(self.lut_vcom1) self.send_command(0x21) # ww -- - for count in range(0, 42): - self.send_data(self.lut_ww1[count]) + self.send_data2(self.lut_ww1) self.send_command(0x22) # bw r - for count in range(0, 42): - self.send_data(self.lut_bw1[count]) + self.send_data2(self.lut_bw1) self.send_command(0x23) # wb w - for count in range(0, 42): - self.send_data(self.lut_wb1[count]) + self.send_data2(self.lut_wb1) self.send_command(0x24) # bb b - for count in range(0, 42): - self.send_data(self.lut_bb1[count]) + self.send_data2(self.lut_bb1) def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -290,14 +289,17 @@ class EPD: if (Image == None): return + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00) + self.send_data2([0x00] * self.height * linewidth) epdconfig.delay_ms(10) self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(image[i]) + self.send_data2(image) epdconfig.delay_ms(10) self.SetFullReg() @@ -317,29 +319,40 @@ class EPD: self.send_data(int(self.height / 256)) self.send_data(self.height % 256 - 1) self.send_data(0x28) - + + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + + buf = [0x00] * self.height * linewidth + + for i in range(self.height * linewidth): + buf[i] = ~image[i] + self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(image[i]) + self.send_data2(image) epdconfig.delay_ms(10) self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(~image[i]) + self.send_data2(buf) epdconfig.delay_ms(10) self.SetPartReg() self.TurnOnDisplay() - def Clear(self, color): + def Clear(self): + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00) + self.send_data2([0x00] * self.height * linewidth) epdconfig.delay_ms(10) self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xFF) + self.send_data2([0xFF] * self.height * linewidth) epdconfig.delay_ms(10) self.SetFullReg() diff --git a/lib/waveshare_epd/epd2in13g.py b/lib/waveshare_epd/epd2in13g.py new file mode 100644 index 0000000..8d3035a --- /dev/null +++ b/lib/waveshare_epd/epd2in13g.py @@ -0,0 +1,242 @@ +# ***************************************************************************** +# * | File : epd2in13g.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2023-05-29 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# ******************************************************************************/ +# 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. +# + +import logging +from . import epdconfig + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 122 +EPD_HEIGHT = 250 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.BLACK = 0x000000 # 00 BGR + self.WHITE = 0xffffff # 01 + self.YELLOW = 0x00ffff # 10 + self.RED = 0x0000ff # 11 + self.Gate_BITS = EPD_HEIGHT + if self.width < 128: + self.Source_BITS = 128 + else: + self.Source_BITS = self.width + + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) # module reset + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy H") + epdconfig.delay_ms(100) + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(5) + logger.debug("e-Paper busy release") + + def SetWindow(self): + self.send_command(0x61) # SET_RAM_X_ADDRESS_START_END_POSITION + # x point must be the multiple of 8 or the last 3 bits will be ignored + self.send_data(int(self.Source_BITS/256)) + self.send_data(self.Source_BITS%256) + self.send_data(int(self.Gate_BITS/256)) + self.send_data(self.Gate_BITS%256) + + def TurnOnDisplay(self): + self.send_command(0x12) # DISPLAY_REFRESH + self.send_data(0X00) + self.ReadBusy() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + + self.reset() + + self.ReadBusy() + self.send_command(0x4D) + self.send_data(0x78) + + self.send_command(0x00) + self.send_data(0x0F) + self.send_data(0x29) + + self.send_command(0x01) + self.send_data(0x07) + self.send_data(0x00) + + self.send_command(0x03) + self.send_data(0x10) + self.send_data(0x54) + self.send_data(0x44) + + self.send_command(0x06) + self.send_data(0x05) + self.send_data(0x00) + self.send_data(0x3F) + self.send_data(0x0A) + self.send_data(0x25) + self.send_data(0x12) + self.send_data(0x1A) + + self.send_command(0x50) + self.send_data(0x37) + + self.send_command(0x60) + self.send_data(0x02) + self.send_data(0x02) + + self.SetWindow() + + self.send_command(0xE7) + self.send_data(0x1C) + + self.send_command(0xE3) + self.send_data(0x22) + + self.send_command(0xB4) + self.send_data(0xD0) + self.send_command(0xB5) + self.send_data(0x03) + + self.send_command(0xE9) + self.send_data(0x01) + + self.send_command(0x30) + self.send_data(0x08) + + self.send_command(0x04) + self.ReadBusy() + return 0 + + def getbuffer(self, image): + # Create a pallette with the 4 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 255,255,0, 255,0,0) + (0,0,0)*252) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 4 colors, dithering if needed + image_4color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_4color = bytearray(image_4color.tobytes('raw')) + + # into a single byte to transfer to the panel + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + buf = [0x00] * int(Width * Height) + idx = 0 + for j in range(0, Height): + for i in range(0, Width): + if i == Width -1: + buf[i + j * Width] = (buf_4color[idx] << 6) + (buf_4color[idx+1] << 4) + idx = idx + 2 + else: + buf[i + j * Width] = (buf_4color[idx] << 6) + (buf_4color[idx+1] << 4) + (buf_4color[idx+2] << 2) + buf_4color[idx+3] + idx = idx + 4 + return buf + + def display(self, image): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, self.Source_BITS//4): + if i < 31 : + self.send_data(image[i + j * Width]) + else : + self.send_data(0x00) + + self.TurnOnDisplay() + + def Clear(self, color=0x55): + Width = self.Source_BITS//4 + Height = self.height + + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(color) + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + epdconfig.delay_ms(100) + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd2in15b.py b/lib/waveshare_epd/epd2in15b.py new file mode 100644 index 0000000..f439b29 --- /dev/null +++ b/lib/waveshare_epd/epd2in15b.py @@ -0,0 +1,204 @@ +# ***************************************************************************** +# * | File : epd2in15b.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2024-08-07 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 160 +EPD_HEIGHT = 296 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + # hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + # send 1 byte command + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + # send 1 byte data + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + # judge e-Paper whether is busy + def busy(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) != 0): + epdconfig.delay_ms(10) + epdconfig.delay_ms(10) + logger.debug("e-Paper busy release") + + # set the display window + def set_windows(self, xstart, ystart, xend, yend): + self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION + self.send_data((xstart>>3) & 0xff) + self.send_data((xend>>3) & 0xff) + + self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION + self.send_data(ystart & 0xff) + self.send_data((ystart >> 8) & 0xff) + self.send_data(yend & 0xff) + self.send_data((yend >> 8) & 0xff) + + # set the display cursor(origin) + def set_cursor(self, xstart, ystart): + self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER + self.send_data(xstart & 0xff) + + self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER + self.send_data(ystart & 0xff) + self.send_data((ystart >> 8) & 0xff) + + # initialize + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.busy() + self.send_command(0x12) # SWRESET + self.busy() + + self.send_command(0x11) # data entry mode + self.send_data(0x03) + + self.set_windows(0, 0, self.width - 1, self.height - 1) + self.set_cursor(0, 0) + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x05) + + self.send_command(0x18) # Read built-in temperature sensor + self.send_data(0x80) + + self.busy() + + return 0 + + # turn on display + def ondisplay(self): + self.send_command(0x20) + self.busy() + + # image converted to bytearray + def getbuffer(self, image): + img = image + imwidth, imheight = img.size + if(imwidth == self.width and imheight == self.height): + img = img.convert('1') + elif(imwidth == self.height and imheight == self.width): + # image has correct dimensions, but needs to be rotated + img = img.rotate(90, expand=True).convert('1') + else: + logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) + # return a blank buffer + return [0x00] * (int(self.width/8) * self.height) + + buf = bytearray(img.tobytes('raw')) + return buf + + # display image + def display(self, imageblack, imagered): + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + + self.send_command(0x24) + self.send_data2(imageblack) + + for j in range(0, self.height): + for i in range(0, linewidth): + imagered[i+j*linewidth] = (~imagered[i+j*linewidth])&0xFF + self.send_command(0x26) + self.send_data2(imagered) + + self.ondisplay() + + # display white image + def clear(self): + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + + buf = [0xff] * (int(linewidth * self.height)) + + self.send_command(0x24) + self.send_data2(buf) + + buf = [0x00] * (int(linewidth * self.height)) + self.send_command(0x26) + self.send_data2(buf) + + self.ondisplay() + + # Compatible with older version functions + def Clear(self): + self.clear() + + # sleep + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP + self.send_data(0x01) # check code + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd2in15g.py b/lib/waveshare_epd/epd2in15g.py new file mode 100644 index 0000000..d55590c --- /dev/null +++ b/lib/waveshare_epd/epd2in15g.py @@ -0,0 +1,239 @@ +# ***************************************************************************** +# * | File : epd2in15g.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2024-08-07 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# ******************************************************************************/ +# 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. +# + +import logging +from . import epdconfig + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 160 +EPD_HEIGHT = 296 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.BLACK = 0x000000 # 00 BGR + self.WHITE = 0xffffff # 01 + self.YELLOW = 0x00ffff # 10 + self.RED = 0x0000ff # 11 + + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) # module reset + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy H") + epdconfig.delay_ms(100) + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(5) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x12) # DISPLAY_REFRESH + self.send_data(0X00) + self.ReadBusy() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + + self.reset() + + self.ReadBusy() + self.send_command(0x4D) + self.send_data(0x78) + + self.send_command(0x00) + self.send_data(0x0F) + self.send_data(0x29) + + self.send_command(0x01) + self.send_data(0x07) + self.send_data(0x00) + + self.send_command(0x03) + self.send_data(0x10) + self.send_data(0x54) + self.send_data(0x44) + + self.send_command(0x06) + self.send_data(0x0F) + self.send_data(0x0A) + self.send_data(0x2F) + self.send_data(0x25) + self.send_data(0x22) + self.send_data(0x2E) + self.send_data(0x21) + + self.send_command(0x30) + self.send_data(0x02) + + self.send_command(0x41) + self.send_data(0x00) + + self.send_command(0x50) + self.send_data(0x37) + + self.send_command(0x60) + self.send_data(0x02) + self.send_data(0x02) + + self.send_command(0x61) + self.send_data(int(self.width/256)) + self.send_data(self.width%256) + self.send_data(int(self.height/256)) + self.send_data(self.height%256) + + self.send_command(0x65) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0XE7) + self.send_data(0x1C) + + self.send_command(0xE3) + self.send_data(0x22) + + self.send_command(0xE0) + self.send_data(0x00) + + self.send_command(0xB4) + self.send_data(0xD0) + self.send_command(0xB5) + self.send_data(0x03) + + self.send_command(0xE9) + self.send_data(0x01) + + self.send_command(0x04) + self.ReadBusy() + return 0 + + def getbuffer(self, image): + # Create a pallette with the 4 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 255,255,0, 255,0,0) + (0,0,0)*252) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 4 colors, dithering if needed + image_4color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_4color = bytearray(image_4color.tobytes('raw')) + + # into a single byte to transfer to the panel + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + buf = [0x00] * int(Width * Height) + idx = 0 + for j in range(0, Height): + for i in range(0, Width): + buf[i + j * Width] = (buf_4color[idx] << 6) + (buf_4color[idx+1] << 4) + (buf_4color[idx+2] << 2) + buf_4color[idx+3] + idx = idx + 4 + return buf + + def display(self, image): + self.send_command(0x10) + self.send_data2(image) + + self.TurnOnDisplay() + + def Clear(self, color=0x55): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(color) + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.send_data(0X00) + epdconfig.delay_ms(100) + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd2in36g.py b/lib/waveshare_epd/epd2in36g.py new file mode 100644 index 0000000..6dcc420 --- /dev/null +++ b/lib/waveshare_epd/epd2in36g.py @@ -0,0 +1,240 @@ +# ***************************************************************************** +# * | File : epd2in36g.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2022-08-17 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# ******************************************************************************/ +# 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. +# + +import logging +from . import epdconfig + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 168 +EPD_HEIGHT = 296 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.BLACK = 0x000000 # 00 BGR + self.WHITE = 0xffffff # 01 + self.YELLOW = 0x00ffff # 10 + self.RED = 0x0000ff # 11 + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) # module reset + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusyH(self): + logger.debug("e-Paper busy H") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(5) + logger.debug("e-Paper busy H release") + + def ReadBusyL(self): + logger.debug("e-Paper busy L") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: busy, 1: idle + epdconfig.delay_ms(5) + logger.debug("e-Paper busy L release") + + def TurnOnDisplay(self): + self.send_command(0x12) # DISPLAY_REFRESH + self.send_data(0x01) + self.ReadBusyH() + + self.send_command(0x02) # POWER_OFF + self.send_data(0X00) + self.ReadBusyH() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + + self.reset() + + self.send_command(0x66) + self.send_data(0x49) + self.send_data(0x55) + self.send_data(0x13) + self.send_data(0x5D) + + self.send_command(0x66) + self.send_data(0x49) + self.send_data(0x55) + + self.send_command(0xB0) + self.send_data(0x03) + + self.send_command(0x00) + self.send_data(0x4F) + self.send_data(0x69) + + self.send_command(0x03) + self.send_data(0x00) + + self.send_command(0xF0) + self.send_data(0xF6) + self.send_data(0x0D) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x06) + self.send_data(0xCF) + self.send_data(0xDE) + self.send_data(0x0F) + + self.send_command(0x41) + self.send_data(0x00) + + self.send_command(0x50) + self.send_data(0x30) + + self.send_command(0x60) + self.send_data(0x0C) + self.send_data(0x05) + + self.send_command(0x61) + self.send_data(0xA8) + self.send_data(0x01) + self.send_data(0x28) + + self.send_command(0x84) + self.send_data(0x01) + return 0 + + def getbuffer(self, image): + # Create a pallette with the 4 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 255,255,0, 255,0,0) + (0,0,0)*252) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 4 colors, dithering if needed + image_4color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_4color = bytearray(image_4color.tobytes('raw')) + + # into a single byte to transfer to the panel + buf = [0x00] * int(self.width * self.height / 4) + idx = 0 + for i in range(0, len(buf_4color), 4): + buf[idx] = (buf_4color[i] << 6) + (buf_4color[i+1] << 4) + (buf_4color[i+2] << 2) + buf_4color[i+3] + idx += 1 + + return buf + + def display(self, image): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x68) + self.send_data(0x01) + + self.send_command(0x04) + self.ReadBusyH() + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(image[i + j * Width]) + + self.send_command(0x68) + self.send_data(0x00) + + self.TurnOnDisplay() + + def Clear(self, color=0x55): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x68) + self.send_data(0x01) + + self.send_command(0x04) + self.ReadBusyH() + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(color) + + self.send_command(0x68) + self.send_data(0x00) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.send_data(0x00) + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd2in66.py b/lib/waveshare_epd/epd2in66.py index abcc33b..cee45dd 100644 --- a/lib/waveshare_epd/epd2in66.py +++ b/lib/waveshare_epd/epd2in66.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V1.0 -# * | Date : 2020-07-22 +# * | This version: V1.1 +# * | Date : 2022-08-9 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -34,6 +34,8 @@ from . import epdconfig EPD_WIDTH = 152 EPD_HEIGHT = 296 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -68,7 +70,7 @@ class EPD: epdconfig.digital_write(self.reset_pin, 1) epdconfig.delay_ms(200) epdconfig.digital_write(self.reset_pin, 0) - epdconfig.delay_ms(5) + epdconfig.delay_ms(2) epdconfig.digital_write(self.reset_pin, 1) epdconfig.delay_ms(200) @@ -86,12 +88,19 @@ class EPD: epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy epdconfig.delay_ms(200) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self, mode): @@ -143,37 +152,37 @@ class EPD: self.ReadBusy() else: - logging.debug("There is no such mode") + logger.debug("There is no such mode") return 0 def load_lut(self, lut): self.send_command(0x32) - for i in range(0, 153): - self.send_data(lut[i]) - + # for i in range(0, 153): + # self.send_data(lut[i]) + self.send_data2(lut) def turnon_display(self): self.send_command(0x20) self.ReadBusy() def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -194,10 +203,7 @@ class EPD: self.send_data(0x01) self.send_command(0x24) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(image[i + j * int(self.width / 8)]) - + self.send_data2(image) self.turnon_display() @@ -208,15 +214,18 @@ class EPD: self.send_data(0x27) self.send_data(0x01) + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + + buf = [0xff] * int(self.height * linewidth) + self.send_command(0x24) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(0xff) + self.send_data2(buf) self.send_command(0x26) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(0xff) + self.send_data2(buf) self.turnon_display() diff --git a/lib/waveshare_epd/epd2in66b.py b/lib/waveshare_epd/epd2in66b.py index 634ee6c..870d866 100644 --- a/lib/waveshare_epd/epd2in66b.py +++ b/lib/waveshare_epd/epd2in66b.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V1.0 -# * | Date : 2020-12-01 +# * | This version: V1.1 +# * | Date : 2022-08-9 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -34,6 +34,8 @@ from . import epdconfig EPD_WIDTH = 152 EPD_HEIGHT = 296 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -66,12 +68,19 @@ class EPD: epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy epdconfig.delay_ms(20) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): @@ -122,21 +131,21 @@ class EPD: self.ReadBusy() def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -147,30 +156,30 @@ class EPD: def display(self, Blackimage, Redimage): if (Blackimage == None or Redimage == None): - return + return + Redimage_1 = [0x00] * len(Redimage) + for i in range(len(Redimage)) : + Redimage_1[i] = ~Redimage[i] self.send_command(0x24) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(Blackimage[i + j * int(self.width / 8)]) + self.send_data2(Blackimage) self.send_command(0x26) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(~Redimage[i + j * int(self.width / 8)]) + self.send_data2(Redimage_1) self.turnon_display() def Clear(self): + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + self.send_command(0x24) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(0xff) + self.send_data2([0xff] * int(self.height * linewidth)) self.send_command(0x26) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(0x00) + self.send_data2([0x00] * int(self.height * linewidth)) self.turnon_display() diff --git a/lib/waveshare_epd/epd2in66g.py b/lib/waveshare_epd/epd2in66g.py new file mode 100644 index 0000000..18d11f5 --- /dev/null +++ b/lib/waveshare_epd/epd2in66g.py @@ -0,0 +1,228 @@ +# ***************************************************************************** +# * | File : epd2in9g.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2023-03-08 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# ******************************************************************************/ +# 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. +# + +import logging +from . import epdconfig + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 184 +EPD_HEIGHT = 360 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.BLACK = 0x000000 # 00 BGR + self.WHITE = 0xffffff # 01 + self.YELLOW = 0x00ffff # 10 + self.RED = 0x0000ff # 11 + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) # module reset + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusyH(self): + logger.debug("e-Paper busy H") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(5) + logger.debug("e-Paper busy H release") + + def ReadBusyL(self): + logger.debug("e-Paper busy L") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: busy, 1: idle + epdconfig.delay_ms(5) + logger.debug("e-Paper busy L release") + + def TurnOnDisplay(self): + self.send_command(0x12) # DISPLAY_REFRESH + self.send_data(0x00) + self.ReadBusyH() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + + self.reset() + self.ReadBusyH() + self.send_command(0x4D) + self.send_data(0x78) + + self.send_command(0x00) #PSR + self.send_data(0x0F) + self.send_data(0x29) + + self.send_command(0x01) #PWRR + self.send_data(0x07) + self.send_data(0x00) + + self.send_command(0x03) #POFS + self.send_data(0x10) + self.send_data(0x54) + self.send_data(0x44) + + self.send_command(0x06) #BTST_P + self.send_data(0x05) + self.send_data(0x00) + self.send_data(0x3F) + self.send_data(0x0A) + self.send_data(0x25) + self.send_data(0x12) + self.send_data(0x1A) + + self.send_command(0x50) #CDI + self.send_data(0x37) + + self.send_command(0x60) #TCON + self.send_data(0x02) + self.send_data(0x02) + + self.send_command(0x61) #TRES + self.send_data(self.width//256) # Source_BITS_H + self.send_data(self.width%256) # Source_BITS_L + self.send_data(self.height//256) # Gate_BITS_H + self.send_data(self.height%256) # Gate_BITS_L + + self.send_command(0xE7) + self.send_data(0x1C) + + self.send_command(0xE3) + self.send_data(0x22) + + self.send_command(0xB4) + self.send_data(0xD0) + self.send_command(0xB5) + self.send_data(0x03) + + self.send_command(0xE9) + self.send_data(0x01) + + self.send_command(0x30) + self.send_data(0x08) + + self.send_command(0x04) + self.ReadBusyH() + return 0 + + def getbuffer(self, image): + # Create a pallette with the 4 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 255,255,0, 255,0,0) + (0,0,0)*252) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 4 colors, dithering if needed + image_4color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_4color = bytearray(image_4color.tobytes('raw')) + + # into a single byte to transfer to the panel + buf = [0x00] * int(self.width * self.height / 4) + idx = 0 + for i in range(0, len(buf_4color), 4): + buf[idx] = (buf_4color[i] << 6) + (buf_4color[i+1] << 4) + (buf_4color[i+2] << 2) + buf_4color[i+3] + idx += 1 + + return buf + + def display(self, image): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(image[i + j * Width]) + + self.TurnOnDisplay() + + def Clear(self, color=0x55): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(color) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.send_data(0X00) + self.ReadBusyH() + epdconfig.delay_ms(2000) + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd2in7.py b/lib/waveshare_epd/epd2in7.py index a62f981..831492b 100644 --- a/lib/waveshare_epd/epd2in7.py +++ b/lib/waveshare_epd/epd2in7.py @@ -38,6 +38,9 @@ GRAY1 = 0xff #white GRAY2 = 0xC0 GRAY3 = 0x80 #gray GRAY4 = 0x00 #Blackest + +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -171,10 +174,10 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy epdconfig.delay_ms(200) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def set_lut(self): self.send_command(0x20) # vcom @@ -361,21 +364,21 @@ class EPD: self.send_data(0x57) def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -385,15 +388,15 @@ class EPD: return buf def getbuffer_4Gray(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width / 4) * self.height) image_monocolor = image.convert('L') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() i=0 - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. @@ -406,7 +409,7 @@ class EPD: buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for x in range(imwidth): for y in range(imheight): newx = y diff --git a/lib/waveshare_epd/epd2in7_V2.py b/lib/waveshare_epd/epd2in7_V2.py new file mode 100644 index 0000000..30074a6 --- /dev/null +++ b/lib/waveshare_epd/epd2in7_V2.py @@ -0,0 +1,519 @@ +# ***************************************************************************** +# * | File : epd2in7_V2.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2022-09-17 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 176 +EPD_HEIGHT = 264 + +GRAY1 = 0xff #white +GRAY2 = 0xC0 +GRAY3 = 0x80 #gray +GRAY4 = 0x00 #Blackest + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.GRAY1 = GRAY1 #white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 #gray + self.GRAY4 = GRAY4 #Blackest + + LUT_DATA_4Gray = [ + 0x40,0x48,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x8,0x48,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x2,0x48,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x20,0x48,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0xA,0x19,0x0,0x3,0x8,0x0,0x0, + 0x14,0x1,0x0,0x14,0x1,0x0,0x3, + 0xA,0x3,0x0,0x8,0x19,0x0,0x0, + 0x1,0x0,0x0,0x0,0x0,0x0,0x1, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0, + 0x22,0x17,0x41,0x0,0x32,0x1C, + ] + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): # 1: idle, 0: busy + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xF7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Fast(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xC7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Partial(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xFF) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_4GRAY(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xC7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def Lut(self): + self.send_command(0x32) + for i in range(159): + self.send_data(self.LUT_DATA_4Gray[i]) + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x45) #set Ram-Y address start/end position + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x07) #0x0107-->(263+1)=264 + self.send_data(0x01) + + self.send_command(0x4F) # set RAM y address count to 0; + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x11) # data entry mode + self.send_data(0x03) + return 0 + + def init_Fast(self): + if (epdconfig.module_init() != 0): + return -1 + + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x18) #Read built-in temperature sensor + self.send_data(0x80) + + self.send_command(0x22) # Load temperature value + self.send_data(0xB1) + self.send_command(0x20) + self.ReadBusy() + + self.send_command(0x1A) # Write to temperature register + self.send_data(0x64) + self.send_data(0x00) + + self.send_command(0x45) #set Ram-Y address start/end position + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x07) #0x0107-->(263+1)=264 + self.send_data(0x01) + + self.send_command(0x4F) # set RAM y address count to 0; + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x11) # data entry mode + self.send_data(0x03) + + self.send_command(0x22) # Load temperature value + self.send_data(0x91) + self.send_command(0x20) + self.ReadBusy() + return 0 + + def Init_4Gray(self): + if (epdconfig.module_init() != 0): + return -1 + self.reset() + + self.send_command(0x12) # soft reset + self.ReadBusy(); + + self.send_command(0x74) #set analog block control + self.send_data(0x54) + self.send_command(0x7E) #set digital block control + self.send_data(0x3B) + + self.send_command(0x01) #Driver output control + self.send_data(0x07) + self.send_data(0x01) + self.send_data(0x00) + + self.send_command(0x11) #data entry mode + self.send_data(0x03) + + self.send_command(0x44) #set Ram-X address start/end position + self.send_data(0x00) + self.send_data(0x15) #0x15-->(21+1)*8=176 + + self.send_command(0x45) #set Ram-Y address start/end position + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x07) #0x0107-->(263+1)=264 + self.send_data(0x01) + + + self.send_command(0x3C) #BorderWavefrom + self.send_data(0x00) + + + self.send_command(0x2C) #VCOM Voltage + self.send_data(self.LUT_DATA_4Gray[158]) #0x1C + + + self.send_command(0x3F) #EOPQ + self.send_data(self.LUT_DATA_4Gray[153]) + + self.send_command(0x03) #VGH + self.send_data(self.LUT_DATA_4Gray[154]) + + self.send_command(0x04) # + self.send_data(self.LUT_DATA_4Gray[155]) #VSH1 + self.send_data(self.LUT_DATA_4Gray[156]) #VSH2 + self.send_data(self.LUT_DATA_4Gray[157]) #VSL + + self.Lut() #LUT + + + self.send_command(0x4E) # set RAM x address count to 0; + self.send_data(0x00) + self.send_command(0x4F) # set RAM y address count to 0X199; + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i=0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = self.height - x - 1 + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + return buf + + def Clear(self): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + self.send_command(0x24) + for j in range(Height): + for i in range(Width): + self.send_data(0XFF) + self.TurnOnDisplay() + + def display(self, image): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + self.send_command(0x24) + for j in range(Height): + for i in range(Width): + self.send_data(image[i + j * Width]) + self.TurnOnDisplay() + + def display_Fast(self, image): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + self.send_command(0x24) + for j in range(Height): + for i in range(Width): + self.send_data(image[i + j * Width]) + self.TurnOnDisplay_Fast() + + def display_Base(self, image): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + self.send_command(0x24) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(image[i + j * Width]) + + self.send_command(0x26) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(image[i + j * Width]) + self.TurnOnDisplay() + + def display_Base_color(self, color): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + self.send_command(0x24) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(color) + + self.send_command(0x26) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(color) + # self.TurnOnDisplay() + + def display_Partial(self, Image, Xstart, Ystart, Xend, Yend): + if((Xstart % 8 + Xend % 8 == 8 & Xstart % 8 > Xend % 8) | Xstart % 8 + Xend % 8 == 0 | (Xend - Xstart)%8 == 0): + Xstart = Xstart // 8 + Xend = Xend // 8 + else: + Xstart = Xstart // 8 + if Xend % 8 == 0: + Xend = Xend // 8 + else: + Xend = Xend // 8 + 1 + + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + + Xend -= 1 + Yend -= 1 + + # Reset + self.reset() + + self.send_command(0x3C) #BorderWavefrom + self.send_data(0x80) + + self.send_command(0x44) # set RAM x address start/end, in page 35 + self.send_data(Xstart & 0xff) # RAM x address start at 00h; + self.send_data(Xend & 0xff) # RAM x address end at 0fh(15+1)*8->128 + self.send_command(0x45) # set RAM y address start/end, in page 35 + self.send_data(Ystart & 0xff) # RAM y address start at 0127h; + self.send_data((Ystart>>8) & 0x01) # RAM y address start at 0127h; + self.send_data(Yend & 0xff) # RAM y address end at 00h; + self.send_data((Yend>>8) & 0x01) + + self.send_command(0x4E) # set RAM x address count to 0; + self.send_data(Xstart & 0xff) + self.send_command(0x4F) # set RAM y address count to 0X127; + self.send_data(Ystart & 0xff) + self.send_data((Ystart>>8) & 0x01) + + self.send_command(0x24) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + if((j > Ystart-1) & (j < (Yend + 1)) & (i > Xstart-1) & (i < (Xend + 1))): + self.send_data(Image[i + j * Width]) + self.TurnOnDisplay_Partial() + + def display_4Gray(self, image): + self.send_command(0x24) + for i in range(0, 5808): #5808*4 46464 + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else: #0x40 + temp3 |= 0x00 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else : #0x40 + temp3 |= 0x00 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0x26) + for i in range(0, 5808): #5808*4 46464 + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.TurnOnDisplay_4GRAY() + + def sleep(self): + self.send_command(0X10) + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd2in7b.py b/lib/waveshare_epd/epd2in7b.py index 8c06ab0..314c828 100644 --- a/lib/waveshare_epd/epd2in7b.py +++ b/lib/waveshare_epd/epd2in7b.py @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 176 EPD_HEIGHT = 264 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -119,10 +121,10 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def set_lut(self): self.send_command(0x20) # vcom @@ -206,21 +208,21 @@ class EPD: return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y diff --git a/lib/waveshare_epd/epd2in7b_V2.py b/lib/waveshare_epd/epd2in7b_V2.py index 556a64c..1538023 100644 --- a/lib/waveshare_epd/epd2in7b_V2.py +++ b/lib/waveshare_epd/epd2in7b_V2.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V1.0 -# * | Date : 2020-10-22 +# * | This version: V1.1 +# * | Date : 2022-08-10 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 176 EPD_HEIGHT = 264 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -66,13 +68,20 @@ class EPD: epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) # Read Busy def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy epdconfig.delay_ms(10) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") # Setting the display window def SetWindows(self, Xstart, Ystart, Xend, Yend): @@ -118,21 +127,21 @@ class EPD: return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -146,25 +155,25 @@ class EPD: Width = self.width / 8 Height = self.height - self.send_command(0x24) + buf = [0x00] * int(Width * Height) for i in range(0, int(Width * Height)): - self.send_data(imageblack[i]) + buf[i] = ~imagered[i] + + self.send_command(0x24) + self.send_data2(imageblack) self.send_command(0x26) - for i in range(0, int(Width * Height)): - self.send_data(~imagered[i]) + self.send_data2(buf) self.TurnOnDisplay() # Clear the screen def Clear(self): self.send_command(0x24) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xff) + self.send_data2([0xff] * int(self.width * self.height / 8)) self.send_command(0x26) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00) + self.send_data2([0x00] * int(self.width * self.height / 8)) self.TurnOnDisplay() diff --git a/lib/waveshare_epd/epd2in9.py b/lib/waveshare_epd/epd2in9.py index 55a8361..3690dd9 100644 --- a/lib/waveshare_epd/epd2in9.py +++ b/lib/waveshare_epd/epd2in9.py @@ -34,6 +34,8 @@ from . import epdconfig EPD_WIDTH = 128 EPD_HEIGHT = 296 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -90,9 +92,9 @@ class EPD: self.send_command(0x20) # MASTER_ACTIVATION self.send_command(0xFF) # TERMINATE_FRAME_READ_WRITE - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") self.ReadBusy() - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def SetWindow(self, x_start, y_start, x_end, y_end): self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION @@ -149,21 +151,21 @@ class EPD: return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -183,7 +185,7 @@ class EPD: self.send_data(image[i + j * int(self.width / 8)]) self.TurnOnDisplay() - def Clear(self, color): + def Clear(self, color=0xFF): self.SetWindow(0, 0, self.width - 1, self.height - 1) for j in range(0, self.height): self.SetCursor(0, j) diff --git a/lib/waveshare_epd/epd2in9_V2.py b/lib/waveshare_epd/epd2in9_V2.py index 67dcdcd..d84510b 100644 --- a/lib/waveshare_epd/epd2in9_V2.py +++ b/lib/waveshare_epd/epd2in9_V2.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V1.0 -# * | Date : 2020-10-20 +# * | This version: V1.1 +# * | Date : 2022-08-9 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -33,6 +33,12 @@ from . import epdconfig # Display resolution EPD_WIDTH = 128 EPD_HEIGHT = 296 +GRAY1 = 0xff #white +GRAY2 = 0xC0 +GRAY3 = 0x80 #gray +GRAY4 = 0x00 #Blackest + +logger = logging.getLogger(__name__) class EPD: def __init__(self): @@ -42,6 +48,10 @@ class EPD: self.cs_pin = epdconfig.CS_PIN self.width = EPD_WIDTH self.height = EPD_HEIGHT + self.GRAY1 = GRAY1 #white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 #gray + self.GRAY4 = GRAY4 #Blackest WF_PARTIAL_2IN9 = [ 0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, @@ -49,7 +59,7 @@ class EPD: 0x40,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0A,0x0,0x0,0x0,0x0,0x0,0x2, + 0x0A,0x0,0x0,0x0,0x0,0x0,0x1, 0x1,0x0,0x0,0x0,0x0,0x0,0x0, 0x1,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0, @@ -87,6 +97,49 @@ class EPD: 0x22, 0x17, 0x41, 0x0, 0x32, 0x36 ] + Gray4 = [ + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, 0x60, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, + 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x00, 0x05, 0x14, 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, 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, 0x00, + 0x24, 0x22, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00, + 0x22, 0x17, 0x41, 0xAE, 0x32, 0x28, + ] + + WF_FULL = [ + 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x19, 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, 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, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x42, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00, + 0x22, 0x17, 0x41, 0xAE, 0x32, 0x38] + # Hardware reset def reset(self): epdconfig.digital_write(self.reset_pin, 1) @@ -107,12 +160,19 @@ class EPD: epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy epdconfig.delay_ms(10) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def TurnOnDisplay(self): self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 @@ -195,23 +255,87 @@ class EPD: self.SetLut(self.WS_20_30) # EPD hardware init end return 0 + + def init_Fast(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.ReadBusy() + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x01) #Driver output control + self.send_data(0x27) + self.send_data(0x01) + self.send_data(0x00) + + self.send_command(0x11) #data entry mode + self.send_data(0x03) + + self.SetWindow(0, 0, self.width-1, self.height-1) + + self.send_command(0x3C) + self.send_data(0x05) + + self.send_command(0x21) # Display update control + self.send_data(0x00) + self.send_data(0x80) + + self.SetCursor(0, 0) + self.ReadBusy() + + self.SetLut(self.WF_FULL) + # EPD hardware init end + return 0 + + def Init_4Gray(self): + if (epdconfig.module_init() != 0): + return -1 + self.reset() + epdconfig.delay_ms(100) + + self.ReadBusy() + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x01) #Driver output control + self.send_data(0x27) + self.send_data(0x01) + self.send_data(0x00) + + self.send_command(0x11) #data entry mode + self.send_data(0x03) + + self.SetWindow(8, 0, self.width, self.height-1) + + self.send_command(0x3C) + self.send_data(0x04) + + self.SetCursor(1, 0) + self.ReadBusy() + + self.SetLut(self.Gray4) + # EPD hardware init end + return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -219,14 +343,48 @@ class EPD: if pixels[x, y] == 0: buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) return buf + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i=0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = self.height - x - 1 + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + return buf def display(self, image): if (image == None): return self.send_command(0x24) # WRITE_RAM - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(image[i + j * int(self.width / 8)]) + self.send_data2(image) self.TurnOnDisplay() def display_Base(self, image): @@ -234,16 +392,79 @@ class EPD: return self.send_command(0x24) # WRITE_RAM - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(image[i + j * int(self.width / 8)]) + self.send_data2(image) self.send_command(0x26) # WRITE_RAM - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(image[i + j * int(self.width / 8)]) + self.send_data2(image) self.TurnOnDisplay() + + def display_4Gray(self, image): + self.send_command(0x24) + for i in range(0, 4736): + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else: #0x40 + temp3 |= 0x00 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else : #0x40 + temp3 |= 0x00 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0x26) + for i in range(0, 4736): + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.TurnOnDisplay() def display_Partial(self, image): if (image == None): @@ -279,16 +500,21 @@ class EPD: self.SetCursor(0, 0) self.send_command(0x24) # WRITE_RAM - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(image[i + j * int(self.width / 8)]) + self.send_data2(image) self.TurnOnDisplay_Partial() - def Clear(self, color): + + def Clear(self, color=0xFF): + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + self.send_command(0x24) # WRITE_RAM - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(color) + self.send_data2([color] * int(self.height * linewidth)) + self.TurnOnDisplay() + self.send_command(0x26) # WRITE_RAM + self.send_data2([color] * int(self.height * linewidth)) self.TurnOnDisplay() def sleep(self): diff --git a/lib/waveshare_epd/epd2in9b_V3.py b/lib/waveshare_epd/epd2in9b_V3.py index 4d1a4d4..2a1cc09 100644 --- a/lib/waveshare_epd/epd2in9b_V3.py +++ b/lib/waveshare_epd/epd2in9b_V3.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V1.1 -# * | Date : 2020-12-03 +# * | This version: V1.2 +# * | Date : 2022-08-10 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 128 EPD_HEIGHT = 296 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -64,14 +66,21 @@ class EPD: epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") self.send_command(0X71) while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy self.send_command(0X71) epdconfig.delay_ms(200) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -98,21 +107,21 @@ class EPD: return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -124,12 +133,10 @@ class EPD: def display(self, blackimage, ryimage): # ryimage: red or yellow image if (blackimage != None): self.send_command(0X10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(blackimage[i]) + self.send_data2(blackimage) if (ryimage != None): self.send_command(0X13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(ryimage[i]) + self.send_data2(ryimage) self.send_command(0x12) epdconfig.delay_ms(200) @@ -137,11 +144,9 @@ class EPD: def Clear(self): self.send_command(0X10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xff) + self.send_data2([0xff] * int(self.width * self.height / 8)) self.send_command(0X13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xff) + self.send_data2([0xff] * int(self.width * self.height / 8)) self.send_command(0x12) epdconfig.delay_ms(200) diff --git a/lib/waveshare_epd/epd2in9b_V4.py b/lib/waveshare_epd/epd2in9b_V4.py new file mode 100644 index 0000000..acaf1b7 --- /dev/null +++ b/lib/waveshare_epd/epd2in9b_V4.py @@ -0,0 +1,388 @@ +# ***************************************************************************** +# * | File : epd2in9b_V4.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2023-12-18 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 128 +EPD_HEIGHT = 296 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + self.send_command(0X71) + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(200) + logger.debug("e-Paper busy release") + + + def TurnOnDisplay(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xF7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Base(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xF4) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Fast(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xC7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Partial(self): + self.send_command(0x22) #Display Update Control + self.send_data(0x1C) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + # EPD hardware init start + self.reset() + + self.ReadBusy() + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x01) #Driver output control + self.send_data((self.height-1)%256) + self.send_data((self.height-1)//256) + self.send_data(0x00) + + self.send_command(0x11) #data entry mode + self.send_data(0x03) + + self.send_command(0x44) #set Ram-X address start/end position + self.send_data(0x00) + self.send_data(self.width//8-1) + + self.send_command(0x45) #set Ram-Y address start/end position + self.send_data(0x00) + self.send_data(0x00) + self.send_data((self.height-1)%256) + self.send_data((self.height-1)//256) + + self.send_command(0x3C) #BorderWavefrom + self.send_data(0x05) + + self.send_command(0x21) # Display update control + self.send_data(0x00) + self.send_data(0x80) + + self.send_command(0x18) #Read built-in temperature sensor + self.send_data(0x80) + + self.send_command(0x4E) # set RAM x address count to 0 + self.send_data(0x00) + self.send_command(0x4F) # set RAM y address count to 0X199 + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + return 0 + + def init_Fast(self): + if (epdconfig.module_init() != 0): + return -1 + + # EPD hardware init start + self.reset() + + self.ReadBusy() + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x18) #Read built-in temperature sensor + self.send_data(0x80) + + self.send_command(0x22) # Load temperature value + self.send_data(0xB1) + self.send_command(0x20) + self.ReadBusy() + + self.send_command(0x1A) # Write to temperature register + self.send_data(0x5a) # 90 + self.send_data(0x00) + + self.send_command(0x22) # Load temperature value + self.send_data(0x91) + self.send_command(0x20) + self.ReadBusy() + + self.send_command(0x01) #Driver output control + self.send_data((self.height-1)%256) + self.send_data((self.height-1)//256) + self.send_data(0x00) + + self.send_command(0x11) #data entry mode + self.send_data(0x03) + + self.send_command(0x44) #set Ram-X address start/end position + self.send_data(0x00) + self.send_data(self.width//8-1) + + self.send_command(0x45) #set Ram-Y address start/end position + self.send_data(0x00) + self.send_data(0x00) + self.send_data((self.height-1)%256) + self.send_data((self.height-1)//256) + + self.send_command(0x4E) # set RAM x address count to 0 + self.send_data(0x00) + self.send_command(0x4F) # set RAM y address count to 0X199 + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, blackimage, ryimage): # ryimage: red or yellow image + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + if (blackimage != None): + self.send_command(0x24) + self.send_data2(blackimage) + if (ryimage != None): + for j in range(Height): + for i in range(Width): + ryimage[i + j * Width] = ~ryimage[i + j * Width] + self.send_command(0x26) + self.send_data2(ryimage) + + self.TurnOnDisplay() + + def display_Fast(self, blackimage, ryimage): # ryimage: red or yellow image + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + if (blackimage != None): + self.send_command(0x24) + self.send_data2(blackimage) + if (ryimage != None): + for j in range(Height): + for i in range(Width): + ryimage[i + j * Width] = ~ryimage[i + j * Width] + self.send_command(0x26) + self.send_data2(ryimage) + + self.TurnOnDisplay_Fast() + + def Clear(self): + self.send_command(0x24) + self.send_data2([0xff] * int(self.width * self.height // 8)) + self.send_command(0x26) + self.send_data2([0x00] * int(self.width * self.height // 8)) + + self.TurnOnDisplay() + + def Clear_Fast(self): + self.send_command(0x24) + self.send_data2([0xff] * int(self.width * self.height // 8)) + self.send_command(0x26) + self.send_data2([0x00] * int(self.width * self.height // 8)) + + self.TurnOnDisplay_Fast() + + def display_Base(self, blackimage, ryimage): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + if (blackimage != None): + self.send_command(0x24) + self.send_data2(blackimage) + if (ryimage != None): + for j in range(Height): + for i in range(Width): + ryimage[i + j * Width] = ~ryimage[i + j * Width] + self.send_command(0x26) + self.send_data2(ryimage) + + self.TurnOnDisplay_Base() + + if (blackimage != None): + for j in range(Height): + for i in range(Width): + blackimage[i + j * Width] = ~blackimage[i + j * Width] + self.send_command(0x26) + self.send_data2(blackimage) + else: + self.send_command(0x26) + self.send_data2(blackimage) + + def display_Base_color(self, color): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + self.send_command(0x24) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(color) + + self.send_command(0x26) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(~color) + + self.TurnOnDisplay_Base() + self.send_command(0x26) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(color) + + def display_Partial(self, Image, Xstart, Ystart, Xend, Yend): + if((Xstart % 8 + Xend % 8 == 8 & Xstart % 8 > Xend % 8) | Xstart % 8 + Xend % 8 == 0 | (Xend - Xstart)%8 == 0): + Xstart = Xstart // 8 + Xend = Xend // 8 + else: + Xstart = Xstart // 8 + if Xend % 8 == 0: + Xend = Xend // 8 + else: + Xend = Xend // 8 + 1 + + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + + Xend -= 1 + Yend -= 1 + + self.send_command(0x44) # set RAM x address start/end, in page 35 + self.send_data(Xstart & 0xff) # RAM x address start at 00h + self.send_data(Xend & 0xff) # RAM x address end at 0fh(15+1)*8->128 + self.send_command(0x45) # set RAM y address start/end, in page 35 + self.send_data(Ystart & 0xff) # RAM y address start at 0127h + self.send_data((Ystart>>8) & 0x01) # RAM y address start at 0127h + self.send_data(Yend & 0xff) # RAM y address end at 00h + self.send_data((Yend>>8) & 0x01) + + self.send_command(0x4E) # set RAM x address count to 0 + self.send_data(Xstart & 0xff) + self.send_command(0x4F) # set RAM y address count to 0X127 + self.send_data(Ystart & 0xff) + self.send_data((Ystart>>8) & 0x01) + + self.send_command(0x24) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + if((j > Ystart-1) & (j < (Yend + 1)) & (i > Xstart-1) & (i < (Xend + 1))): + self.send_data(Image[i + j * Width]) + self.TurnOnDisplay_Partial() + + def sleep(self): + self.send_command(0x10) # deep sleep + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd2in9bc.py b/lib/waveshare_epd/epd2in9bc.py index 74fa532..51ea5b5 100644 --- a/lib/waveshare_epd/epd2in9bc.py +++ b/lib/waveshare_epd/epd2in9bc.py @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 128 EPD_HEIGHT = 296 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -66,10 +68,10 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy epdconfig.delay_ms(200) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -97,21 +99,21 @@ class EPD: return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y diff --git a/lib/waveshare_epd/epd2in9d.py b/lib/waveshare_epd/epd2in9d.py index fe377b7..28d3757 100644 --- a/lib/waveshare_epd/epd2in9d.py +++ b/lib/waveshare_epd/epd2in9d.py @@ -7,8 +7,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V2.0 -# * | Date : 2019-06-20 +# * | This version: V2.1 +# * | Date : 2022-08-10 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -30,6 +30,7 @@ # THE SOFTWARE. # +from distutils.command.build_scripts import build_scripts import logging from . import epdconfig from PIL import Image @@ -39,6 +40,8 @@ import RPi.GPIO as GPIO EPD_WIDTH = 128 EPD_HEIGHT = 296 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -127,13 +130,20 @@ class EPD: epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy self.send_command(0x71) epdconfig.delay_ms(10) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def TurnOnDisplay(self): self.send_command(0x12) @@ -197,37 +207,32 @@ class EPD: self.send_data(0x97) self.send_command(0x20) # vcom - for count in range(0, 44): - self.send_data(self.lut_vcom1[count]) + self.send_data2(self.lut_vcom1) self.send_command(0x21) # ww -- - for count in range(0, 42): - self.send_data(self.lut_ww1[count]) + self.send_data2(self.lut_ww1) self.send_command(0x22) # bw r - for count in range(0, 42): - self.send_data(self.lut_bw1[count]) + self.send_data2(self.lut_bw1) self.send_command(0x23) # wb w - for count in range(0, 42): - self.send_data(self.lut_wb1[count]) + self.send_data2(self.lut_wb1) self.send_command(0x24) # bb b - for count in range(0, 42): - self.send_data(self.lut_bb1[count]) + self.send_data2(self.lut_bb1) def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -238,13 +243,11 @@ class EPD: def display(self, image): self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00) + self.send_data2([0x00] * int(self.width * self.height / 8)) epdconfig.delay_ms(10) self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(image[i]) + self.send_data2(image) epdconfig.delay_ms(10) self.TurnOnDisplay() @@ -261,28 +264,28 @@ class EPD: self.send_data(int(self.height / 256)) self.send_data(self.height % 256 - 1) self.send_data(0x28) - - self.send_command(0x10) + + + buf = [0x00] * int(self.width * self.height / 8) for i in range(0, int(self.width * self.height / 8)): - self.send_data(image[i]) + buf[i] = ~image[i] + self.send_command(0x10) + self.send_data2(image) epdconfig.delay_ms(10) self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(~image[i]) + self.send_data2(buf) epdconfig.delay_ms(10) self.TurnOnDisplay() - def Clear(self, color): + def Clear(self): self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00) + self.send_data2([0x00] * int(self.width * self.height / 8)) epdconfig.delay_ms(10) self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xFF) + self.send_data2([0xFF] * int(self.width * self.height / 8)) epdconfig.delay_ms(10) self.TurnOnDisplay() diff --git a/lib/waveshare_epd/epd3in0g.py b/lib/waveshare_epd/epd3in0g.py new file mode 100644 index 0000000..16330f7 --- /dev/null +++ b/lib/waveshare_epd/epd3in0g.py @@ -0,0 +1,221 @@ +# ***************************************************************************** +# * | File : epd3in0g.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1 +# * | Date : 2022-07-20 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# ******************************************************************************/ +# 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. +# + +import logging +from . import epdconfig + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 168 +EPD_HEIGHT = 400 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.BLACK = 0x000000 # 00 BGR + self.WHITE = 0xffffff # 01 + self.YELLOW = 0x00ffff # 10 + self.RED = 0x0000ff # 11 + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) # module reset + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusyH(self): + logger.debug("e-Paper busy H") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(5) + logger.debug("e-Paper busy H release") + + def ReadBusyL(self): + logger.debug("e-Paper busy L") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: busy, 1: idle + epdconfig.delay_ms(5) + logger.debug("e-Paper busy L release") + + def TurnOnDisplay(self): + self.send_command(0x12) # DISPLAY_REFRESH + self.send_data(0x01) + self.ReadBusyH() + + self.send_command(0x02) # POWER_OFF + self.send_data(0X00) + self.ReadBusyH() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + + self.reset() + + self.send_command(0x66) + self.send_data(0x49) + self.send_data(0x55) + self.send_data(0x13) + self.send_data(0x5D) + self.send_data(0x05) + self.send_data(0x10) + + self.send_command(0xB0) + self.send_data(0x00) # 1 boost + + self.send_command(0x01) + self.send_data(0x0F) + self.send_data(0x00) + + self.send_command(0x00) + self.send_data(0x4F) + self.send_data(0x6B) + + self.send_command(0x06) + self.send_data(0xD7) + self.send_data(0xDE) + self.send_data(0x12) + + self.send_command(0x61) + self.send_data(0x00) + self.send_data(0xA8) + self.send_data(0x01) + self.send_data(0x90) + + self.send_command(0x50) + self.send_data(0x37) + + self.send_command(0x60) + self.send_data(0x0C) + self.send_data(0x05) + + self.send_command(0xE3) + self.send_data(0xFF) + + self.send_command(0x84) + self.send_data(0x00) + return 0 + + def getbuffer(self, image): + # Create a pallette with the 4 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 255,255,0, 255,0,0) + (0,0,0)*252) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 4 colors, dithering if needed + image_4color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_4color = bytearray(image_4color.tobytes('raw')) + + # into a single byte to transfer to the panel + buf = [0x00] * int(self.width * self.height / 4) + idx = 0 + for i in range(0, len(buf_4color), 4): + buf[idx] = (buf_4color[i] << 6) + (buf_4color[i+1] << 4) + (buf_4color[i+2] << 2) + buf_4color[i+3] + idx += 1 + + return buf + + def display(self, image): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x04) + self.ReadBusyH() + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(image[i + j * Width]) + + self.TurnOnDisplay() + + def Clear(self, color=0x55): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x04) + self.ReadBusyH() + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(color) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.send_data(0x00) + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd3in52.py b/lib/waveshare_epd/epd3in52.py new file mode 100644 index 0000000..960460d --- /dev/null +++ b/lib/waveshare_epd/epd3in52.py @@ -0,0 +1,459 @@ +# ***************************************************************************** +# * | File : epd3in52.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2022-07-20 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + +import logging +from multiprocessing.reduction import recv_handle +from . import epdconfig + +# Display resolution +EPD_WIDTH = 240 +EPD_HEIGHT = 360 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.Flag = 0 + self.WHITE = 0xFF + self.BLACK = 0x00 + self.Source_Line = 0xAA + self.Gate_Line = 0x55 + self.UP_BLACK_DOWN_WHITE = 0xF0 + self.LEFT_BLACK_RIGHT_WHITE = 0x0F + self.Frame = 0x01 + self.Crosstalk = 0x02 + self.Chessboard = 0x03 + self.Image = 0x04 + + # GC 0.9S + lut_R20_GC = [ + 0x01,0x0f,0x0f,0x0f,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,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00 + ] + lut_R21_GC = [ + 0x01,0x4f,0x8f,0x0f,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,0x00,0x00,0x00 + ] + lut_R22_GC = [ + 0x01,0x0f,0x8f,0x0f,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,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00 + ] + lut_R23_GC = [ + 0x01,0x4f,0x8f,0x4f,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,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00 + ] + lut_R24_GC = [ + 0x01,0x0f,0x8f,0x4f,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,0x00,0x00,0x00 + ] + + # DU 0.3s + lut_R20_DU = [ + 0x01,0x0f,0x01,0x00,0x00,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,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00 + ] + lut_R21_DU = [ + 0x01,0x0f,0x01,0x00,0x00,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,0x00,0x00,0x00 + ] + lut_R22_DU = [ + 0x01,0x8f,0x01,0x00,0x00,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,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00 + ] + lut_R23_DU = [ + 0x01,0x4f,0x01,0x00,0x00,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,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00 + ] + lut_R24_DU = [ + 0x01,0x0f,0x01,0x00,0x00,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,0x00,0x00,0x00 + ] + + lut_vcom = [ + 0x01,0x19,0x19,0x19,0x19,0x01,0x01, + 0x01,0x19,0x19,0x19,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 + ] + lut_ww = [ + 0x01,0x59,0x99,0x59,0x99,0x01,0x01, + 0x01,0x59,0x99,0x19,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 + ] + lut_bw = [ + 0x01,0x59,0x99,0x59,0x99,0x01,0x01, + 0x01,0x59,0x99,0x19,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 + ] + lut_wb = [ + 0x01,0x19,0x99,0x59,0x99,0x01,0x01, + 0x01,0x59,0x99,0x59,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 + ] + lut_bb = [ + 0x01,0x19,0x99,0x59,0x99,0x01,0x01, + 0x01,0x59,0x99,0x59,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 + ] + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: busy, 1: idle + epdconfig.delay_ms(5) + logger.debug("e-Paper busy release") + + def lut(self) : + self.send_command(0x20) # vcom + self.send_data2(self.lut_vcom[:42]) + + self.send_command(0x21) # ww -- + self.send_data2(self.lut_ww[:42]) + + self.send_command(0x22) # bw r + self.send_data2(self.lut_bw[:42]) + + self.send_command(0x23) # wb w + self.send_data2(self.lut_bb[:42]) + + self.send_command(0x24) # bb b + self.send_data2(self.lut_wb[:42]) + + def refresh(self): + self.send_command(0x17) + self.send_data(0xA5) + self.ReadBusy() + epdconfig.delay_ms(200) + + # LUT download + def lut_GC(self): + self.send_command(0x20); # vcom + self.send_data2(self.lut_R20_GC[:56]) + + self.send_command(0x21); # red not use + self.send_data2(self.lut_R21_GC[:42]) + + self.send_command(0x24); # bb b + self.send_data2(self.lut_R24_GC[:42]) + + if(self.Flag == 0) : + self.send_command(0x22); # bw r + self.send_data2(self.lut_R22_GC[:56]) + + self.send_command(0x23); # wb w + self.send_data2(self.lut_R23_GC[:42]) + self.Flag = 1 + + else : + self.send_command(0x22); # bw r + self.send_data2(self.lut_R23_GC[:56]) + + self.send_command(0x23); # wb w + self.send_data2(self.lut_R22_GC[:42]) + self.Flag = 0 + + # LUT download + def lut_DU(self): + self.send_command(0x20); # vcom + self.send_data2(self.lut_R20_DU[:56]) + + self.send_command(0x21); # red not use + self.send_data2(self.lut_R21_DU[:42]) + + self.send_command(0x24); # bb b + self.send_data2(self.lut_R24_DU[:42]) + + if(self.Flag == 0) : + self.send_command(0x22); # bw r + self.send_data2(self.lut_R22_DU[:56]) + + self.send_command(0x23); # wb w + self.send_data2(self.lut_R23_DU[:42]) + + self.Flag = 1 + + else : + self.send_command(0x22); # bw r + self.send_data2(self.lut_R23_DU[:56]) + + self.send_command(0x23); # wb w + self.send_data2(self.lut_R22_DU[:42]) + + self.Flag = 0 + + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.Flag = 0 + self.reset() + + self.send_command(0x00) # panel setting PSR + self.send_data(0xFF) # RES1 RES0 REG KW/R UD SHL SHD_N RST_N + self.send_data(0x01) # x x x VCMZ TS_AUTO TIGE NORG VC_LUTZ + + self.send_command(0x01) # POWER SETTING PWR + self.send_data(0x03) # x x x x x x VDS_EN VDG_EN + self.send_data(0x10) # x x x VCOM_SLWE VGH[3:0] VGH=20V, VGL=-20V + self.send_data(0x3F) # x x VSH[5:0] VSH = 15V + self.send_data(0x3F) # x x VSL[5:0] VSL=-15V + self.send_data(0x03) # OPTEN VDHR[6:0] VHDR=6.4V + # T_VDS_OFF[1:0] 00=1 frame; 01=2 frame; 10=3 frame; 11=4 frame + self.send_command(0x06) # booster soft start BTST + self.send_data(0x37) # BT_PHA[7:0] + self.send_data(0x3D) # BT_PHB[7:0] + self.send_data(0x3D) # x x BT_PHC[5:0] + + self.send_command(0x60) # TCON setting TCON + self.send_data(0x22) # S2G[3:0] G2S[3:0] non-overlap = 12 + + self.send_command(0x82) # VCOM_DC setting VDCS + self.send_data(0x07) # x VDCS[6:0] VCOM_DC value= -1.9v 00~3f,0x12=-1.9v + + self.send_command(0x30) + self.send_data(0x09) + + self.send_command(0xe3) # power saving PWS + self.send_data(0x88) # VCOM_W[3:0] SD_W[3:0] + + self.send_command(0x61) # resoultion setting + self.send_data(0xf0) # HRES[7:3] 0 0 0 + self.send_data(0x01) # x x x x x x x VRES[8] + self.send_data(0x68) # VRES[7:0] + + self.send_command(0x50); + self.send_data(0xB7); + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, image): + if (image == None): + return + self.send_command(0x13); # Transfer new data + self.send_data2(image) + + def display_NUM(self, NUM): + # pcnt = 0 + + self.send_command(0x13); #Transfer new data + for column in range(0, self.height): + for row in range(0, self.width//8): + if NUM == self.WHITE: + self.send_data(0xFF) + + elif NUM == self.BLACK: + self.send_data(0x00) + + elif NUM == self.Source_Line: + self.send_data(0xAA) + + elif NUM == self.Gate_Line: + if(column%2): + self.send_data(0xff) # An odd number of Gate line + else: + self.send_data(0x00) # The even line Gate + + elif NUM == self.Chessboard: + if(row>=(self.width/8/2) and column>=(self.height/2)): + self.send_data(0xff) + elif(row<(self.width/8/2) and column<(self.height/2)): + self.send_data(0xff) + else: + self.send_data(0x00) + + elif NUM == self.LEFT_BLACK_RIGHT_WHITE: + if(row>=(self.width/8/2)): + self.send_data(0xff) + else: + self.send_data(0x00) + + elif NUM == self.UP_BLACK_DOWN_WHITE: + if(column>=(self.height/2)): + self.send_data(0xFF) + else: + self.send_data(0x00) + + elif NUM == self.Frame: + if(column==0 or column==(self.height-1)): + self.send_data(0x00) + elif(row==0): + self.send_data(0x7F) + elif(row==(self.width/8-1)): + self.send_data(0xFE); + else: + self.send_data(0xFF); + + elif NUM == self.Crosstalk: + if((row>=(self.width/8/3) and row<=(self.width/8/3*2) and column<=(self.height/3)) or (row>=(self.width/8/3) and row<=(self.width/8/3*2) and column>=(self.height/3*2))): + self.send_data(0x00) + else: + self.send_data(0xFF) + + elif NUM == self.Image: + epdconfig.delay_ms(1) + # self.send_data(gImage_1[pcnt++]) + + + def Clear(self): + self.send_command(0x13); # Transfer new data + self.send_data2([0xFF] * int(self.width * self.height / 8)) + self.lut_GC() + self.refresh() + + def sleep(self): + self.send_command(0X07) # DEEP_SLEEP_MODE + self.send_data(0xA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd3in7.py b/lib/waveshare_epd/epd3in7.py index b9f108c..3768568 100644 --- a/lib/waveshare_epd/epd3in7.py +++ b/lib/waveshare_epd/epd3in7.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V1.0 -# * | Date : 2020-07-16 +# * | This version: V1.1 +# * | Date : 2022-08-10 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -36,8 +36,11 @@ EPD_HEIGHT = 480 GRAY1 = 0xff #white GRAY2 = 0xC0 #Close to white -GRAY3 = 0x80 #Close to balck -GRAY4 = 0x00 #balck +GRAY3 = 0x80 #Close to black +GRAY4 = 0x00 #black + +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -130,12 +133,19 @@ class EPD: epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy epdconfig.delay_ms(10) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self, mode): @@ -211,7 +221,7 @@ class EPD: self.send_data(0xFF) self.send_data(0xFF) else: - logging.debug("There is no such mode") + logger.debug("There is no such mode") self.send_command(0x44) # setting X direction start/end position of RAM self.send_data(0x00) @@ -232,26 +242,25 @@ class EPD: def load_lut(self, lut): self.send_command(0x32) - for i in range(0, 105): - self.send_data(lut[i]) + self.send_data2(lut) def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -262,15 +271,15 @@ class EPD: def getbuffer_4Gray(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width / 4) * self.height) image_monocolor = image.convert('L') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() i=0 - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. @@ -283,7 +292,7 @@ class EPD: buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for x in range(imwidth): for y in range(imheight): newx = y @@ -309,6 +318,13 @@ class EPD: self.send_data(0x00) self.send_data(0x00) + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + + buf = [0x00] * self.height * linewidth + self.send_command(0x24) for i in range(0, (int)(self.height*(self.width/8))): temp3=0 @@ -338,7 +354,8 @@ class EPD: if(j!=1 or k!=1): temp3 <<= 1 temp1 <<= 2 - self.send_data(temp3) + buf[i] = temp3 + self.send_data2(buf) self.send_command(0x4E) self.send_data(0x00) @@ -376,7 +393,8 @@ class EPD: if(j!=1 or k!=1): temp3 <<= 1 temp1 <<= 2 - self.send_data(temp3) + buf[i] = temp3 + self.send_data2(buf) self.load_lut(self.lut_4Gray_GC) self.send_command(0x22) @@ -397,9 +415,7 @@ class EPD: self.send_data(0x00) self.send_command(0x24) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(image[i + j * int(self.width / 8)]) + self.send_data2(image) self.load_lut(self.lut_1Gray_A2) self.send_command(0x20) @@ -414,34 +430,33 @@ class EPD: self.send_data(0x00) self.send_data(0x00) + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + self.send_command(0x24) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(0xff) + self.send_data2([0xff] * int(self.height * linewidth)) if(mode == 0): #4Gray self.send_command(0x26) - for j in range(0, self.height): - for i in range(0, int(self.width / 8)): - self.send_data(0xff) + self.send_data2([0xff] * int(self.height * linewidth)) + self.load_lut(self.lut_4Gray_GC) self.send_command(0x22) self.send_data(0xC7) elif(mode == 1): #1Gray self.load_lut(self.lut_1Gray_DU) else: - logging.debug("There is no such mode") + logger.debug("There is no such mode") self.send_command(0x20) self.ReadBusy() def sleep(self): - self.send_command(0X50) # DEEP_SLEEP_MODE - self.send_data(0xf7) - self.send_command(0X02) #power off - self.send_command(0X07) #deep sleep - self.send_data(0xA5) + self.send_command(0X10) #deep sleep + self.send_data(0x03) epdconfig.delay_ms(2000) epdconfig.module_exit() diff --git a/lib/waveshare_epd/epd4in01f.py b/lib/waveshare_epd/epd4in01f.py index ceb9c8c..fd20241 100644 --- a/lib/waveshare_epd/epd4in01f.py +++ b/lib/waveshare_epd/epd4in01f.py @@ -6,8 +6,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V1.0 -# * | Date : 2020-11-06 +# * | This version: V1.1 +# * | Date : 2022-08-10 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -36,6 +36,8 @@ from . import epdconfig EPD_WIDTH = 640 EPD_HEIGHT = 400 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -73,18 +75,25 @@ class EPD: epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) def ReadBusyHigh(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy epdconfig.delay_ms(10) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def ReadBusyLow(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy epdconfig.delay_ms(10) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -93,33 +102,33 @@ class EPD: self.reset() self.ReadBusyHigh() - self.send_command(0x00); - self.send_data(0x2f); - self.send_data(0x00); - self.send_command(0x01); - self.send_data(0x37); - self.send_data(0x00); - self.send_data(0x05); - self.send_data(0x05); - self.send_command(0x03); - self.send_data(0x00); - self.send_command(0x06); - self.send_data(0xC7); - self.send_data(0xC7); - self.send_data(0x1D); - self.send_command(0x41); - self.send_data(0x00); - self.send_command(0x50); - self.send_data(0x37); - self.send_command(0x60); - self.send_data(0x22); - self.send_command(0x61); - self.send_data(0x02); - self.send_data(0x80); - self.send_data(0x01); - self.send_data(0x90); - self.send_command(0xE3); - self.send_data(0xAA); + self.send_command(0x00) + self.send_data(0x2f) + self.send_data(0x00) + self.send_command(0x01) + self.send_data(0x37) + self.send_data(0x00) + self.send_data(0x05) + self.send_data(0x05) + self.send_command(0x03) + self.send_data(0x00) + self.send_command(0x06) + self.send_data(0xC7) + self.send_data(0xC7) + self.send_data(0x1D) + self.send_command(0x41) + self.send_data(0x00) + self.send_command(0x50) + self.send_data(0x37) + self.send_command(0x60) + self.send_data(0x22) + self.send_command(0x61) + self.send_data(0x02) + self.send_data(0x80) + self.send_data(0x01) + self.send_data(0x90) + self.send_command(0xE3) + self.send_data(0xAA) # EPD hardware init end return 0 @@ -129,7 +138,7 @@ class EPD: image_monocolor = image.convert('RGB')#Picture mode conversion imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) + logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) if(imwidth == self.width and imheight == self.height): for y in range(imheight): for x in range(imwidth): @@ -187,9 +196,7 @@ class EPD: self.send_data(0x01) self.send_data(0x90) self.send_command(0x10) - for i in range(0, int(EPD_HEIGHT)): - for j in range(0, int(EPD_WIDTH/2)): - self.send_data((image[j+(int(EPD_WIDTH/2)*i)])) + self.send_data2(image) self.send_command(0x04)#0x04 self.ReadBusyHigh() self.send_command(0x12)#0x12 @@ -205,9 +212,7 @@ class EPD: self.send_data(0x01) self.send_data(0x90) self.send_command(0x10) - for i in range(0, int(EPD_HEIGHT)): - for j in range(0, int(EPD_WIDTH/2)): - self.send_data(0x11) + self.send_data2([0x11] * int(EPD_HEIGHT) * int(EPD_WIDTH/2)) #BLACK 0x00 /// 0000 #WHITE 0x11 /// 0001 #GREEN 0x22 /// 0010 diff --git a/lib/waveshare_epd/epd4in2.py b/lib/waveshare_epd/epd4in2.py index d4d05d8..ce1d057 100644 --- a/lib/waveshare_epd/epd4in2.py +++ b/lib/waveshare_epd/epd4in2.py @@ -1,11 +1,11 @@ # ***************************************************************************** -# * | File : epd4in2.py +# * | File : epd4in2.py # * | Author : Waveshare team # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V4.0 -# * | Date : 2019-06-20 +# * | This version: V4.2 +# * | Date : 2022-10-29 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -34,13 +34,16 @@ from PIL import Image import RPi.GPIO as GPIO # Display resolution -EPD_WIDTH = 400 -EPD_HEIGHT = 300 +EPD_WIDTH = 400 +EPD_HEIGHT = 300 + +GRAY1 = 0xff # white +GRAY2 = 0xC0 +GRAY3 = 0x80 # gray +GRAY4 = 0x00 # Blackest + +logger = logging.getLogger(__name__) -GRAY1 = 0xff #white -GRAY2 = 0xC0 -GRAY3 = 0x80 #gray -GRAY4 = 0x00 #Blackest class EPD: def __init__(self): @@ -50,171 +53,183 @@ class EPD: self.cs_pin = epdconfig.CS_PIN self.width = EPD_WIDTH self.height = EPD_HEIGHT - self.GRAY1 = GRAY1 #white - self.GRAY2 = GRAY2 - self.GRAY3 = GRAY3 #gray - self.GRAY4 = GRAY4 #Blackest + self.GRAY1 = GRAY1 # white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 # gray + self.GRAY4 = GRAY4 # Blackest + self.DATA = [0x00] * 15000 lut_vcom0 = [ - 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x17, 0x17, 0x00, 0x00, 0x02, - 0x00, 0x0A, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x01, + 0x00, 0x08, 0x08, 0x00, 0x00, 0x02, + 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, ] lut_ww = [ - 0x40, 0x17, 0x00, 0x00, 0x00, 0x02, - 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, - 0x40, 0x0A, 0x01, 0x00, 0x00, 0x01, - 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x90, 0x0F, 0x0F, 0x00, 0x00, 0x01, + 0xA0, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ] lut_bw = [ - 0x40, 0x17, 0x00, 0x00, 0x00, 0x02, - 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, - 0x40, 0x0A, 0x01, 0x00, 0x00, 0x01, - 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x90, 0x0F, 0x0F, 0x00, 0x00, 0x01, + 0xA0, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ] lut_wb = [ - 0x80, 0x17, 0x00, 0x00, 0x00, 0x02, - 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, - 0x80, 0x0A, 0x01, 0x00, 0x00, 0x01, - 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA0, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x90, 0x0F, 0x0F, 0x00, 0x00, 0x01, + 0x50, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ] lut_bb = [ - 0x80, 0x17, 0x00, 0x00, 0x00, 0x02, - 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, - 0x80, 0x0A, 0x01, 0x00, 0x00, 0x01, - 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x90, 0x0F, 0x0F, 0x00, 0x00, 0x01, + 0x10, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + # ******************************partial screen update LUT*********************************/ + EPD_4IN2_Partial_lut_vcom1 = [ + 0x00, 0x01, 0x20, 0x01, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ] - #******************************partial screen update LUT*********************************/ - EPD_4IN2_Partial_lut_vcom1 =[ - 0x00 ,0x19 ,0x01 ,0x00 ,0x00 ,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 ,0x00 ,0x00 ,0x00 ,0x00, - 0x00 ,0x00, ] - EPD_4IN2_Partial_lut_ww1 =[ - 0x00 ,0x19 ,0x01 ,0x00 ,0x00 ,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 ,0x00 ,0x00 ,0x00 ,0x00,] + EPD_4IN2_Partial_lut_ww1 = [ + 0x00, 0x01, 0x20, 0x01, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + ] - EPD_4IN2_Partial_lut_bw1 =[ - 0x80 ,0x19 ,0x01 ,0x00 ,0x00 ,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 ,0x00 ,0x00 ,0x00 ,0x00, ] + EPD_4IN2_Partial_lut_bw1 = [ + 0x20, 0x01, 0x20, 0x01, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] - EPD_4IN2_Partial_lut_wb1 =[ - 0x40 ,0x19 ,0x01 ,0x00 ,0x00 ,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 ,0x00 ,0x00 ,0x00 ,0x00, ] + EPD_4IN2_Partial_lut_wb1 = [ + 0x10, 0x01, 0x20, 0x01, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + ] - EPD_4IN2_Partial_lut_bb1 =[ - 0x00 ,0x19 ,0x01 ,0x00 ,0x00 ,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 ,0x00 ,0x00 ,0x00 ,0x00, ] + EPD_4IN2_Partial_lut_bb1 = [ + 0x00, 0x01, 0x20, 0x01, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + ] - #******************************gray*********************************/ - #0~3 gray - EPD_4IN2_4Gray_lut_vcom =[ - 0x00 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, - 0x60 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, - 0x00 ,0x14 ,0x00 ,0x00 ,0x00 ,0x01, - 0x00 ,0x13 ,0x0A ,0x01 ,0x00 ,0x01, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 + # ******************************gray*********************************/ + # 0~3 gray + EPD_4IN2_4Gray_lut_vcom = [ + 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x60, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x13, 0x0A, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] - #R21 - EPD_4IN2_4Gray_lut_ww =[ - 0x40 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, - 0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, - 0x10 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01, - 0xA0 ,0x13 ,0x01 ,0x00 ,0x00 ,0x01, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + # R21 + EPD_4IN2_4Gray_lut_ww = [ + 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x10, 0x14, 0x0A, 0x00, 0x00, 0x01, + 0xA0, 0x13, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ] - #R22H r - EPD_4IN2_4Gray_lut_bw =[ - 0x40 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, - 0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, - 0x00 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01, - 0x99 ,0x0C ,0x01 ,0x03 ,0x04 ,0x01, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + # R22H r + EPD_4IN2_4Gray_lut_bw = [ + 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x0A, 0x00, 0x00, 0x01, + 0x99, 0x0C, 0x01, 0x03, 0x04, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ] - #R23H w - EPD_4IN2_4Gray_lut_wb =[ - 0x40 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, - 0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, - 0x00 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01, - 0x99 ,0x0B ,0x04 ,0x04 ,0x01 ,0x01, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + # R23H w + EPD_4IN2_4Gray_lut_wb = [ + 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x0A, 0x00, 0x00, 0x01, + 0x99, 0x0B, 0x04, 0x04, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ] - #R24H b - EPD_4IN2_4Gray_lut_bb =[ - 0x80 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, - 0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, - 0x20 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01, - 0x50 ,0x13 ,0x01 ,0x00 ,0x00 ,0x01, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, - 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + # R24H b + EPD_4IN2_4Gray_lut_bb = [ + 0x80, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x20, 0x14, 0x0A, 0x00, 0x00, 0x01, + 0x50, 0x13, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ] - + # Hardware reset def reset(self): epdconfig.digital_write(self.reset_pin, 1) - epdconfig.delay_ms(20) + epdconfig.delay_ms(10) epdconfig.digital_write(self.reset_pin, 0) - epdconfig.delay_ms(5) + epdconfig.delay_ms(10) epdconfig.digital_write(self.reset_pin, 1) - epdconfig.delay_ms(20) + epdconfig.delay_ms(10) epdconfig.digital_write(self.reset_pin, 0) - epdconfig.delay_ms(5) + epdconfig.delay_ms(10) epdconfig.digital_write(self.reset_pin, 1) - epdconfig.delay_ms(20) + epdconfig.delay_ms(10) epdconfig.digital_write(self.reset_pin, 0) - epdconfig.delay_ms(5) + epdconfig.delay_ms(10) epdconfig.digital_write(self.reset_pin, 1) - epdconfig.delay_ms(20) + epdconfig.delay_ms(10) def send_command(self, command): epdconfig.digital_write(self.dc_pin, 0) @@ -227,381 +242,437 @@ class EPD: epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) - + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + def ReadBusy(self): self.send_command(0x71) - while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + while epdconfig.digital_read(self.busy_pin) == 0: # 0: idle, 1: busy self.send_command(0x71) - epdconfig.delay_ms(100) + epdconfig.delay_ms(100) def set_lut(self): - self.send_command(0x20) # vcom - for count in range(0, 44): - self.send_data(self.lut_vcom0[count]) - - self.send_command(0x21) # ww -- - for count in range(0, 42): - self.send_data(self.lut_ww[count]) - - self.send_command(0x22) # bw r - for count in range(0, 42): - self.send_data(self.lut_bw[count]) - - self.send_command(0x23) # wb w - for count in range(0, 42): - self.send_data(self.lut_bb[count]) - - self.send_command(0x24) # bb b - for count in range(0, 42): - self.send_data(self.lut_wb[count]) + self.send_command(0x20) # vcom + self.send_data2(self.lut_vcom0) + self.send_command(0x21) # ww -- + self.send_data2(self.lut_ww) + + self.send_command(0x22) # bw r + self.send_data2(self.lut_bw) + + self.send_command(0x23) # wb w + self.send_data2(self.lut_bb) + + self.send_command(0x24) # bb b + self.send_data2(self.lut_wb) def Partial_SetLut(self): - self.send_command(0x20); - for count in range(0, 44): - self.send_data(self.EPD_4IN2_Partial_lut_vcom1[count]) + self.send_command(0x20) + self.send_data2(self.EPD_4IN2_Partial_lut_vcom1) - self.send_command(0x21); - for count in range(0, 42): - self.send_data(self.EPD_4IN2_Partial_lut_ww1[count]) - - self.send_command(0x22); - for count in range(0, 42): - self.send_data(self.EPD_4IN2_Partial_lut_bw1[count]) + self.send_command(0x21) + self.send_data2(self.EPD_4IN2_Partial_lut_ww1) - self.send_command(0x23); - for count in range(0, 42): - self.send_data(self.EPD_4IN2_Partial_lut_wb1[count]) + self.send_command(0x22) + self.send_data2(self.EPD_4IN2_Partial_lut_bw1) - self.send_command(0x24); - for count in range(0, 42): - self.send_data(self.EPD_4IN2_Partial_lut_bb1[count]) + self.send_command(0x23) + self.send_data2(self.EPD_4IN2_Partial_lut_wb1) + self.send_command(0x24) + self.send_data2(self.EPD_4IN2_Partial_lut_bb1) - def Gray_SetLut(self): - self.send_command(0x20) #vcom - for count in range(0, 42): - self.send_data(self.EPD_4IN2_4Gray_lut_vcom[count]) + self.send_command(0x20) # vcom + self.send_data2(self.EPD_4IN2_4Gray_lut_vcom) - self.send_command(0x21) #red not use - for count in range(0, 42): - self.send_data(self.EPD_4IN2_4Gray_lut_ww[count]) + self.send_command(0x21) # red not use + self.send_data2(self.EPD_4IN2_4Gray_lut_ww) - self.send_command(0x22) #bw r - for count in range(0, 42): - self.send_data(self.EPD_4IN2_4Gray_lut_bw[count]) + self.send_command(0x22) # bw r + self.send_data2(self.EPD_4IN2_4Gray_lut_bw) - self.send_command(0x23) #wb w - for count in range(0, 42): - self.send_data(self.EPD_4IN2_4Gray_lut_wb[count]) + self.send_command(0x23) # wb w + self.send_data2(self.EPD_4IN2_4Gray_lut_wb) - self.send_command(0x24) #bb b - for count in range(0, 42): - self.send_data(self.EPD_4IN2_4Gray_lut_bb[count]) + self.send_command(0x24) # bb b + self.send_data2(self.EPD_4IN2_4Gray_lut_bb) + + self.send_command(0x25) # vcom + self.send_data2(self.EPD_4IN2_4Gray_lut_ww) - self.send_command(0x25) #vcom - for count in range(0, 42): - self.send_data(self.EPD_4IN2_4Gray_lut_ww[count]) - - def init(self): - if (epdconfig.module_init() != 0): + if epdconfig.module_init() != 0: return -1 # EPD hardware init start self.reset() - - self.send_command(0x01) # POWER SETTING - self.send_data(0x03) # VDS_EN, VDG_EN - self.send_data(0x00) # VCOM_HV, VGHL_LV[1], VGHL_LV[0] - self.send_data(0x2b) # VDH - self.send_data(0x2b) # VDL - - self.send_command(0x06) # boost soft start - self.send_data(0x17) - self.send_data(0x17) - self.send_data(0x17) - - self.send_command(0x04) # POWER_ON - self.ReadBusy() - - self.send_command(0x00) # panel setting - self.send_data(0xbf) # KW-BF KWR-AF BWROTP 0f - self.send_data(0x0d) - - self.send_command(0x30) # PLL setting - self.send_data(0x3c) # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ - self.send_command(0x61) # resolution setting + self.send_command(0x01) # POWER SETTING + self.send_data(0x03) # VDS_EN, VDG_EN + self.send_data(0x00) # VCOM_HV, VGHL_LV[1], VGHL_LV[0] + self.send_data(0x2b) # VDH + self.send_data(0x2b) # VDL + + self.send_command(0x06) # boost soft start + self.send_data(0x17) + self.send_data(0x17) + self.send_data(0x17) + + self.send_command(0x04) # POWER_ON + self.ReadBusy() + + self.send_command(0x00) # panel setting + self.send_data(0xbf) # KW-BF KWR-AF BWROTP 0f + + self.send_command(0x30) # PLL setting + self.send_data(0x3c) # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ + + self.send_command(0x61) # resolution setting + self.send_data(0x01) + self.send_data(0x90) # 128 self.send_data(0x01) - self.send_data(0x90) # 128 - self.send_data(0x01) self.send_data(0x2c) - self.send_command(0x82) # vcom_DC setting - self.send_data(0x28) + self.send_command(0x82) # vcom_DC setting + self.send_data(0x12) + + self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING + self.send_data( + 0x97) # 97white border 77black border VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7 - self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING - self.send_data(0x97) # 97white border 77black border VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7 - self.set_lut() # EPD hardware init end return 0 - - def Init_4Gray(self): - if (epdconfig.module_init() != 0): + + def init_Partial(self): + if epdconfig.module_init() != 0: return -1 # EPD hardware init start self.reset() - - self.send_command(0x01) #POWER SETTING - self.send_data (0x03) - self.send_data (0x00) #VGH=20V,VGL=-20V - self.send_data (0x2b) #VDH=15V - self.send_data (0x2b) #VDL=-15V - self.send_data (0x13) - self.send_command(0x06) #booster soft start - self.send_data (0x17) #A - self.send_data (0x17) #B - self.send_data (0x17) #C + self.send_command(0x01) # POWER SETTING + self.send_data(0x03) # VDS_EN, VDG_EN + self.send_data(0x00) # VCOM_HV, VGHL_LV[1], VGHL_LV[0] + self.send_data(0x2b) # VDH + self.send_data(0x2b) # VDL + + self.send_command(0x06) # boost soft start + self.send_data(0x17) + self.send_data(0x17) + self.send_data(0x17) + + self.send_command(0x04) # POWER_ON + self.ReadBusy() + + self.send_command(0x00) # panel setting + self.send_data(0xbf) # KW-BF KWR-AF BWROTP 0f + + self.send_command(0x30) # PLL setting + self.send_data(0x3c) # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ + + self.send_command(0x61) # resolution setting + self.send_data(0x01) + self.send_data(0x90) # 128 + self.send_data(0x01) + self.send_data(0x2c) + + self.send_command(0x82) # vcom_DC setting + self.send_data(0x12) + + self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING + self.send_data( + 0x07) # 97white border 77black border VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7 + + self.Partial_SetLut() + # EPD hardware init end + return 0 + + def Init_4Gray(self): + if epdconfig.module_init() != 0: + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x01) # POWER SETTING + self.send_data(0x03) + self.send_data(0x00) # VGH=20V,VGL=-20V + self.send_data(0x2b) # VDH=15V + self.send_data(0x2b) # VDL=-15V + self.send_data(0x13) + + self.send_command(0x06) # booster soft start + self.send_data(0x17) # A + self.send_data(0x17) # B + self.send_data(0x17) # C self.send_command(0x04) self.ReadBusy() - self.send_command(0x00) #panel setting - self.send_data(0x3f) #KW-3f KWR-2F BWROTP 0f BWOTP 1f + self.send_command(0x00) # panel setting + self.send_data(0x3f) # KW-3f KWR-2F BWROTP 0f BWOTP 1f - self.send_command(0x30) #PLL setting - self.send_data (0x3c) #100hz + self.send_command(0x30) # PLL setting + self.send_data(0x3c) # 100hz - self.send_command(0x61) #resolution setting - self.send_data (0x01) #400 - self.send_data (0x90) - self.send_data (0x01) #300 - self.send_data (0x2c) + self.send_command(0x61) # resolution setting + self.send_data(0x01) # 400 + self.send_data(0x90) + self.send_data(0x01) # 300 + self.send_data(0x2c) - self.send_command(0x82) #vcom_DC setting - self.send_data (0x12) + self.send_command(0x82) # vcom_DC setting + self.send_data(0x12) - self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING + self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING self.send_data(0x97) def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) - buf = [0xFF] * (int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) - if(imwidth == self.width and imheight == self.height): - logging.debug("Horizontal") + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if imwidth == self.width and imheight == self.height: + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) - elif(imwidth == self.height and imheight == self.width): - logging.debug("Vertical") + elif imwidth == self.height and imheight == self.width: + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): newx = y newy = self.height - x - 1 if pixels[x, y] == 0: - buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8)) return buf - + def getbuffer_4Gray(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width / 4) * self.height) image_monocolor = image.convert('L') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - i=0 - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) - if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + i = 0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if imwidth == self.width and imheight == self.height: + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. - if(pixels[x, y] == 0xC0): + if pixels[x, y] == 0xC0: pixels[x, y] = 0x80 - elif (pixels[x, y] == 0x80): + elif pixels[x, y] == 0x80: pixels[x, y] = 0x40 - i= i+1 - if(i%4 == 0): - buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) - - elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + i = i + 1 + if i % 4 == 0: + buf[int((x + (y * self.width)) / 4)] = ( + (pixels[x - 3, y] & 0xc0) | (pixels[x - 2, y] & 0xc0) >> 2 | ( + pixels[x - 1, y] & 0xc0) >> 4 | (pixels[x, y] & 0xc0) >> 6) + + elif imwidth == self.height and imheight == self.width: + logger.debug("Horizontal") for x in range(imwidth): for y in range(imheight): newx = y newy = x - if(pixels[x, y] == 0xC0): + if pixels[x, y] == 0xC0: pixels[x, y] = 0x80 - elif (pixels[x, y] == 0x80): + elif pixels[x, y] == 0x80: pixels[x, y] = 0x40 - i= i+1 - if(i%4 == 0): - buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) - + i = i + 1 + if i % 4 == 0: + buf[int((newx + (newy * self.width)) / 4)] = ( + (pixels[x, y - 3] & 0xc0) | (pixels[x, y - 2] & 0xc0) >> 2 | ( + pixels[x, y - 1] & 0xc0) >> 4 | (pixels[x, y] & 0xc0) >> 6) + return buf def display(self, image): - self.send_command(0x92); - self.set_lut(); + if self.width % 8 == 0: + linewidth = int(self.width / 8) + else: + linewidth = int(self.width / 8) + 1 + + self.send_command(0x92) + self.set_lut() self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xFF) - + self.send_data2([0xFF] * int(self.width * linewidth)) + self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(image[i]) - - self.send_command(0x12) + self.send_data2(image) + + self.send_command(0x12) self.ReadBusy() def EPD_4IN2_PartialDisplay(self, X_start, Y_start, X_end, Y_end, Image): # EPD_WIDTH = 400 # EPD_HEIGHT = 300 - if(EPD_WIDTH % 8 != 0): - Width = int(EPD_WIDTH / 8) + 1; + + if EPD_WIDTH % 8 != 0: + Width = int(EPD_WIDTH / 8) + 1 else: - Width = int(EPD_WIDTH / 8); - Height = EPD_HEIGHT; - - if(X_start % 8 != 0): - X_start = int(X_start/8)*8+8 - if(X_end % 8 != 0): - X_end = int(X_end/8)*8+8 - - self.Partial_SetLut(); - self.send_command(0x91); #This command makes the display enter partial mode - self.send_command(0x90); #resolution setting - self.send_data (int(X_start/256)); - self.send_data (int(X_start%256)); #x-start - - self.send_data (int(X_end /256)); - self.send_data (int(X_end %256)-1); #x-end + Width = int(EPD_WIDTH / 8) + Height = EPD_HEIGHT - self.send_data (int(Y_start/256)); - self.send_data (int(Y_start%256)); #y-start - + if X_start % 8 != 0: + X_start = int(X_start / 8) + 1 + else: + X_start = int(X_start / 8) + if X_end % 8 != 0: + X_end = int(X_end / 8) + 1 + else: + X_end = int(X_end / 8) - self.send_data (int(Y_end/256)); - self.send_data (int(Y_end%256)-1); #y-end - self.send_data (0x28); + buf = [0x00] * (Y_end - Y_start) * (X_end - X_start) - self.send_command(0x10); #writes Old data to SRAM for programming - for j in range(0, int(Y_end - Y_start)): - for i in range(0, int(X_end/8) - int(X_start/8)): - self.send_data(Image[(Y_start + j)*Width + int(X_start/8) + i]); - - self.send_command(0x13); #writes New data to SRAM. - for j in range(0, int(Y_end - Y_start)): - for i in range(0, int(X_end/8) - int(X_start/8)): - self.send_data(~Image[(Y_start + j)*Width + int(X_start/8) + i]); - - self.send_command(0x12); #DISPLAY REFRESH - epdconfig.delay_ms(200) #The delay here is necessary, 200uS at least!!! + self.send_command(0x91) # This command makes the display enter partial mode + self.send_command(0x90) # resolution setting + self.send_data(int(X_start * 8 / 256)) + self.send_data(int(X_start * 8 % 256)) # x-start + + self.send_data(int(X_end * 8 / 256)) + self.send_data(int(X_end * 8 % 256) - 1) # x-end + + self.send_data(int(Y_start / 256)) + self.send_data(int(Y_start % 256)) # y-start + + self.send_data(int(Y_end / 256)) + self.send_data(int(Y_end % 256) - 1) # y-end + self.send_data(0x28) + + self.send_command(0x10) # writes Old data to SRAM for programming + for j in range(0, Y_end - Y_start): + for i in range(0, X_end - X_start): + buf[j * (X_end - X_start) + i] = self.DATA[(Y_start + j) * Width + X_start + i] + self.send_data2(buf) + + self.send_command(0x13) # writes New data to SRAM. + for j in range(0, Y_end - Y_start): + for i in range(0, X_end - X_start): + buf[j * (X_end - X_start) + i] = ~Image[(Y_start + j) * Width + X_start + i] + self.DATA[(Y_start + j) * Width + X_start + i] = ~Image[(Y_start + j) * Width + X_start / 8 + i] + self.send_data2(buf) + + self.send_command(0x12) # DISPLAY REFRESH + epdconfig.delay_ms(200) # The delay here is necessary, 200uS at least!!! self.ReadBusy() - def display_4Gray(self, image): - self.send_command(0x92); - self.set_lut(); + self.send_command(0x92) + self.set_lut() self.send_command(0x10) - for i in range(0, int(EPD_WIDTH * EPD_HEIGHT / 8)): # EPD_WIDTH * EPD_HEIGHT / 4 - temp3=0 + + if self.width % 8 == 0: + linewidth = int(self.width / 8) + else: + linewidth = int(self.width / 8) + 1 + + buf = [0x00] * self.height * linewidth + + for i in range(0, int(EPD_WIDTH * EPD_HEIGHT / 8)): # EPD_WIDTH * EPD_HEIGHT / 4 + temp3 = 0 for j in range(0, 2): - temp1 = image[i*2+j] + temp1 = image[i * 2 + j] for k in range(0, 2): - temp2 = temp1&0xC0 - if(temp2 == 0xC0): - temp3 |= 0x01#white - elif(temp2 == 0x00): - temp3 |= 0x00 #black - elif(temp2 == 0x80): - temp3 |= 0x01 #gray1 - else: #0x40 - temp3 |= 0x00 #gray2 - temp3 <<= 1 - + temp2 = temp1 & 0xC0 + if temp2 == 0xC0: + temp3 |= 0x01 # white + elif temp2 == 0x00: + temp3 |= 0x00 # black + elif temp2 == 0x80: + temp3 |= 0x01 # gray1 + else: # 0x40 + temp3 |= 0x00 # gray2 + temp3 <<= 1 + temp1 <<= 2 - temp2 = temp1&0xC0 - if(temp2 == 0xC0): #white + temp2 = temp1 & 0xC0 + if temp2 == 0xC0: # white temp3 |= 0x01 - elif(temp2 == 0x00): #black + elif temp2 == 0x00: # black temp3 |= 0x00 - elif(temp2 == 0x80): - temp3 |= 0x01 #gray1 - else : #0x40 - temp3 |= 0x00 #gray2 - if(j!=1 or k!=1): + elif temp2 == 0x80: + temp3 |= 0x01 # gray1 + else: # 0x40 + temp3 |= 0x00 # gray2 + if j != 1 or k != 1: temp3 <<= 1 temp1 <<= 2 - self.send_data(temp3) - - self.send_command(0x13) - - for i in range(0, int(EPD_WIDTH * EPD_HEIGHT / 8)): #5808*4 46464 - temp3=0 + buf[i] = temp3 + self.send_data2(buf) + + self.send_command(0x13) + + for i in range(0, int(EPD_WIDTH * EPD_HEIGHT / 8)): # 5808*4 46464 + temp3 = 0 for j in range(0, 2): - temp1 = image[i*2+j] + temp1 = image[i * 2 + j] for k in range(0, 2): - temp2 = temp1&0xC0 - if(temp2 == 0xC0): - temp3 |= 0x01#white - elif(temp2 == 0x00): - temp3 |= 0x00 #black - elif(temp2 == 0x80): - temp3 |= 0x00 #gray1 - else: #0x40 - temp3 |= 0x01 #gray2 - temp3 <<= 1 - + temp2 = temp1 & 0xC0 + if temp2 == 0xC0: + temp3 |= 0x01 # white + elif temp2 == 0x00: + temp3 |= 0x00 # black + elif temp2 == 0x80: + temp3 |= 0x00 # gray1 + else: # 0x40 + temp3 |= 0x01 # gray2 + temp3 <<= 1 + temp1 <<= 2 - temp2 = temp1&0xC0 - if(temp2 == 0xC0): #white + temp2 = temp1 & 0xC0 + if temp2 == 0xC0: # white temp3 |= 0x01 - elif(temp2 == 0x00): #black + elif temp2 == 0x00: # black temp3 |= 0x00 - elif(temp2 == 0x80): - temp3 |= 0x00 #gray1 - else: #0x40 - temp3 |= 0x01 #gray2 - if(j!=1 or k!=1): + elif temp2 == 0x80: + temp3 |= 0x00 # gray1 + else: # 0x40 + temp3 |= 0x01 # gray2 + if j != 1 or k != 1: temp3 <<= 1 temp1 <<= 2 - self.send_data(temp3) - + buf[i] = temp3 + self.send_data2(buf) + self.Gray_SetLut() self.send_command(0x12) epdconfig.delay_ms(200) self.ReadBusy() # pass - + def Clear(self): + if self.width % 8 == 0: + linewidth = int(self.width / 8) + else: + linewidth = int(self.width / 8) + 1 + self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xFF) - + self.send_data2([0xff] * int(self.height * linewidth)) + self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xFF) - - self.send_command(0x12) + self.send_data2([0xff] * int(self.height * linewidth)) + + self.send_command(0x12) self.ReadBusy() def sleep(self): - self.send_command(0x02) # POWER_OFF + self.send_command(0x02) # POWER_OFF self.ReadBusy() - self.send_command(0x07) # DEEP_SLEEP + self.send_command(0x07) # DEEP_SLEEP self.send_data(0XA5) - + epdconfig.delay_ms(2000) epdconfig.module_exit() - -### END OF FILE ### +### END OF FILE ### diff --git a/lib/waveshare_epd/epd4in26.py b/lib/waveshare_epd/epd4in26.py new file mode 100644 index 0000000..ef895b5 --- /dev/null +++ b/lib/waveshare_epd/epd4in26.py @@ -0,0 +1,510 @@ +# ***************************************************************************** +# * | File : epd4in26.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2023-12-20 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 800 +EPD_HEIGHT = 480 + +GRAY1 = 0xff #white +GRAY2 = 0xC0 +GRAY3 = 0x80 #gray +GRAY4 = 0x00 #Blackest + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.GRAY1 = GRAY1 #white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 #gray + self.GRAY4 = GRAY4 #Blackest + + LUT_DATA_4Gray = [# #112bytes + 0x80, 0x48, 0x4A, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x48, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x48, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA8, 0x48, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x1E, 0x1C, 0x02, 0x00, + 0x05, 0x01, 0x05, 0x01, 0x02, + 0x08, 0x01, 0x01, 0x04, 0x04, + 0x00, 0x02, 0x00, 0x02, 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, 0x01, + 0x22, 0x22, 0x22, 0x22, 0x22, + 0x17, 0x41, 0xA8, 0x32, 0x30, + 0x00, 0x00 ] + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.SPI.writebytes2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + busy = epdconfig.digital_read(self.busy_pin) + while(busy == 1): + busy = epdconfig.digital_read(self.busy_pin) + epdconfig.delay_ms(20) + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xF7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Fast(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xC7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Part(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xFF) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_4GRAY(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xC7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + ''' + function : Setting the display window + parameter: + xstart : X-axis starting position + ystart : Y-axis starting position + xend : End position of X-axis + yend : End position of Y-axis + ''' + def SetWindow(self, x_start, y_start, x_end, y_end): + self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION + self.send_data(x_start & 0xFF) + self.send_data((x_start>>8) & 0x03) + self.send_data(x_end & 0xFF) + self.send_data((x_end>>8) & 0x03) + + self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION + self.send_data(y_start & 0xFF) + self.send_data((y_start >> 8) & 0xFF) + self.send_data(y_end & 0xFF) + self.send_data((y_end >> 8) & 0xFF) + + ''' + function : Set Cursor + parameter: + x : X-axis starting position + y : Y-axis starting position + ''' + def SetCursor(self, x, y): + self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER + # x point must be the multiple of 8 or the last 3 bits will be ignored + self.send_data(x & 0xFF) + self.send_data((x>>8) & 0x03) + + self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER + self.send_data(y & 0xFF) + self.send_data((y >> 8) & 0xFF) + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x18) # use the internal temperature sensor + self.send_data(0x80) + + self.send_command(0x0C) #set soft start + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0x80) + + self.send_command(0x01) # drive output control + self.send_data((self.height-1)%256) # Y + self.send_data((self.height-1)//256) # Y + self.send_data(0x02) + + self.send_command(0x3C) # Border Border setting + self.send_data(0x01) + + self.send_command(0x11) # data entry mode + self.send_data(0x01) # X-mode x+ y- + + self.SetWindow(0, self.height-1, self.width-1, 0) + + self.SetCursor(0, 0) + self.ReadBusy() + + # EPD hardware init end + return 0 + + def init_Fast(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x18) # use the internal temperature sensor + self.send_data(0x80) + + self.send_command(0x0C) #set soft start + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0x80) + + self.send_command(0x01) # drive output control + self.send_data((self.height-1)%256) # Y + self.send_data((self.height-1)//256) # Y + self.send_data(0x02) + + self.send_command(0x3C) # Border Border setting + self.send_data(0x01) + + self.send_command(0x11) # data entry mode + self.send_data(0x01) # X-mode x+ y- + + self.SetWindow(0, self.height-1, self.width-1, 0) + + self.SetCursor(0, 0) + self.ReadBusy() + + #TEMP (1.5s) + self.send_command(0x1A) + self.send_data(0x5A) + + self.send_command(0x22) + self.send_data(0x91) + self.send_command(0x20) + + self.ReadBusy() + + # EPD hardware init end + return 0 + + def Lut(self): + self.send_command(0x32) + for count in range(0, 105): + self.send_data(self.LUT_DATA_4Gray[count]) + + self.send_command(0x03) #VGH + self.send_data(self.LUT_DATA_4Gray[105]) + + self.send_command(0x04) # + self.send_data(self.LUT_DATA_4Gray[106]) #VSH1 + self.send_data(self.LUT_DATA_4Gray[107]) #VSH2 + self.send_data(self.LUT_DATA_4Gray[108]) #VSL + + self.send_command(0x2C) #VCOM Voltage + self.send_data(self.LUT_DATA_4Gray[109]) #0x1C + + def init_4GRAY(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x18) # use the internal temperature sensor + self.send_data(0x80) + + self.send_command(0x0C) #set soft start + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0x80) + + self.send_command(0x01) # drive output control + self.send_data((self.height-1)%256) # Y + self.send_data((self.height-1)//256) # Y + self.send_data(0x02) + + self.send_command(0x3C) # Border Border setting + self.send_data(0x01) + + self.send_command(0x11) # data entry mode + self.send_data(0x01) # X-mode x+ y- + + self.SetWindow(0, self.height-1, self.width-1, 0) + + self.SetCursor(0, 0) + self.ReadBusy() + + self.Lut() + # EPD hardware init end + return 0 + + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if imwidth == self.width and imheight == self.height: + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif imwidth == self.height and imheight == self.width: + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i=0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = self.height - x - 1 + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + return buf + + def display(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.TurnOnDisplay() + + def display_Base(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.send_command(0x26) + self.send_data2(image) + + self.TurnOnDisplay() + + def display_Fast(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.TurnOnDisplay_Fast() + + def display_Partial(self, Image): + + # Reset + self.reset() + + self.send_command(0x18) #BorderWavefrom + self.send_data(0x80) + + self.send_command(0x3C) #BorderWavefrom + self.send_data(0x80) + + self.send_command(0x01) # drive output control + self.send_data((self.height-1)%256) # Y + self.send_data((self.height-1)//256) # Y + + self.send_command(0x11) # data entry mode + self.send_data(0x01) # X-mode x+ y- + + self.SetWindow(0, self.height-1, self.width-1, 0) + + self.SetCursor(0, 0) + + self.send_command(0x24) #Write Black and White image to RAM + self.send_data2(Image) + + self.TurnOnDisplay_Part() + + def display_4Gray(self, image): + self.send_command(0x24) + for i in range(0, 48000): #5808*4 46464 + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else: #0x40 + temp3 |= 0x00 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else : #0x40 + temp3 |= 0x00 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0x26) + for i in range(0, 48000): #5808*4 46464 + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.TurnOnDisplay_4GRAY() + + def Clear(self): + self.send_command(0x24) + self.send_data2([0xFF] * (int(self.width/8) * self.height)) + + self.send_command(0x26) + self.send_data2([0xFF] * (int(self.width/8) * self.height)) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### diff --git a/lib/waveshare_epd/epd4in2_V2.py b/lib/waveshare_epd/epd4in2_V2.py new file mode 100644 index 0000000..105d57b --- /dev/null +++ b/lib/waveshare_epd/epd4in2_V2.py @@ -0,0 +1,530 @@ +# ***************************************************************************** +# * | File : epd4in2_V2.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2023-09-13 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + + +import logging +from . import epdconfig +from PIL import Image +import RPi.GPIO as GPIO + +# Display resolution +EPD_WIDTH = 400 +EPD_HEIGHT = 300 + +GRAY1 = 0xff # white +GRAY2 = 0xC0 +GRAY3 = 0x80 # gray +GRAY4 = 0x00 # Blackest + +logger = logging.getLogger(__name__) + + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.Seconds_1_5S = 0 + self.Seconds_1S = 1 + self.GRAY1 = GRAY1 # white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 # gray + self.GRAY4 = GRAY4 # Blackest + + + LUT_ALL=[ 0x01, 0x0A, 0x1B, 0x0F, 0x03, 0x01, 0x01, + 0x05, 0x0A, 0x01, 0x0A, 0x01, 0x01, 0x01, + 0x05, 0x08, 0x03, 0x02, 0x04, 0x01, 0x01, + 0x01, 0x04, 0x04, 0x02, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x0A, 0x1B, 0x0F, 0x03, 0x01, 0x01, + 0x05, 0x4A, 0x01, 0x8A, 0x01, 0x01, 0x01, + 0x05, 0x48, 0x03, 0x82, 0x84, 0x01, 0x01, + 0x01, 0x84, 0x84, 0x82, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x0A, 0x1B, 0x8F, 0x03, 0x01, 0x01, + 0x05, 0x4A, 0x01, 0x8A, 0x01, 0x01, 0x01, + 0x05, 0x48, 0x83, 0x82, 0x04, 0x01, 0x01, + 0x01, 0x04, 0x04, 0x02, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x8A, 0x1B, 0x8F, 0x03, 0x01, 0x01, + 0x05, 0x4A, 0x01, 0x8A, 0x01, 0x01, 0x01, + 0x05, 0x48, 0x83, 0x02, 0x04, 0x01, 0x01, + 0x01, 0x04, 0x04, 0x02, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x8A, 0x9B, 0x8F, 0x03, 0x01, 0x01, + 0x05, 0x4A, 0x01, 0x8A, 0x01, 0x01, 0x01, + 0x05, 0x48, 0x03, 0x42, 0x04, 0x01, 0x01, + 0x01, 0x04, 0x04, 0x42, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x07, 0x17, 0x41, 0xA8, + 0x32, 0x30 ] + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(100) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(100) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xF7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Fast(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xC7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Partial(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xFF) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_4GRAY(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xCF) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def init(self): + if epdconfig.module_init() != 0: + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x21) # Display update control + self.send_data(0x40) + self.send_data(0x00) + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x05) + + self.send_command(0x11) # data entry mode + self.send_data(0x03) # X-mode + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x31) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x2B) + self.send_data(0x01) + + self.send_command(0x4E) + self.send_data(0x00) + + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + return 0 + + def init_fast(self, mode): + if epdconfig.module_init() != 0: + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x21) # Display update control + self.send_data(0x40) + self.send_data(0x00) + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x05) + + if mode == self.Seconds_1_5S: + self.send_command(0x1A) + self.send_data(0x6E) + else : + self.send_command(0x1A) + self.send_data(0x5A) + + self.send_command(0x22) # Load temperature value + self.send_data(0x91) + self.send_command(0x20) + self.ReadBusy() + + self.send_command(0x11) # data entry mode + self.send_data(0x03) # X-mode + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x31) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x2B) + self.send_data(0x01) + + self.send_command(0x4E) + self.send_data(0x00) + + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + return 0 + + def Lut(self): + self.send_command(0x32) + for i in range(227): + self.send_data(self.LUT_ALL[i]) + + self.send_command(0x3F) + self.send_data(self.LUT_ALL[227]) + + self.send_command(0x03) + self.send_data(self.LUT_ALL[228]) + + self.send_command(0x04) + self.send_data(self.LUT_ALL[229]) + self.send_data(self.LUT_ALL[230]) + self.send_data(self.LUT_ALL[231]) + + self.send_command(0x2c) + self.send_data(self.LUT_ALL[232]) + + + + def Init_4Gray(self): + if epdconfig.module_init() != 0: + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x21) # Display update control + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x03) + + self.send_command(0x0C) # BTST + self.send_data(0x8B) # 8B + self.send_data(0x9C) # 9C + self.send_data(0xA4) # 96 A4 + self.send_data(0x0F) # 0F + + self.Lut() + + self.send_command(0x11) # data entry mode + self.send_data(0x03) # X-mode + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x31) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x2B) + self.send_data(0x01) + + self.send_command(0x4E) + self.send_data(0x00) + + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if imwidth == self.width and imheight == self.height: + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif imwidth == self.height and imheight == self.width: + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i = 0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if imwidth == self.width and imheight == self.height: + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0xC0: + pixels[x, y] = 0x80 + elif pixels[x, y] == 0x80: + pixels[x, y] = 0x40 + i = i + 1 + if i % 4 == 0: + buf[int((x + (y * self.width)) / 4)] = ( + (pixels[x - 3, y] & 0xc0) | (pixels[x - 2, y] & 0xc0) >> 2 | ( + pixels[x - 1, y] & 0xc0) >> 4 | (pixels[x, y] & 0xc0) >> 6) + + elif imwidth == self.height and imheight == self.width: + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = x + if pixels[x, y] == 0xC0: + pixels[x, y] = 0x80 + elif pixels[x, y] == 0x80: + pixels[x, y] = 0x40 + i = i + 1 + if i % 4 == 0: + buf[int((newx + (newy * self.width)) / 4)] = ( + (pixels[x, y - 3] & 0xc0) | (pixels[x, y - 2] & 0xc0) >> 2 | ( + pixels[x, y - 1] & 0xc0) >> 4 | (pixels[x, y] & 0xc0) >> 6) + + return buf + + def Clear(self): + if self.width % 8 == 0: + linewidth = int(self.width / 8) + else: + linewidth = int(self.width / 8) + 1 + + self.send_command(0x24) + self.send_data2([0xff] * int(self.height * linewidth)) + + self.send_command(0x26) + self.send_data2([0xff] * int(self.height * linewidth)) + + self.TurnOnDisplay() + + def display(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.send_command(0x26) + self.send_data2(image) + + self.TurnOnDisplay() + + def display_Fast(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.send_command(0x26) + self.send_data2(image) + + self.TurnOnDisplay_Fast() + + def display_Partial(self, Image): + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x80) + + self.send_command(0x21) # Display update control + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x80) + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x31) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x2B) + self.send_data(0x01) + + self.send_command(0x4E) + self.send_data(0x00) + + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x24) # WRITE_RAM + self.send_data2(Image) + self.TurnOnDisplay_Partial() + + def display_4Gray(self, image): + if self.width % 8 == 0: + linewidth = int(self.width / 8) + else: + linewidth = int(self.width / 8) + 1 + + buf = [0x00] * self.height * linewidth + + self.send_command(0x24) + for i in range(0, int(EPD_WIDTH * EPD_HEIGHT / 8)): # EPD_WIDTH * EPD_HEIGHT / 4 + temp3 = 0 + for j in range(0, 2): + temp1 = image[i * 2 + j] + for k in range(0, 2): + temp2 = temp1 & 0xC0 + if temp2 == 0xC0: + temp3 |= 0x01 # white + elif temp2 == 0x00: + temp3 |= 0x00 # black + elif temp2 == 0x80: + temp3 |= 0x00 # gray1 + else: # 0x40 + temp3 |= 0x01 # gray2 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1 & 0xC0 + if temp2 == 0xC0: # white + temp3 |= 0x01 + elif temp2 == 0x00: # black + temp3 |= 0x00 + elif temp2 == 0x80: + temp3 |= 0x00 # gray1 + else: # 0x40 + temp3 |= 0x01 # gray2 + if j != 1 or k != 1: + temp3 <<= 1 + temp1 <<= 2 + buf[i] = temp3 + self.send_data2(buf) + + self.send_command(0x26) + for i in range(0, int(EPD_WIDTH * EPD_HEIGHT / 8)): + temp3 = 0 + for j in range(0, 2): + temp1 = image[i * 2 + j] + for k in range(0, 2): + temp2 = temp1 & 0xC0 + if temp2 == 0xC0: + temp3 |= 0x01 # white + elif temp2 == 0x00: + temp3 |= 0x00 # black + elif temp2 == 0x80: + temp3 |= 0x01 # gray1 + else: # 0x40 + temp3 |= 0x00 # gray2 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1 & 0xC0 + if temp2 == 0xC0: # white + temp3 |= 0x01 + elif temp2 == 0x00: # black + temp3 |= 0x00 + elif temp2 == 0x80: + temp3 |= 0x01 # gray1 + else: # 0x40 + temp3 |= 0x00 # gray2 + if j != 1 or k != 1: + temp3 <<= 1 + temp1 <<= 2 + buf[i] = temp3 + self.send_data2(buf) + + self.TurnOnDisplay_4GRAY() + # pass + + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### diff --git a/lib/waveshare_epd/epd4in2b_V2.py b/lib/waveshare_epd/epd4in2b_V2.py index 1ad789c..0bd31b8 100644 --- a/lib/waveshare_epd/epd4in2b_V2.py +++ b/lib/waveshare_epd/epd4in2b_V2.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V4.0 -# * | Date : 2019-06-20 +# * | This version: V4.1 +# * | Date : 2022-08-10 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -34,6 +34,8 @@ from . import epdconfig EPD_WIDTH = 400 EPD_HEIGHT = 300 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -42,6 +44,11 @@ class EPD: self.cs_pin = epdconfig.CS_PIN self.width = EPD_WIDTH self.height = EPD_HEIGHT + self.flag = 0 + + if (epdconfig.module_init(cleanup=True) != 0): + return -1 + # Hardware reset def reset(self): @@ -55,53 +62,114 @@ class EPD: def send_command(self, command): epdconfig.digital_write(self.dc_pin, 0) epdconfig.digital_write(self.cs_pin, 0) - epdconfig.spi_writebyte([command]) + epdconfig.DEV_SPI_write(command) epdconfig.digital_write(self.cs_pin, 1) def send_data(self, data): epdconfig.digital_write(self.dc_pin, 1) epdconfig.digital_write(self.cs_pin, 0) - epdconfig.spi_writebyte([data]) + epdconfig.DEV_SPI_write(data) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") - self.send_command(0x71); - while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy - self.send_command(0x71); - epdconfig.delay_ms(20) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy") + if(self.flag == 1): + while(epdconfig.digital_read(self.busy_pin) == 1): + epdconfig.delay_ms(100) + + else: + while(epdconfig.digital_read(self.busy_pin) == 0): + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + if(self.flag == 1): + self.send_command(0x22) + self.send_data(0xF7) + self.send_command(0x20) + self.ReadBusy() + + else: + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() def init(self): - if (epdconfig.module_init() != 0): - return -1 - + i = 0x00 self.reset() - - self.send_command(0x04); - self.ReadBusy(); + self.send_command(0x2F) + epdconfig.delay_ms(100) + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + i = epdconfig.DEV_SPI_read() + epdconfig.digital_write(self.cs_pin, 1) + # print(i) - self.send_command(0x00); - self.send_data(0x0f); + if(i == 0x01): + self.flag = 1 + self.ReadBusy() + self.send_command(0x12) + self.ReadBusy() + + self.send_command(0x3C) + self.send_data(0x05) + + self.send_command(0x18) + self.send_data(0x80) + + self.send_command(0x11) + self.send_data(0x03) + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(self.width//8-1) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data((self.height-1)%256) + self.send_data((self.height-1)//256) + + self.send_command(0x4E) + self.send_data(0x00) + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + else: + self.flag = 0 + self.send_command(0x04) # POWER_ON + self.ReadBusy() + + self.send_command(0x00) # panel setting + self.send_data(0x0f) return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): newx = y @@ -111,39 +179,79 @@ class EPD: return buf def display(self, imageblack, imagered): - self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(imageblack[i]) + high = self.height + if( self.width % 8 == 0) : + wide = self.width // 8 + else : + wide = self.width // 8 + 1 - self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(imagered[i]) + if(self.flag == 1): + self.send_command(0x24) + for j in range(0, high): + for i in range(0, wide): + self.send_data(imageblack[i + j * wide]) + + self.send_command(0x26) + for j in range(0, high): + for i in range(0, wide): + self.send_data(~imagered[i + j * wide]) - self.send_command(0x12) - epdconfig.delay_ms(20) - self.ReadBusy() + else: + self.send_command(0x10) + for j in range(0, high): + for i in range(0, wide): + self.send_data(imageblack[i + j * wide]) + + self.send_command(0x13) + for j in range(0, high): + for i in range(0, wide): + self.send_data(~imagered[i + j * wide]) + + self.TurnOnDisplay() def Clear(self): - self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xFF) - - self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xFF) + high = self.height + if( self.width % 8 == 0) : + wide = self.width // 8 + else : + wide = self.width // 8 + 1 + + if(self.flag == 1): + self.send_command(0x24) + for j in range(0, high): + for i in range(0, wide): + self.send_data(0xff) + + self.send_command(0x26) + for j in range(0, high): + for i in range(0, wide): + self.send_data(0x00) - self.send_command(0x12) - epdconfig.delay_ms(20) - self.ReadBusy() + else: + self.send_command(0x10) + for j in range(0, high): + for i in range(0, wide): + self.send_data(0xff) + + self.send_command(0x13) + for j in range(0, high): + for i in range(0, wide): + self.send_data(0x00) + + self.TurnOnDisplay() def sleep(self): - self.send_command(0X50); - self.send_data(0xf7); #border floating - - self.send_command(0X02); #power off - self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal - self.send_command(0X07); #deep sleep - self.send_data(0xA5); + if(self.flag == 1): + self.send_command(0X10) + self.send_data(0x03) + + else: + self.send_command(0X50) + self.send_data(0xf7) + self.send_command(0X02) + self.ReadBusy() + self.send_command(0X07) + self.send_data(0xA5) epdconfig.delay_ms(2000) epdconfig.module_exit() diff --git a/lib/waveshare_epd/epd4in2b_V2.pyc b/lib/waveshare_epd/epd4in2b_V2.pyc new file mode 100644 index 0000000..7152bbb Binary files /dev/null and b/lib/waveshare_epd/epd4in2b_V2.pyc differ diff --git a/lib/waveshare_epd/epd4in2b_V2_old.py b/lib/waveshare_epd/epd4in2b_V2_old.py new file mode 100644 index 0000000..631da1e --- /dev/null +++ b/lib/waveshare_epd/epd4in2b_V2_old.py @@ -0,0 +1,259 @@ +# ***************************************************************************** +# * | File : epd4in2bc.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V4.1 +# * | Date : 2022-08-10 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 400 +EPD_HEIGHT = 300 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.flag = 0 + + if (epdconfig.module_init(cleanup=True) != 0): + return -1 + + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(5) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.DEV_SPI_write(command) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.DEV_SPI_write(data) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + if(self.flag == 1): + while(epdconfig.digital_read(self.busy_pin) == 1): + epdconfig.delay_ms(100) + + else: + while(epdconfig.digital_read(self.busy_pin) == 0): + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + if(self.flag == 1): + self.send_command(0x22) + self.send_data(0xF7) + self.send_command(0x20) + self.ReadBusy() + + else: + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def init(self): + i = 0x00 + self.reset() + self.send_command(0x2F) + epdconfig.delay_ms(100) + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + i = epdconfig.DEV_SPI_read() + epdconfig.digital_write(self.cs_pin, 1) + # print(i) + + if(i == 0x01): + self.flag = 1 + self.ReadBusy() + self.send_command(0x12) + self.ReadBusy() + + self.send_command(0x3C) + self.send_data(0x05) + + self.send_command(0x18) + self.send_data(0x80) + + self.send_command(0x11) + self.send_data(0x03) + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(self.width//8-1) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data((self.height-1)%256) + self.send_data((self.height-1)//256) + + self.send_command(0x4E) + self.send_data(0x00) + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + else: + self.flag = 0 + self.send_command(0x04) # POWER_ON + self.ReadBusy() + + self.send_command(0x00) # panel setting + self.send_data(0x0f) + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, imageblack, imagered): + high = self.height + if( self.width % 8 == 0) : + wide = self.width // 8 + else : + wide = self.width // 8 + 1 + + if(self.flag == 1): + self.send_command(0x24) + for j in range(0, high): + for i in range(0, wide): + self.send_data(imageblack[i + j * wide]) + + self.send_command(0x26) + for j in range(0, high): + for i in range(0, wide): + self.send_data(~imagered[i + j * wide]) + + else: + self.send_command(0x10) + for j in range(0, high): + for i in range(0, wide): + self.send_data(imageblack[i + j * wide]) + + self.send_command(0x13) + for j in range(0, high): + for i in range(0, wide): + self.send_data(imagered[i + j * wide]) + + self.TurnOnDisplay() + + def Clear(self): + high = self.height + if( self.width % 8 == 0) : + wide = self.width // 8 + else : + wide = self.width // 8 + 1 + + if(self.flag == 1): + self.send_command(0x24) + for j in range(0, high): + for i in range(0, wide): + self.send_data(0xff) + + self.send_command(0x26) + for j in range(0, high): + for i in range(0, wide): + self.send_data(0x00) + + else: + self.send_command(0x10) + for j in range(0, high): + for i in range(0, wide): + self.send_data(0xff) + + self.send_command(0x13) + for j in range(0, high): + for i in range(0, wide): + self.send_data(0xff) + + self.TurnOnDisplay() + + def sleep(self): + if(self.flag == 1): + self.send_command(0X10) + self.send_data(0x03) + + else: + self.send_command(0X50) + self.send_data(0xf7) + self.send_command(0X02) + self.ReadBusy() + self.send_command(0X07) + self.send_data(0xA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd4in2b_V2_old.pyc b/lib/waveshare_epd/epd4in2b_V2_old.pyc new file mode 100644 index 0000000..565e5be Binary files /dev/null and b/lib/waveshare_epd/epd4in2b_V2_old.pyc differ diff --git a/lib/waveshare_epd/epd4in2bc.py b/lib/waveshare_epd/epd4in2bc.py index ab0e6ee..c948f2f 100644 --- a/lib/waveshare_epd/epd4in2bc.py +++ b/lib/waveshare_epd/epd4in2bc.py @@ -34,6 +34,8 @@ from . import epdconfig EPD_WIDTH = 400 EPD_HEIGHT = 300 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -65,10 +67,10 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -90,21 +92,21 @@ class EPD: return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): newx = y diff --git a/lib/waveshare_epd/epd4in37g.py b/lib/waveshare_epd/epd4in37g.py new file mode 100644 index 0000000..758b19c --- /dev/null +++ b/lib/waveshare_epd/epd4in37g.py @@ -0,0 +1,242 @@ +# ***************************************************************************** +# * | File : epd4in37g.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2022-08-15 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# ******************************************************************************/ +# 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. +# + +import logging +from . import epdconfig + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 512 +EPD_HEIGHT = 368 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.BLACK = 0x000000 # 00 BGR + self.WHITE = 0xffffff # 01 + self.YELLOW = 0x00ffff # 10 + self.RED = 0x0000ff # 11 + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) # module reset + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusyH(self): + logger.debug("e-Paper busy H") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(5) + logger.debug("e-Paper busy H release") + + def ReadBusyL(self): + logger.debug("e-Paper busy L") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: busy, 1: idle + epdconfig.delay_ms(5) + logger.debug("e-Paper busy L release") + + def TurnOnDisplay(self): + self.send_command(0x12) # DISPLAY_REFRESH + self.send_data(0x00) + self.ReadBusyH() + + self.send_command(0x02) # POWER_OFF + self.send_data(0X00) + self.ReadBusyH() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + self.ReadBusyH() + epdconfig.delay_ms(30) + + self.send_command(0xAA) + self.send_data(0x49) + self.send_data(0x55) + self.send_data(0x20) + self.send_data(0x08) + self.send_data(0x09) + self.send_data(0x18) + + self.send_command(0x01) + self.send_data(0x3F) + + self.send_command(0x00) + self.send_data(0x4F) + self.send_data(0x69) + + + self.send_command(0x05) + self.send_data(0x40) + self.send_data(0x1F) + self.send_data(0x1F) + self.send_data(0x2C) + + self.send_command(0x08) + self.send_data(0x6F) + self.send_data(0x1F) + self.send_data(0x1F) + self.send_data(0x22) + + # =================== + # 20211212 + # First setting + self.send_command(0x06) + self.send_data(0x6F) + self.send_data(0x1F) + self.send_data(0x17) + self.send_data(0x17) + # =================== + + self.send_command(0x03) + self.send_data(0x00) + self.send_data(0x54) + self.send_data(0x00) + self.send_data(0x44) + + self.send_command(0x60) + self.send_data(0x02) + self.send_data(0x00) + # Please notice that PLL must be set for version 2 IC + self.send_command(0x30) + self.send_data(0x08) + + self.send_command(0x50) + self.send_data(0x3F) + + self.send_command(0x61) + self.send_data(0x02) + self.send_data(0x00) + self.send_data(0x01) + self.send_data(0x70) + + self.send_command(0xE3) + self.send_data(0x2F) + + self.send_command(0x84) + self.send_data(0x01) + return 0 + + def getbuffer(self, image): + # Create a pallette with the 4 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 255,255,0, 255,0,0) + (0,0,0)*252) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 4 colors, dithering if needed + image_4color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_4color = bytearray(image_4color.tobytes('raw')) + + # into a single byte to transfer to the panel + buf = [0x00] * int(self.width * self.height / 4) + idx = 0 + for i in range(0, len(buf_4color), 4): + buf[idx] = (buf_4color[i] << 6) + (buf_4color[i+1] << 4) + (buf_4color[i+2] << 2) + buf_4color[i+3] + idx += 1 + return buf + + def display(self, image): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x04) + self.ReadBusyH() + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(image[i + j * Width]) + self.TurnOnDisplay() + + def Clear(self, color=0x55): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x04) + self.ReadBusyH() + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(color) + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.send_data(0x00) + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd5in65f.py b/lib/waveshare_epd/epd5in65f.py index 28b7978..711b4a3 100644 --- a/lib/waveshare_epd/epd5in65f.py +++ b/lib/waveshare_epd/epd5in65f.py @@ -40,6 +40,8 @@ import io EPD_WIDTH = 600 EPD_HEIGHT = 448 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -78,23 +80,24 @@ class EPD: epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) - def send_data_bulk(self, data): + # send a lot of data + def send_data2(self, data): epdconfig.digital_write(self.dc_pin, 1) epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte2(data) epdconfig.digital_write(self.cs_pin, 1) def ReadBusyHigh(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def ReadBusyLow(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -151,7 +154,7 @@ class EPD: elif(imwidth == self.height and imheight == self.width): image_temp = image.rotate(90, expand=True) else: - logging.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) # Convert the soruce image to the 7 colors, dithering if needed image_7color = image_temp.convert("RGB").quantize(palette=pal_image) @@ -175,7 +178,7 @@ class EPD: self.send_data(0xC0) self.send_command(0x10) - self.send_data_bulk(image) + self.send_data2(image) self.send_command(0x04) #0x04 self.ReadBusyHigh() self.send_command(0x12) #0x12 @@ -194,7 +197,7 @@ class EPD: # Set all pixels to white buf = [0x11] * int(self.width * self.height / 2) - self.send_data_bulk(buf) + self.send_data2(buf) self.send_command(0x04) #0x04 self.ReadBusyHigh() diff --git a/lib/waveshare_epd/epd5in79.py b/lib/waveshare_epd/epd5in79.py new file mode 100644 index 0000000..c3145d8 --- /dev/null +++ b/lib/waveshare_epd/epd5in79.py @@ -0,0 +1,672 @@ +# ***************************************************************************** +# * | File : epd5in79.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2024-03-05 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 792 +EPD_HEIGHT = 272 + +GRAY1 = 0xff #white +GRAY2 = 0xC0 +GRAY3 = 0x80 #gray +GRAY4 = 0x00 #Blackest + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.GRAY1 = GRAY1 #white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 #gray + self.GRAY4 = GRAY4 #Blackest + + self.LUT_DATA_4Gray = [ + 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, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x01, 0x4A, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x82, 0x42, 0x00, 0x00, 0x10, 0x00, + 0x01, 0x8A, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x01, 0x41, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x82, 0x42, 0x00, 0x00, 0x10, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x01, 0x81, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x82, 0x42, 0x00, 0x00, 0x10, 0x00, + 0x01, 0x41, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x01, 0x8A, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x82, 0x42, 0x00, 0x00, 0x10, 0x00, + 0x01, 0x4A, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + + 0x02, 0x00, 0x00, + 0x22, 0x17, 0x41, 0xA8, 0x32, 0x40, ] + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(1) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(200) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x22) + self.send_data(0xF7) + self.send_command(0x20) # DISPLAY REFRESH + epdconfig.delay_ms(100) # The delay here is necessary, 200uS at least!!! + self.ReadBusy() # waiting for the electronic paper IC to release the idle signal + + def TurnOnDisplay_Fast(self): + self.send_command(0x22) + self.send_data(0xC7) + self.send_command(0x20) # DISPLAY REFRESH + epdconfig.delay_ms(100) # The delay here is necessary, 200uS at least!!! + self.ReadBusy() # waiting for the electronic paper IC to release the idle signal + + def TurnOnDisplay_Partial(self): + self.send_command(0x22) + self.send_data(0xFF) + self.send_command(0x20) # DISPLAY REFRESH + epdconfig.delay_ms(100) # The delay here is necessary, 200uS at least!!! + self.ReadBusy() # waiting for the electronic paper IC to release the idle signal + + def TurnOnDisplay_4GRAY(self): + self.send_command(0x22) + self.send_data(0xCF) + self.send_command(0x20) # DISPLAY REFRESH + epdconfig.delay_ms(100) # The delay here is necessary, 200uS at least!!! + self.ReadBusy() # waiting for the electronic paper IC to release the idle signal + + def EPD_5in79_Lut(self): + self.send_command(0x32) + self.send_data2(self.LUT_DATA_4Gray[:227]) + self.send_command(0x3f) + self.send_data(self.LUT_DATA_4Gray[227]) + + self.send_command(0x03) + self.send_data(self.LUT_DATA_4Gray[228]) + + self.send_command(0x04) + self.send_data(self.LUT_DATA_4Gray[229]) + self.send_data(self.LUT_DATA_4Gray[230]) + self.send_data(self.LUT_DATA_4Gray[231]) + + self.send_command(0x2C) + self.send_data(self.LUT_DATA_4Gray[232]) + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + self.ReadBusy() # waiting for the electronic paper IC to release the idle signal + self.send_command(0x12) # POWER ON + self.ReadBusy() # waiting for the electronic paper IC to release the idle signal + + self.send_command(0x11) + self.send_data(0x01) + + self.send_command(0x44) # Set Ram X- address Start / End position + self.send_data(0x00) # XStart, POR = 00h + self.send_data(0x31) # 400/8-1 + self.send_command(0x45) # Set Ram Y- address Start / End position + self.send_data(0x0f) + self.send_data(0x01) # 300-1 + self.send_data(0x00) # YEnd L + self.send_data(0x00) # YEnd H + + self.send_command(0x4e) + self.send_data(0x00) + self.send_command(0x4f) + self.send_data(0x0f) + self.send_data(0x01) + + self.ReadBusy() + + self.send_command(0x91) + self.send_data(0x00) + + self.send_command(0xC4) # Set Ram X- address Start / End position + self.send_data(0x31) # XStart, POR = 00h + self.send_data(0x00) # 400/8-1 + self.send_command(0xC5) # Set Ram Y- address Start / End position + self.send_data(0x0f) + self.send_data(0x01) # 300-1 + self.send_data(0x00) # YEnd L + self.send_data(0x00) # YEnd H + + self.send_command(0xCE) + self.send_data(0x31) + self.send_command(0xCF) + self.send_data(0x0f) + self.send_data(0x01) + + self.ReadBusy() + + return 0 + + def init_Fast(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + self.ReadBusy() + self.send_command(0x12) + self.ReadBusy() + + self.send_command(0x18) + self.send_data(0x80) + + self.send_command(0x22) + self.send_data(0xB1) + self.send_command(0x20) + self.ReadBusy() + + self.send_command(0x1A) + self.send_data(0x64) + self.send_data(0x00) + + self.send_command(0x22) + self.send_data(0x91) + self.send_command(0x20) + self.ReadBusy() + + self.send_command(0x11) + self.send_data(0x01) + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x31) + self.send_command(0x45) + self.send_data(0x0f) + self.send_data(0x01) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x4e) + self.send_data(0x00) + self.send_command(0x4f) + self.send_data(0x0f) + self.send_data(0x01) + + self.ReadBusy() + + self.send_command(0x91) + self.send_data(0x00) + + self.send_command(0xC4) + self.send_data(0x31) + self.send_data(0x00) + self.send_command(0xC5) + self.send_data(0x0f) + self.send_data(0x01) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0xCe) + self.send_data(0x31) + self.send_command(0xCf) + self.send_data(0x0f) + self.send_data(0x01) + + self.ReadBusy() + + return 0 + + def init_Partial(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + self.ReadBusy() + self.send_command(0x12) + self.ReadBusy() + + self.send_command(0x3C) + self.send_data(0x80) + + return 0 + + def init_4Gray(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + self.ReadBusy() + self.send_command(0x12) + self.ReadBusy() + + self.send_command(0x0C) + self.send_data(0x8B) + self.send_data(0x9C) + self.send_data(0xA6) + self.send_data(0x0F) + + self.send_command(0x3C) + self.send_data(0x81) + + self.ReadBusy() + + self.send_command(0x11) + self.send_data(0x01) + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x31) + self.send_command(0x45) + self.send_data(0x0f) + self.send_data(0x01) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x4e) + self.send_data(0x00) + self.send_command(0x4f) + self.send_data(0x0f) + self.send_data(0x01) + + self.ReadBusy() + + self.send_command(0x91) + self.send_data(0x00) + + self.send_command(0xC4) + self.send_data(0x31) + self.send_data(0x00) + self.send_command(0xC5) + self.send_data(0x0f) + self.send_data(0x01) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0xCe) + self.send_data(0x31) + self.send_command(0xCf) + self.send_data(0x0f) + self.send_data(0x01) + + self.EPD_5in79_Lut() + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if imwidth == self.width and imheight == self.height: + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif imwidth == self.height and imheight == self.width: + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i=0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = self.height - x - 1 + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + return buf + + def display(self, imageblack): + Width =int(self.width / 16)+1 + Width1 =int(self.width / 8) + + self.send_command(0x24) + for i in range(self.height): + self.send_data2(imageblack[i * Width1 : i * Width1+Width]) + self.send_command(0X26) + self.send_data2([0x00] * 13600) + + self.send_command(0xA4) + for i in range(self.height): + self.send_data2(imageblack[i * Width1 + Width - 1 : i * Width1 + Width * 2 - 1]) + self.send_command(0xA6) + self.send_data2([0x00] * 13600) + + self.TurnOnDisplay() + + def display_Base(self, imageblack): + Width =int(self.width / 16)+1 + Width1 =int(self.width / 8) + + self.send_command(0x24) + for i in range(self.height): + self.send_data2(imageblack[i * Width1 : i * Width1+Width]) + self.send_command(0X26) + self.send_data2([0x00] * 13600) + + self.send_command(0xA4) + for i in range(self.height): + self.send_data2(imageblack[i * Width1 + Width - 1 : i * Width1 + Width * 2 - 1]) + self.send_command(0xA6) + self.send_data2([0x00] * 13600) + + self.TurnOnDisplay() + + self.send_command(0x26) + for i in range(self.height): + self.send_data2(imageblack[i * Width1 : i * Width1+Width]) + + self.send_command(0xA6) + for i in range(self.height): + self.send_data2(imageblack[i * Width1 + Width - 1 : i * Width1 + Width * 2 - 1]) + + def display_Base_color(self, color): + Width =int(self.width / 16)+1 + Width1 =int(self.width / 8) + + self.send_command(0x24) + self.send_data2([color] * 13600) + self.send_command(0X26) + self.send_data2([0x00] * 13600) + + self.send_command(0xA4) + self.send_data2([color] * 13600) + self.send_command(0xA6) + self.send_data2([0x00] * 13600) + + self.TurnOnDisplay() + + self.send_command(0x26) + self.send_data2([color] * 13600) + + self.send_command(0xA6) + self.send_data2([color] * 13600) + + def display_Fast(self, imageblack): + Width =int(self.width / 16)+1 + Width1 =int(self.width / 8) + + self.send_command(0x24) + for i in range(self.height): + self.send_data2(imageblack[i * Width1 : i * Width1+Width]) + self.send_command(0X26) + self.send_data2([0x00] * 13600) + + self.send_command(0xA4) + for i in range(self.height): + self.send_data2(imageblack[i * Width1 + Width - 1 : i * Width1 + Width * 2 - 1]) + self.send_command(0xA6) + self.send_data2([0x00] * 13600) + + self.TurnOnDisplay_Fast() + + def display_Partial(self, Image): + Width =int(self.width / 16)+1 + Width1 =int(self.width / 8) + Height = self.height + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x31) + self.send_command(0x45) + self.send_data(0x0f) + self.send_data(0x01) # 300-1 + self.send_data(0x00) # YEnd L + self.send_data(0x00) # YEnd H + + self.send_command(0x4e) + self.send_data(0x00) + self.send_command(0x4f) + self.send_data(0x0f) + self.send_data(0x01) + + self.send_command(0x24) + for i in range(Height): + self.send_data2(Image[i * Width1 : i * Width1+Width]) + + self.send_command(0xC4) # Set Ram X- address Start / End position + self.send_data(0x31) # XStart, POR = 00h + self.send_data(0x00) # 400/8-1 + self.send_command(0xC5) # Set Ram Y- address Start / End position + self.send_data(0x0f) + self.send_data(0x01) # 300-1 + self.send_data(0x00) # YEnd L + self.send_data(0x00) # YEnd H + + self.send_command(0xCe) + self.send_data(0x31) + self.send_command(0xCf) + self.send_data(0x0f) + self.send_data(0x01) + + self.send_command(0xA4) + for i in range(Height): + self.send_data2(Image[i * Width1 + Width - 1 : i * Width1 + Width * 2 - 1]) + + self.TurnOnDisplay_Partial() + + + def display_4Gray(self, image): + Width =int(self.width / 16)+1 + Width1 =int(self.width / 8) + + self.send_command(0x24) + for j in range(self.height): + for i in range(Width): + temp3=0 + for o in range(0, 2): + temp1 = image[(j * Width1 + i)*2+o] + for k in range(0, 4): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x01 + elif(temp2 == 0x00): + temp3 |= 0x00 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + if(o!=1 or k!=3): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0x26) + for j in range(self.height): + for i in range(Width): + temp3=0 + for o in range(0, 2): + temp1 = image[(j * Width1 + i)*2+o] + for k in range(0, 4): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x01 + elif(temp2 == 0x00): + temp3 |= 0x00 + elif(temp2 == 0x80): + temp3 |= 0x01 + else: #0x40 + temp3 |= 0x00 + if(o!=1 or k!=3): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0xA4) + for j in range(self.height): + for i in range(Width): + temp3=0 + for o in range(0, 2): + temp1 = image[(j * Width1 + i + Width - 1)*2+o] + for k in range(0, 4): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x01 + elif(temp2 == 0x00): + temp3 |= 0x00 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + if(o!=1 or k!=3): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0xA6) + for j in range(self.height): + for i in range(Width): + temp3=0 + for o in range(0, 2): + temp1 = image[(j * Width1 + i + Width - 1)*2+o] + for k in range(0, 4): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x01 + elif(temp2 == 0x00): + temp3 |= 0x00 + elif(temp2 == 0x80): + temp3 |= 0x01 + else: #0x40 + temp3 |= 0x00 + if(o!=1 or k!=3): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.TurnOnDisplay_4GRAY() + + def Clear(self): + self.send_command(0x24) + self.send_data2([0xFF] * 13600) + self.send_command(0X26) + self.send_data2([0x00] * 13600) + + self.send_command(0xA4) + self.send_data2([0xFF] * 13600) + self.send_command(0xA6) + self.send_data2([0x00] * 13600) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0X10) # deep sleep + self.send_data(0x03) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd5in79b.py b/lib/waveshare_epd/epd5in79b.py new file mode 100644 index 0000000..49cb92d --- /dev/null +++ b/lib/waveshare_epd/epd5in79b.py @@ -0,0 +1,206 @@ +# ***************************************************************************** +# * | File : epd5in79b.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2024-03-05 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 792 +EPD_HEIGHT = 272 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(1) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(200) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x22) + self.send_data(0xF7) # 24s # 0xD7 16s Probability refresh bad, probability damage ink screen + self.send_command(0x20) # DISPLAY REFRESH + epdconfig.delay_ms(100) # The delay here is necessary, 200uS at least!!! + self.ReadBusy() # waiting for the electronic paper IC to release the idle signal + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.ReadBusy() # waiting for the electronic paper IC to release the idle signal + self.send_command(0x12) # POWER ON + self.ReadBusy() # waiting for the electronic paper IC to release the idle signal + + self.send_command(0x11) + self.send_data(0x01) + self.send_command(0x44) # Set Ram X- address Start / End position + self.send_data(0x00) # XStart, POR = 00h + self.send_data(0x31) # 400/8-1 + self.send_command(0x45) # Set Ram Y- address Start / End position + self.send_data(0x0f) + self.send_data(0x01) # 300-1 + self.send_data(0x00) # YEnd L + self.send_data(0x00) # YEnd H + + self.send_command(0x4e) + self.send_data(0x00) + self.send_command(0x4f) + self.send_data(0x0f) + self.send_data(0x01) + + + self.send_command(0x91) + self.send_data(0x00) + + self.send_command(0xC4) # Set Ram X- address Start / End position + self.send_data(0x31) # XStart, POR = 00h + self.send_data(0x00) # 400/8-1 + self.send_command(0xC5) # Set Ram Y- address Start / End position + self.send_data(0x0f) + self.send_data(0x01) # 300-1 + self.send_data(0x00) # YEnd L + self.send_data(0x00) # YEnd H + + self.send_command(0xCe) + self.send_data(0x31) + self.send_command(0xCf) + self.send_data(0x0f) + self.send_data(0x01) + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, imageblack, imagered): + buf = [0x00] * int(self.width * self.height / 8) + for i in range(0, int(self.width * self.height / 8)): + buf[i] = ~imagered[i] + + Width =int(self.width / 16)+1 + Width1 =int(self.width / 8) + Height = self.height + + self.send_command(0x24) + for i in range(Height): + self.send_data2(imageblack[i * Width1 : i * Width1+Width]) + self.send_command(0X26) + for i in range(self.height): + self.send_data2(buf[i * Width1 : i * Width1+Width]) + + self.send_command(0xA4) + for i in range(self.height): + self.send_data2(imageblack[i * Width1 + Width - 1 : i * Width1 + Width * 2 - 1]) + self.send_command(0xA6) + for i in range(self.height): + self.send_data2(buf[i * Width1 + Width - 1 : i * Width1 + Width * 2 - 1]) + + self.TurnOnDisplay() + + def Clear(self): + self.send_command(0x24) + self.send_data2([0xFF] * 13600) + self.send_command(0X26) + self.send_data2([0x00] * 13600) + + self.send_command(0xA4) + self.send_data2([0xFF] * 13600) + self.send_command(0xA6) + self.send_data2([0x00] * 13600) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0X10) # deep sleep + self.send_data(0x03) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd5in79g.py b/lib/waveshare_epd/epd5in79g.py new file mode 100644 index 0000000..21cad82 --- /dev/null +++ b/lib/waveshare_epd/epd5in79g.py @@ -0,0 +1,226 @@ +# ***************************************************************************** +# * | File : epd5in79b.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2024-03-05 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + + +import logging +from . import epdconfig + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 792 +EPD_HEIGHT = 272 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.BLACK = 0x000000 # 00 BGR + self.WHITE = 0xffffff # 01 + self.YELLOW = 0x00ffff # 10 + self.RED = 0x0000ff # 11 + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(1) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusyH(self): + logger.debug("e-Paper busy H") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(5) + epdconfig.delay_ms(200) + logger.debug("e-Paper busy H release") + + def ReadBusyL(self): + logger.debug("e-Paper busy L") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: busy, 1: idle + epdconfig.delay_ms(5) + logger.debug("e-Paper busy L release") + + def TurnOnDisplay(self): + self.send_command(0xA2) + self.send_data(0x00) + + self.send_command(0x12) + self.send_data(0x00) + epdconfig.delay_ms(100) + self.ReadBusyH() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.ReadBusyH() + + self.send_command(0xA2) + self.send_data(0x01) + + self.send_command(0x00) + self.send_data(0x03) + self.send_data(0x29) + + self.send_command(0xA2) + self.send_data(0x02) + + self.send_command(0x00) + self.send_data(0x07) + self.send_data(0x29) + + self.send_command(0xA2) + self.send_data(0x00) + + self.send_command(0x50) + self.send_data(0x97) + + self.send_command(0x61) + self.send_data(0x01) + self.send_data(0x8c) + self.send_data(0x01) + self.send_data(0x10) + + self.send_command(0x06) + self.send_data(0x38) + self.send_data(0x38) + self.send_data(0x38) + self.send_data(0x00) + + + self.send_command(0xE9) + self.send_data(0x01) + + + self.send_command(0xE0) + self.send_data(0x01) + + self.send_command(0x04) + self.ReadBusyH() + return 0 + + def getbuffer(self, image): + # Create a pallette with the 4 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 255,255,0, 255,0,0) + (0,0,0)*252) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 4 colors, dithering if needed + image_4color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_4color = bytearray(image_4color.tobytes('raw')) + + # into a single byte to transfer to the panel + buf = [0x00] * int(self.width * self.height / 4) + idx = 0 + for i in range(0, len(buf_4color), 4): + buf[idx] = (buf_4color[i] << 6) + (buf_4color[i+1] << 4) + (buf_4color[i+2] << 2) + buf_4color[i+3] + idx += 1 + return buf + + def display(self, image): + Width =int(self.width / 8) + Width1 =int(self.width / 4) + Height = self.height + + self.send_command(0xA2) + self.send_data(0x02) + self.send_command(0x10) + for i in range(Height//2): + self.send_data2(image[i * Width1 : i * Width1+Width]) + self.send_data2(image[(Height-i-1) * Width1 : (Height-i-1) * Width1+Width]) + + self.send_command(0xA2) + self.send_data(0x01) + self.send_command(0x10) + for i in range(Height//2): + self.send_data2(image[i * Width1+Width : (i+1) * Width1]) + self.send_data2(image[(Height-i-1) * Width1+Width : (Height-i) * Width1]) + + self.TurnOnDisplay() + + def Clear(self, color=0x55): + self.send_command(0xA2) + self.send_data(0x02) + self.send_command(0x10) + self.send_data2([color] * int(self.height) * int(self.width/8)) + + self.send_command(0xA2) + self.send_data(0x01) + self.send_command(0x10) + self.send_data2([color] * int(self.height) * int(self.width/8)) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0X10) # deep sleep + self.send_data(0x03) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd5in83.py b/lib/waveshare_epd/epd5in83.py index 516e39e..84fabf0 100644 --- a/lib/waveshare_epd/epd5in83.py +++ b/lib/waveshare_epd/epd5in83.py @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 600 EPD_HEIGHT = 448 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -66,10 +68,10 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -125,7 +127,7 @@ class EPD: image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) + logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) if(imwidth == self.width and imheight == self.height): for y in range(imheight): for x in range(imwidth): diff --git a/lib/waveshare_epd/epd5in83_V2.py b/lib/waveshare_epd/epd5in83_V2.py index 5c5a3b7..b8e8281 100644 --- a/lib/waveshare_epd/epd5in83_V2.py +++ b/lib/waveshare_epd/epd5in83_V2.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V1.0 -# * | Date : 2020-12-09 +# * | This version: V1.1 +# * | Date : 2022-08-10 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -34,6 +34,8 @@ from . import epdconfig EPD_WIDTH = 648 EPD_HEIGHT = 480 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -63,12 +65,19 @@ class EPD: epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): epdconfig.delay_ms(20) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def TurnOnDisplay(self): self.send_command(0x12); #POWER ON @@ -114,21 +123,21 @@ class EPD: return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -138,21 +147,20 @@ class EPD: return buf def display(self, image): + buf = [0x00] * int(self.width * self.height / 8) + for i in range(0, int(self.width * self.height / 8)): + buf[i] = ~image[i] self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00) + self.send_data2([0x00] * int(self.width * self.height / 8)) self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(~image[i]) + self.send_data2(buf) self.TurnOnDisplay() def Clear(self): self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00) + self.send_data2([0x00] * int(self.width * self.height / 8)) self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00) + self.send_data2([0x00] * int(self.width * self.height / 8)) self.TurnOnDisplay() def sleep(self): diff --git a/lib/waveshare_epd/epd5in83b_V2.py b/lib/waveshare_epd/epd5in83b_V2.py index 0c8a726..3f424d0 100644 --- a/lib/waveshare_epd/epd5in83b_V2.py +++ b/lib/waveshare_epd/epd5in83b_V2.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V1.0 -# * | Date : 2020-07-04 +# * | This version: V1.1 +# * | Date : 2022-08-10 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 648 EPD_HEIGHT = 480 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -64,14 +66,21 @@ class EPD: epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") self.send_command(0X71) while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy self.send_command(0X71) epdconfig.delay_ms(200) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -111,21 +120,21 @@ class EPD: return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): newx = y @@ -135,14 +144,16 @@ class EPD: return buf def display(self, imageblack, imagered): + buf = [0x00] * int(self.width * self.height / 8) + for i in range(0, int(self.width * self.height / 8)): + buf[i] = ~imagered[i] + if (imageblack != None): self.send_command(0X10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(imageblack[i]) + self.send_data2(imageblack) if (imagered != None): self.send_command(0X13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(~imagered[i]) + self.send_data2(buf) self.send_command(0x12) epdconfig.delay_ms(200) @@ -150,11 +161,9 @@ class EPD: def Clear(self): self.send_command(0X10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xff) + self.send_data2([0xFF] * int(self.width * self.height / 8)) self.send_command(0X13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00) + self.send_data2([0x00] * int(self.width * self.height / 8)) self.send_command(0x12) epdconfig.delay_ms(200) diff --git a/lib/waveshare_epd/epd5in83bc.py b/lib/waveshare_epd/epd5in83bc.py index 80f8980..cf5d4c4 100644 --- a/lib/waveshare_epd/epd5in83bc.py +++ b/lib/waveshare_epd/epd5in83bc.py @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 600 EPD_HEIGHT = 448 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -66,10 +68,10 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -117,21 +119,21 @@ class EPD: return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) + logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): newx = y diff --git a/lib/waveshare_epd/epd7in3e.py b/lib/waveshare_epd/epd7in3e.py new file mode 100644 index 0000000..59fc3c0 --- /dev/null +++ b/lib/waveshare_epd/epd7in3e.py @@ -0,0 +1,228 @@ +# ***************************************************************************** +# * | File : epd7in3f.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2022-10-20 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# ******************************************************************************/ +# 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. +# + +import logging +from . import epdconfig + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 800 +EPD_HEIGHT = 480 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.BLACK = 0x000000 # 0000 BGR + self.WHITE = 0xffffff # 0001 + self.YELLOW = 0x00ffff # 0010 + self.RED = 0x0000ff # 0011 + # self.ORANGE = 0x0080ff # 0100 + self.BLUE = 0xff0000 # 0101 + self.GREEN = 0x00ff00 # 0110 + + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) # module reset + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusyH(self): + logger.debug("e-Paper busy H") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: busy, 1: idle + epdconfig.delay_ms(5) + logger.debug("e-Paper busy H release") + + def TurnOnDisplay(self): + self.send_command(0x04) # POWER_ON + self.ReadBusyH() + + self.send_command(0x12) # DISPLAY_REFRESH + self.send_data(0X00) + self.ReadBusyH() + + self.send_command(0x02) # POWER_OFF + self.send_data(0X00) + self.ReadBusyH() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + self.ReadBusyH() + epdconfig.delay_ms(30) + + self.send_command(0xAA) + self.send_data(0x49) + self.send_data(0x55) + self.send_data(0x20) + self.send_data(0x08) + self.send_data(0x09) + self.send_data(0x18) + + self.send_command(0x01) + self.send_data(0x3F) + + self.send_command(0x00) + self.send_data(0x5F) + self.send_data(0x69) + + self.send_command(0x03) + self.send_data(0x00) + self.send_data(0x54) + self.send_data(0x00) + self.send_data(0x44) + + self.send_command(0x05) + self.send_data(0x40) + self.send_data(0x1F) + self.send_data(0x1F) + self.send_data(0x2C) + + self.send_command(0x06) + self.send_data(0x6F) + self.send_data(0x1F) + self.send_data(0x17) + self.send_data(0x49) + + self.send_command(0x08) + self.send_data(0x6F) + self.send_data(0x1F) + self.send_data(0x1F) + self.send_data(0x22) + + self.send_command(0x30) + self.send_data(0x03) + + self.send_command(0x50) + self.send_data(0x3F) + + self.send_command(0x60) + self.send_data(0x02) + self.send_data(0x00) + + self.send_command(0x61) + self.send_data(0x03) + self.send_data(0x20) + self.send_data(0x01) + self.send_data(0xE0) + + self.send_command(0x84) + self.send_data(0x01) + + self.send_command(0xE3) + self.send_data(0x2F) + + self.send_command(0x04) + self.ReadBusyH() + return 0 + + def getbuffer(self, image): + # Create a pallette with the 7 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 255,255,0, 255,0,0, 0,0,0, 0,0,255, 0,255,0) + (0,0,0)*249) + # pal_image.putpalette( (0,0,0, 255,255,255, 0,255,0, 0,0,255, 255,0,0, 255,255,0, 255,128,0) + (0,0,0)*249) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 7 colors, dithering if needed + image_7color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_7color = bytearray(image_7color.tobytes('raw')) + + # PIL does not support 4 bit color, so pack the 4 bits of color + # into a single byte to transfer to the panel + buf = [0x00] * int(self.width * self.height / 2) + idx = 0 + for i in range(0, len(buf_7color), 2): + buf[idx] = (buf_7color[i] << 4) + buf_7color[i+1] + idx += 1 + + return buf + + def display(self, image): + self.send_command(0x10) + self.send_data2(image) + + self.TurnOnDisplay() + + def Clear(self, color=0x11): + self.send_command(0x10) + self.send_data2([color] * int(self.height) * int(self.width/2)) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd7in3e.pyc b/lib/waveshare_epd/epd7in3e.pyc new file mode 100644 index 0000000..589639b Binary files /dev/null and b/lib/waveshare_epd/epd7in3e.pyc differ diff --git a/lib/waveshare_epd/epd7in3f.py b/lib/waveshare_epd/epd7in3f.py new file mode 100644 index 0000000..1fbe67f --- /dev/null +++ b/lib/waveshare_epd/epd7in3f.py @@ -0,0 +1,247 @@ +# ***************************************************************************** +# * | File : epd7in3f.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2022-10-20 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# ******************************************************************************/ +# 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. +# + +import logging +from . import epdconfig + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 800 +EPD_HEIGHT = 480 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.BLACK = 0x000000 # 0000 BGR + self.WHITE = 0xffffff # 0001 + self.GREEN = 0x00ff00 # 0010 + self.BLUE = 0xff0000 # 0011 + self.RED = 0x0000ff # 0100 + self.YELLOW = 0x00ffff # 0101 + self.ORANGE = 0x0080ff # 0110 + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) # module reset + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusyH(self): + logger.debug("e-Paper busy H") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: busy, 1: idle + epdconfig.delay_ms(5) + logger.debug("e-Paper busy H release") + + def TurnOnDisplay(self): + self.send_command(0x04) # POWER_ON + self.ReadBusyH() + + self.send_command(0x12) # DISPLAY_REFRESH + self.send_data(0X00) + self.ReadBusyH() + + self.send_command(0x02) # POWER_OFF + self.send_data(0X00) + self.ReadBusyH() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + self.ReadBusyH() + epdconfig.delay_ms(30) + + self.send_command(0xAA) # CMDH + self.send_data(0x49) + self.send_data(0x55) + self.send_data(0x20) + self.send_data(0x08) + self.send_data(0x09) + self.send_data(0x18) + + self.send_command(0x01) + self.send_data(0x3F) + self.send_data(0x00) + self.send_data(0x32) + self.send_data(0x2A) + self.send_data(0x0E) + self.send_data(0x2A) + + self.send_command(0x00) + self.send_data(0x5F) + self.send_data(0x69) + + self.send_command(0x03) + self.send_data(0x00) + self.send_data(0x54) + self.send_data(0x00) + self.send_data(0x44) + + self.send_command(0x05) + self.send_data(0x40) + self.send_data(0x1F) + self.send_data(0x1F) + self.send_data(0x2C) + + self.send_command(0x06) + self.send_data(0x6F) + self.send_data(0x1F) + self.send_data(0x1F) + self.send_data(0x22) + + self.send_command(0x08) + self.send_data(0x6F) + self.send_data(0x1F) + self.send_data(0x1F) + self.send_data(0x22) + + self.send_command(0x13) # IPC + self.send_data(0x00) + self.send_data(0x04) + + self.send_command(0x30) + self.send_data(0x3C) + + self.send_command(0x41) # TSE + self.send_data(0x00) + + self.send_command(0x50) + self.send_data(0x3F) + + self.send_command(0x60) + self.send_data(0x02) + self.send_data(0x00) + + self.send_command(0x61) + self.send_data(0x03) + self.send_data(0x20) + self.send_data(0x01) + self.send_data(0xE0) + + self.send_command(0x82) + self.send_data(0x1E) + + self.send_command(0x84) + self.send_data(0x00) + + self.send_command(0x86) # AGID + self.send_data(0x00) + + self.send_command(0xE3) + self.send_data(0x2F) + + self.send_command(0xE0) # CCSET + self.send_data(0x00) + + self.send_command(0xE6) # TSSET + self.send_data(0x00) + return 0 + + def getbuffer(self, image): + # Create a pallette with the 7 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 0,255,0, 0,0,255, 255,0,0, 255,255,0, 255,128,0) + (0,0,0)*249) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 7 colors, dithering if needed + image_7color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_7color = bytearray(image_7color.tobytes('raw')) + + # PIL does not support 4 bit color, so pack the 4 bits of color + # into a single byte to transfer to the panel + buf = [0x00] * int(self.width * self.height / 2) + idx = 0 + for i in range(0, len(buf_7color), 2): + buf[idx] = (buf_7color[i] << 4) + buf_7color[i+1] + idx += 1 + + return buf + + def display(self, image): + self.send_command(0x10) + self.send_data2(image) + + self.TurnOnDisplay() + + def Clear(self, color=0x11): + self.send_command(0x10) + self.send_data2([color] * int(self.height) * int(self.width/2)) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd7in3f.pyc b/lib/waveshare_epd/epd7in3f.pyc new file mode 100644 index 0000000..76f7c31 Binary files /dev/null and b/lib/waveshare_epd/epd7in3f.pyc differ diff --git a/lib/waveshare_epd/epd7in3g.py b/lib/waveshare_epd/epd7in3g.py new file mode 100644 index 0000000..c89bc6e --- /dev/null +++ b/lib/waveshare_epd/epd7in3g.py @@ -0,0 +1,242 @@ +# ***************************************************************************** +# * | File : epd7in3g.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1 +# * | Date : 2022-07-20 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# ******************************************************************************/ +# 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. +# + +import logging +from . import epdconfig + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 800 +EPD_HEIGHT = 480 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.BLACK = 0x000000 # 00 BGR + self.WHITE = 0xffffff # 01 + self.YELLOW = 0x00ffff # 10 + self.RED = 0x0000ff # 11 + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) # module reset + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusyH(self): + logger.debug("e-Paper busy H") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(5) + logger.debug("e-Paper busy H release") + + def ReadBusyL(self): + logger.debug("e-Paper busy L") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: busy, 1: idle + epdconfig.delay_ms(5) + logger.debug("e-Paper busy L release") + + def TurnOnDisplay(self): + self.send_command(0x12) # DISPLAY_REFRESH + self.send_data(0x01) + self.ReadBusyH() + + self.send_command(0x02) # POWER_OFF + self.send_data(0X00) + self.ReadBusyH() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + self.ReadBusyH() + epdconfig.delay_ms(30) + + self.send_command(0xAA) + self.send_data(0x49) + self.send_data(0x55) + self.send_data(0x20) + self.send_data(0x08) + self.send_data(0x09) + self.send_data(0x18) + + self.send_command(0x01) + self.send_data(0x3F) + + self.send_command(0x00) + self.send_data(0x4F) + self.send_data(0x69) + + self.send_command(0x05) + self.send_data(0x40) + self.send_data(0x1F) + self.send_data(0x1F) + self.send_data(0x2C) + + self.send_command(0x08) + self.send_data(0x6F) + self.send_data(0x1F) + self.send_data(0x1F) + self.send_data(0x22) + + # =================== + # 20211212 + # First setting + self.send_command(0x06) + self.send_data(0x6F) + self.send_data(0x1F) + self.send_data(0x14) + self.send_data(0x14) + # =================== + + self.send_command(0x03) + self.send_data(0x00) + self.send_data(0x54) + self.send_data(0x00) + self.send_data(0x44) + + self.send_command(0x60) + self.send_data(0x02) + self.send_data(0x00) + # Please notice that PLL must be set for version 2 IC + self.send_command(0x30) + self.send_data(0x08) + + self.send_command(0x50) + self.send_data(0x3F) + + self.send_command(0x61) + self.send_data(0x03) + self.send_data(0x20) + self.send_data(0x01) + self.send_data(0xE0) + + self.send_command(0xE3) + self.send_data(0x2F) + + self.send_command(0x84) + self.send_data(0x01) + return 0 + + def getbuffer(self, image): + # Create a pallette with the 4 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 255,255,0, 255,0,0) + (0,0,0)*252) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 4 colors, dithering if needed + image_4color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_4color = bytearray(image_4color.tobytes('raw')) + + # into a single byte to transfer to the panel + buf = [0x00] * int(self.width * self.height / 4) + idx = 0 + for i in range(0, len(buf_4color), 4): + buf[idx] = (buf_4color[i] << 6) + (buf_4color[i+1] << 4) + (buf_4color[i+2] << 2) + buf_4color[i+3] + idx += 1 + return buf + + def display(self, image): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x04) + self.ReadBusyH() + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(image[i + j * Width]) + self.TurnOnDisplay() + + def Clear(self, color=0x55): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x04) + self.ReadBusyH() + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(color) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.send_data(0x00) + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd7in5.py b/lib/waveshare_epd/epd7in5.py index a778e6d..2f8d8fa 100644 --- a/lib/waveshare_epd/epd7in5.py +++ b/lib/waveshare_epd/epd7in5.py @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 640 EPD_HEIGHT = 384 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -72,10 +74,10 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -134,7 +136,7 @@ class EPD: img = img.rotate(90, expand=True).convert('1') imwidth, imheight = img.size else: - logging.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) + logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) # return a blank buffer return buf diff --git a/lib/waveshare_epd/epd7in5_HD.py b/lib/waveshare_epd/epd7in5_HD.py index a934e28..55070dd 100644 --- a/lib/waveshare_epd/epd7in5_HD.py +++ b/lib/waveshare_epd/epd7in5_HD.py @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 880 EPD_HEIGHT = 528 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -72,7 +74,7 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") busy = epdconfig.digital_read(self.busy_pin) while(busy == 1): busy = epdconfig.digital_read(self.busy_pin) @@ -84,46 +86,46 @@ class EPD: # EPD hardware init start self.reset() - self.ReadBusy(); - self.send_command(0x12); #SWRESET - self.ReadBusy(); + self.ReadBusy() + self.send_command(0x12) #SWRESET + self.ReadBusy() - self.send_command(0x46); # Auto Write Red RAM - self.send_data(0xf7); - self.ReadBusy(); - self.send_command(0x47); # Auto Write B/W RAM - self.send_data(0xf7); - self.ReadBusy(); + self.send_command(0x46) # Auto Write Red RAM + self.send_data(0xf7) + self.ReadBusy() + self.send_command(0x47) # Auto Write B/W RAM + self.send_data(0xf7) + self.ReadBusy() - self.send_command(0x0C); # Soft start setting + self.send_command(0x0C) # Soft start setting self.send_data2([0xAE, 0xC7, 0xC3, 0xC0, 0x40]) - self.send_command(0x01); # Set MUX as 527 + self.send_command(0x01) # Set MUX as 527 self.send_data2([0xAF, 0x02, 0x01]) - self.send_command(0x11); # Data entry mode - self.send_data(0x01); + self.send_command(0x11) # Data entry mode + self.send_data(0x01) - self.send_command(0x44); + self.send_command(0x44) self.send_data2([0x00, 0x00, 0x6F, 0x03]) # RAM x address start at 0 - self.send_command(0x45); + self.send_command(0x45) self.send_data2([0xAF, 0x02, 0x00, 0x00]) - self.send_command(0x3C); # VBD - self.send_data(0x05); # LUT1, for white + self.send_command(0x3C) # VBD + self.send_data(0x05) # LUT1, for white - self.send_command(0x18); - self.send_data(0X80); + self.send_command(0x18) + self.send_data(0X80) - self.send_command(0x22); - self.send_data(0XB1); #Load Temperature and waveform setting. - self.send_command(0x20); - self.ReadBusy(); + self.send_command(0x22) + self.send_data(0XB1) #Load Temperature and waveform setting. + self.send_command(0x20) + self.ReadBusy() - self.send_command(0x4E); # set RAM x address count to 0; + self.send_command(0x4E) # set RAM x address count to 0 self.send_data2([0x00, 0x00]) - self.send_command(0x4F); + self.send_command(0x4F) self.send_data2([0x00, 0x00]) # EPD hardware init end return 0 @@ -136,7 +138,7 @@ class EPD: elif(imwidth == self.height and imheight == self.width): img = img.rotate(90, expand=True).convert('1') else: - logging.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) + logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) # return a blank buffer return [0xff] * int(self.width * self.height / 8) @@ -144,19 +146,19 @@ class EPD: return buf def display(self, image): - self.send_command(0x4F); + self.send_command(0x4F) self.send_data2([0x00, 0x00]) - self.send_command(0x24); + self.send_command(0x24) self.send_data2(image) - self.send_command(0x22); - self.send_data(0xF7);#Load LUT from MCU(0x32) - self.send_command(0x20); - epdconfig.delay_ms(10); - self.ReadBusy(); + self.send_command(0x22) + self.send_data(0xF7)#Load LUT from MCU(0x32) + self.send_command(0x20) + epdconfig.delay_ms(10) + self.ReadBusy() def Clear(self): buf = [0xff] * int(self.width * self.height / 8) - self.send_command(0x4F); + self.send_command(0x4F) self.send_data2([0x00, 0x00]) self.send_command(0x24) self.send_data2(buf) @@ -164,15 +166,15 @@ class EPD: self.send_command(0x26) self.send_data2(buf) - self.send_command(0x22); - self.send_data(0xF7);#Load LUT from MCU(0x32) - self.send_command(0x20); - epdconfig.delay_ms(10); - self.ReadBusy(); + self.send_command(0x22) + self.send_data(0xF7)#Load LUT from MCU(0x32) + self.send_command(0x20) + epdconfig.delay_ms(10) + self.ReadBusy() def sleep(self): - self.send_command(0x10); - self.send_data(0x01); + self.send_command(0x10) + self.send_data(0x01) epdconfig.delay_ms(2000) epdconfig.module_exit() diff --git a/lib/waveshare_epd/epd7in5_V2.py b/lib/waveshare_epd/epd7in5_V2.py index 61cc243..8a92e16 100644 --- a/lib/waveshare_epd/epd7in5_V2.py +++ b/lib/waveshare_epd/epd7in5_V2.py @@ -35,6 +35,13 @@ from . import epdconfig EPD_WIDTH = 800 EPD_HEIGHT = 480 +GRAY1 = 0xff #white +GRAY2 = 0xC0 +GRAY3 = 0x80 #gray +GRAY4 = 0x00 #Blackest + +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -43,61 +50,11 @@ class EPD: self.cs_pin = epdconfig.CS_PIN self.width = EPD_WIDTH self.height = EPD_HEIGHT + self.GRAY1 = GRAY1 #white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 #gray + self.GRAY4 = GRAY4 #Blackest - Voltage_Frame_7IN5_V2 = [ - 0x6, 0x3F, 0x3F, 0x11, 0x24, 0x7, 0x17, - ] - - LUT_VCOM_7IN5_V2 = [ - 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, - 0x0, 0xF, 0x1, 0xF, 0x1, 0x2, - 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - ] - - LUT_WW_7IN5_V2 = [ - 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, - 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, - 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - ] - - LUT_BW_7IN5_V2 = [ - 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, - 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, - 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - ] - - LUT_WB_7IN5_V2 = [ - 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, - 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, - 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - ] - - LUT_BB_7IN5_V2 = [ - 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, - 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, - 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - ] - # Hardware reset def reset(self): epdconfig.digital_write(self.reset_pin, 1) @@ -126,79 +83,39 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") self.send_command(0x71) busy = epdconfig.digital_read(self.busy_pin) while(busy == 0): self.send_command(0x71) busy = epdconfig.digital_read(self.busy_pin) epdconfig.delay_ms(20) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") - def SetLut(self, lut_vcom, lut_ww, lut_bw, lut_wb, lut_bb): - self.send_command(0x20) - for count in range(0, 42): - self.send_data(lut_vcom[count]) - - self.send_command(0x21) - for count in range(0, 42): - self.send_data(lut_ww[count]) - - self.send_command(0x22) - for count in range(0, 42): - self.send_data(lut_bw[count]) - - self.send_command(0x23) - for count in range(0, 42): - self.send_data(lut_wb[count]) - - self.send_command(0x24) - for count in range(0, 42): - self.send_data(lut_bb[count]) - def init(self): if (epdconfig.module_init() != 0): return -1 # EPD hardware init start self.reset() - # self.send_command(0x06) # btst - # self.send_data(0x17) - # self.send_data(0x17) - # self.send_data(0x28) # If an exception is displayed, try using 0x38 - # self.send_data(0x17) - - # self.send_command(0x01) #POWER SETTING - # self.send_data(0x07) - # self.send_data(0x07) #VGH=20V,VGL=-20V - # self.send_data(0x3f) #VDH=15V - # self.send_data(0x3f) #VDL=-15V - - self.send_command(0x01) # power setting - self.send_data(0x17) # 1-0=11: internal power - self.send_data(self.Voltage_Frame_7IN5_V2[6]) # VGH&VGL - self.send_data(self.Voltage_Frame_7IN5_V2[1]) # VSH - self.send_data(self.Voltage_Frame_7IN5_V2[2]) # VSL - self.send_data(self.Voltage_Frame_7IN5_V2[3]) # VSHR - - self.send_command(0x82) # VCOM DC Setting - self.send_data(self.Voltage_Frame_7IN5_V2[4]) # VCOM - - self.send_command(0x06) # Booster Setting - self.send_data(0x27) - self.send_data(0x27) - self.send_data(0x2F) + self.send_command(0x06) # btst + self.send_data(0x17) + self.send_data(0x17) + self.send_data(0x28) # If an exception is displayed, try using 0x38 self.send_data(0x17) - self.send_command(0x30) # OSC Setting - self.send_data(self.Voltage_Frame_7IN5_V2[0]) # 2-0=100: N=4 5-3=111: M=7 3C=50Hz 3A=100HZ + self.send_command(0x01) #POWER SETTING + self.send_data(0x07) + self.send_data(0x07) #VGH=20V,VGL=-20V + self.send_data(0x28) #VDH=15V + self.send_data(0x17) #VDL=-15V self.send_command(0x04) #POWER ON epdconfig.delay_ms(100) self.ReadBusy() self.send_command(0X00) #PANNEL SETTING - self.send_data(0x3F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f + self.send_data(0x1F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f self.send_command(0x61) #tres self.send_data(0x03) #source 800 @@ -209,20 +126,111 @@ class EPD: self.send_command(0X15) self.send_data(0x00) - self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING + # If the screen appears gray, use the annotated initialization command + self.send_command(0X50) self.send_data(0x10) self.send_data(0x07) + # self.send_command(0X50) + # self.send_data(0x10) + # self.send_data(0x17) + # self.send_command(0X52) + # self.send_data(0x03) self.send_command(0X60) #TCON SETTING self.send_data(0x22) - self.send_command(0x65) # Resolution setting - self.send_data(0x00) - self.send_data(0x00) # 800*480 - self.send_data(0x00) - self.send_data(0x00) + # EPD hardware init end + return 0 + + def init_fast(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0X00) #PANNEL SETTING + self.send_data(0x1F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f + + # If the screen appears gray, use the annotated initialization command + self.send_command(0X50) + self.send_data(0x10) + self.send_data(0x07) + # self.send_command(0X50) + # self.send_data(0x10) + # self.send_data(0x17) + # self.send_command(0X52) + # self.send_data(0x03) + + self.send_command(0x04) #POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal + + #Enhanced display drive(Add 0x06 command) + self.send_command(0x06) #Booster Soft Start + self.send_data (0x27) + self.send_data (0x27) + self.send_data (0x18) + self.send_data (0x17) + + self.send_command(0xE0) + self.send_data(0x02) + self.send_command(0xE5) + self.send_data(0x5A) + + # EPD hardware init end + return 0 + + def init_part(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0X00) #PANNEL SETTING + self.send_data(0x1F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f + + self.send_command(0x04) #POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal + + self.send_command(0xE0) + self.send_data(0x02) + self.send_command(0xE5) + self.send_data(0x6E) + + # EPD hardware init end + return 0 + + # The feature will only be available on screens sold after 24/10/23 + def init_4Gray(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0X00) #PANNEL SETTING + self.send_data(0x1F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f + + self.send_command(0X50) + self.send_data(0x10) + self.send_data(0x07) + + self.send_command(0x04) #POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal + + #Enhanced display drive(Add 0x06 command) + self.send_command(0x06) #Booster Soft Start + self.send_data (0x27) + self.send_data (0x27) + self.send_data (0x18) + self.send_data (0x17) + + self.send_command(0xE0) + self.send_data(0x02) + self.send_command(0xE5) + self.send_data(0x5F) - self.SetLut(self.LUT_VCOM_7IN5_V2, self.LUT_WW_7IN5_V2, self.LUT_BW_7IN5_V2, self.LUT_WB_7IN5_V2, self.LUT_BB_7IN5_V2) # EPD hardware init end return 0 @@ -235,7 +243,7 @@ class EPD: # image has correct dimensions, but needs to be rotated img = img.rotate(90, expand=True).convert('1') else: - logging.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) + logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) # return a blank buffer return [0x00] * (int(self.width/8) * self.height) @@ -245,8 +253,56 @@ class EPD: for i in range(len(buf)): buf[i] ^= 0xFF return buf + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i=0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = self.height - x - 1 + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + return buf def display(self, image): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + image1 = [0xFF] * int(self.width * self.height / 8) + for j in range(Height): + for i in range(Width): + image1[i + j * Width] = ~image[i + j * Width] + self.send_command(0x10) + self.send_data2(image1) + self.send_command(0x13) self.send_data2(image) @@ -255,16 +311,133 @@ class EPD: self.ReadBusy() def Clear(self): - buf = [0x00] * (int(self.width/8) * self.height) self.send_command(0x10) - self.send_data2(buf) + self.send_data2([0xFF] * int(self.width * self.height / 8)) self.send_command(0x13) - self.send_data2(buf) + self.send_data2([0x00] * int(self.width * self.height / 8)) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def display_Partial(self, Image, Xstart, Ystart, Xend, Yend): + if((Xstart % 8 + Xend % 8 == 8 & Xstart % 8 > Xend % 8) | Xstart % 8 + Xend % 8 == 0 | (Xend - Xstart)%8 == 0): + Xstart = Xstart // 8 * 8 + Xend = Xend // 8 * 8 + else: + Xstart = Xstart // 8 * 8 + if Xend % 8 == 0: + Xend = Xend // 8 * 8 + else: + Xend = Xend // 8 * 8 + 1 + + Width = (Xend - Xstart) // 8 + Height = Yend - Ystart + + self.send_command(0x50) + self.send_data(0xA9) + self.send_data(0x07) + + self.send_command(0x91) #This command makes the display enter partial mode + self.send_command(0x90) #resolution setting + self.send_data (Xstart//256) + self.send_data (Xstart%256) #x-start + + self.send_data ((Xend-1)//256) + self.send_data ((Xend-1)%256) #x-end + + self.send_data (Ystart//256) # + self.send_data (Ystart%256) #y-start + + self.send_data ((Yend-1)//256) + self.send_data ((Yend-1)%256) #y-end + self.send_data (0x01) + + image1 = [0xFF] * int(self.width * self.height / 8) + for j in range(Height): + for i in range(Width): + image1[i + j * Width] = ~Image[i + j * Width] + + self.send_command(0x13) #Write Black and White image to RAM + self.send_data2(image1) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def display_4Gray(self, image): + self.send_command(0x10) + for i in range(0, 48000): + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else: #0x40 + temp3 |= 0x00 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else : #0x40 + temp3 |= 0x00 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0x13) + for i in range(0, 48000): + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + self.send_command(0x12) epdconfig.delay_ms(100) self.ReadBusy() def sleep(self): + self.send_command(0x50) + self.send_data(0XF7) + self.send_command(0x02) # POWER_OFF self.ReadBusy() @@ -274,4 +447,3 @@ class EPD: epdconfig.delay_ms(2000) epdconfig.module_exit() ### END OF FILE ### - diff --git a/lib/waveshare_epd/epd7in5_V2.pyc b/lib/waveshare_epd/epd7in5_V2.pyc new file mode 100644 index 0000000..15b87c6 Binary files /dev/null and b/lib/waveshare_epd/epd7in5_V2.pyc differ diff --git a/lib/waveshare_epd/epd7in5_V2_old.py b/lib/waveshare_epd/epd7in5_V2_old.py new file mode 100644 index 0000000..280ab47 --- /dev/null +++ b/lib/waveshare_epd/epd7in5_V2_old.py @@ -0,0 +1,530 @@ +# ***************************************************************************** +# * | File : epd7in5.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V4.0 +# * | Date : 2019-06-20 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 800 +EPD_HEIGHT = 480 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + Voltage_Frame_7IN5_V2 = [ + 0x6, 0x3F, 0x3F, 0x11, 0x24, 0x7, 0x17, + ] + + LUT_VCOM_7IN5_V2 = [ + 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ] + + LUT_WW_7IN5_V2 = [ + 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ] + + LUT_BW_7IN5_V2 = [ + 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ] + + LUT_WB_7IN5_V2 = [ + 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ] + + LUT_BB_7IN5_V2 = [ + 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ] + + Lut_all_fresh=[0x67, 0xBF, 0x3F, 0x0D, 0x00, 0x1C, + #VCOM + 0x00, 0x32, 0x32, 0x00, 0x00, 0x01, + 0x00, 0x0A, 0x0A, 0x00, 0x00, 0x00, + 0x00, 0x28, 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, + #WW + 0x60, 0x32, 0x32, 0x00, 0x00, 0x01, + 0x60, 0x0A, 0x0A, 0x00, 0x00, 0x00, + 0x80, 0x28, 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, + #BW + 0x60, 0x32, 0x32, 0x00, 0x00, 0x01, + 0x60, 0x0A, 0x0A, 0x00, 0x00, 0x00, + 0x80, 0x28, 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, + #WB + 0x90, 0x32, 0x32, 0x00, 0x00, 0x01, + 0x60, 0x0A, 0x0A, 0x00, 0x00, 0x00, + 0x40, 0x28, 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, + #BB + 0x90, 0x32, 0x32, 0x00, 0x00, 0x01, + 0x60, 0x0A, 0x0A, 0x00, 0x00, 0x00, + 0x40, 0x28, 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, + #Reserved + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, + ] + + Lut_partial=[0x67, 0xBF, 0x3F, 0x0D, 0x00, 0x1C, + #VCOM + 0x00, 0x14, 0x02, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + #WW + 0x20, 0x14, 0x02, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + #BW + 0x80, 0x14, 0x02, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + #WB + 0x40, 0x14, 0x02, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + #BB + 0x00, 0x14, 0x02, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + #Reserved + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, + ] + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + self.send_command(0x71) + busy = epdconfig.digital_read(self.busy_pin) + while(busy == 0): + self.send_command(0x71) + busy = epdconfig.digital_read(self.busy_pin) + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def SetLut(self, lut_vcom, lut_ww, lut_bw, lut_wb, lut_bb): + self.send_command(0x20) + for count in range(0, 42): + self.send_data(lut_vcom[count]) + + self.send_command(0x21) + for count in range(0, 42): + self.send_data(lut_ww[count]) + + self.send_command(0x22) + for count in range(0, 42): + self.send_data(lut_bw[count]) + + self.send_command(0x23) + for count in range(0, 42): + self.send_data(lut_wb[count]) + + self.send_command(0x24) + for count in range(0, 42): + self.send_data(lut_bb[count]) + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + # self.send_command(0x06) # btst + # self.send_data(0x17) + # self.send_data(0x17) + # self.send_data(0x28) # If an exception is displayed, try using 0x38 + # self.send_data(0x17) + + # self.send_command(0x01) #POWER SETTING + # self.send_data(0x07) + # self.send_data(0x07) #VGH=20V,VGL=-20V + # self.send_data(0x3f) #VDH=15V + # self.send_data(0x3f) #VDL=-15V + + self.send_command(0x01) # power setting + self.send_data(0x17) # 1-0=11: internal power + self.send_data(self.Voltage_Frame_7IN5_V2[6]) # VGH&VGL + self.send_data(self.Voltage_Frame_7IN5_V2[1]) # VSH + self.send_data(self.Voltage_Frame_7IN5_V2[2]) # VSL + self.send_data(self.Voltage_Frame_7IN5_V2[3]) # VSHR + + self.send_command(0x82) # VCOM DC Setting + self.send_data(self.Voltage_Frame_7IN5_V2[4]) # VCOM + + self.send_command(0x06) # Booster Setting + self.send_data(0x27) + self.send_data(0x27) + self.send_data(0x2F) + self.send_data(0x17) + + self.send_command(0x30) # OSC Setting + self.send_data(self.Voltage_Frame_7IN5_V2[0]) # 3C=50Hz, 3A=100HZ + + self.send_command(0x04) # POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() + + self.send_command(0X00) # PANNEL SETTING + self.send_data(0x3F) # KW-3f KWR-2F BWROTP-0f BWOTP-1f + + self.send_command(0x61) # tres + self.send_data(0x03) # source 800 + self.send_data(0x20) + self.send_data(0x01) # gate 480 + self.send_data(0xE0) + + self.send_command(0X15) + self.send_data(0x00) + + self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING + self.send_data(0x10) + self.send_data(0x07) + + self.send_command(0X60) # TCON SETTING + self.send_data(0x22) + + self.send_command(0x65) # Resolution setting + self.send_data(0x00) + self.send_data(0x00) # 800*480 + self.send_data(0x00) + self.send_data(0x00) + + self.SetLut(self.LUT_VCOM_7IN5_V2, self.LUT_WW_7IN5_V2, self.LUT_BW_7IN5_V2, self.LUT_WB_7IN5_V2, self.LUT_BB_7IN5_V2) + # EPD hardware init end + return 0 + + def Epaper_LUT_By_MCU(self,wavedata): + + VCEND=wavedata[0]&0x08 + BDEND=(wavedata[1]&0xC0)>>6 + EVS=VCEND|BDEND + PLL=(wavedata[0]&0xF0)>>4 + XON=wavedata[2]&0xC0 + + self.send_command(0x52) #EVS + self.send_data(EVS) + + self.send_command(0x30) #PLL setting + self.send_data(PLL) + + self.send_command(0x01) #Set VGH VGL VSH VSL VSHR + self.send_data (0x17) + self.send_data (wavedata[0]&0x07) #VGH/VGL Voltage Level selection + self.send_data (wavedata[1]&0x3F) #VSH for black + self.send_data (wavedata[2]&0x3F) #VSL for white + self.send_data (wavedata[3]&0x3F) #VSHR for red + + self.send_command(0x2A) #LUTOPT + self.send_data(XON) + self.send_data(wavedata[4]) + + self.send_command(0x82) #VCOM_DC setting + self.send_data (wavedata[5]) #Vcom value + + + self.send_command(0x20) + self.send_data2(wavedata[6:48]) + + self.send_command(0x21) + self.send_data2(wavedata[48:90]) + + self.send_command(0x22) + self.send_data2(wavedata[90:132]) + + self.send_command(0x23) + self.send_data2(wavedata[132:174]) + + self.send_command(0x24) + self.send_data2(wavedata[174:216]) + + def init2(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x00) # Panel setting + self.send_data(0x3F) + + self.send_command(0x06) # Booster Setting + self.send_data(0x17) + self.send_data(0x17) + self.send_data(0x28) + self.send_data(0x18) + + self.send_command(0x50) # VCOM and DATA interval setting + self.send_data(0x22) + self.send_data(0x07) + + self.send_command(0x60) # TCON setting + self.send_data(0x22) # S-G G-S + + self.send_command(0x61) # Resolution setting + self.send_data(0x03)#800*480 + self.send_data(0x20) + self.send_data(0x01) + self.send_data(0xE0) + + self.send_command(0x65) # Resolution setting + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x04) #POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() + + return 0 + + def init_fast(self): + self.init2() + self.Epaper_LUT_By_MCU(self.Lut_all_fresh) + return 0 + + + def init_part(self): + self.init2() + self.Epaper_LUT_By_MCU(self.Lut_partial) + return 0 + + + def getbuffer(self, image): + img = image + imwidth, imheight = img.size + if(imwidth == self.width and imheight == self.height): + img = img.convert('1') + elif(imwidth == self.height and imheight == self.width): + # image has correct dimensions, but needs to be rotated + img = img.rotate(90, expand=True).convert('1') + else: + logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) + # return a blank buffer + return [0x00] * (int(self.width/8) * self.height) + + buf = bytearray(img.tobytes('raw')) + # The bytes need to be inverted, because in the PIL world 0=black and 1=white, but + # in the e-paper world 0=white and 1=black. + for i in range(len(buf)): + buf[i] ^= 0xFF + return buf + + def display(self, image): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + image1 = [0xFF] * int(self.width * self.height / 8) + for j in range(Height): + for i in range(Width): + image1[i + j * Width] = ~image[i + j * Width] + self.send_command(0x10) + self.send_data2(image1) + + self.send_command(0x13) + self.send_data2(image) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def Clear(self): + self.send_command(0x10) + self.send_data2([0xFF] * int(self.width * self.height / 8)) + self.send_command(0x13) + self.send_data2([0x00] * int(self.width * self.height / 8)) + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def display_Partial(self, Image, Xstart, Ystart, Xend, Yend): + if((Xstart % 8 + Xend % 8 == 8 & Xstart % 8 > Xend % 8) | Xstart % 8 + Xend % 8 == 0 | (Xend - Xstart)%8 == 0): + Xstart = Xstart // 8 * 8 + Xend = Xend // 8 * 8 + else: + Xstart = Xstart // 8 * 8 + if Xend % 8 == 0: + Xend = Xend // 8 * 8 + else: + Xend = Xend // 8 * 8 + 1 + + Width = (Xend - Xstart) // 8 + Height = Yend - Ystart + + self.send_command(0x50) + self.send_data(0xA9) + self.send_data(0x07) + + self.send_command(0x91) #This command makes the display enter partial mode + self.send_command(0x90) #resolution setting + self.send_data (Xstart//256) + self.send_data (Xstart%256) #x-start + + self.send_data ((Xend-1)//256) + self.send_data ((Xend-1)%256) #x-end + + self.send_data (Ystart//256) # + self.send_data (Ystart%256) #y-start + + self.send_data ((Yend-1)//256) + self.send_data ((Yend-1)%256) #y-end + self.send_data (0x01) + + image1 = [0xFF] * int(self.width * self.height / 8) + for j in range(Height): + for i in range(Width): + image1[i + j * Width] = ~Image[i + j * Width] + + self.send_command(0x13) #Write Black and White image to RAM + self.send_data2(image1) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### diff --git a/lib/waveshare_epd/epd7in5b_HD.py b/lib/waveshare_epd/epd7in5b_HD.py index 8bd4333..4321d9c 100644 --- a/lib/waveshare_epd/epd7in5b_HD.py +++ b/lib/waveshare_epd/epd7in5b_HD.py @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 880 EPD_HEIGHT = 528 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -66,7 +68,7 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") busy = epdconfig.digital_read(self.busy_pin) while(busy == 1): busy = epdconfig.digital_read(self.busy_pin) @@ -78,78 +80,78 @@ class EPD: self.reset() - self.send_command(0x12); #SWRESET - self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal + self.send_command(0x12) #SWRESET + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal - self.send_command(0x46); # Auto Write RAM - self.send_data(0xF7); - self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal + self.send_command(0x46) # Auto Write RAM + self.send_data(0xF7) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal - self.send_command(0x47); # Auto Write RAM - self.send_data(0xF7); - self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal + self.send_command(0x47) # Auto Write RAM + self.send_data(0xF7) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal - self.send_command(0x0C); # Soft start setting - self.send_data(0xAE); - self.send_data(0xC7); - self.send_data(0xC3); - self.send_data(0xC0); - self.send_data(0x40); + self.send_command(0x0C) # Soft start setting + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0x40) - self.send_command(0x01); # Set MUX as 527 - self.send_data(0xAF); - self.send_data(0x02); - self.send_data(0x01); + self.send_command(0x01) # Set MUX as 527 + self.send_data(0xAF) + self.send_data(0x02) + self.send_data(0x01) - self.send_command(0x11); # Data entry mode - self.send_data(0x01); + self.send_command(0x11) # Data entry mode + self.send_data(0x01) - self.send_command(0x44); - self.send_data(0x00); # RAM x address start at 0 - self.send_data(0x00); - self.send_data(0x6F); # RAM x address end at 36Fh -> 879 - self.send_data(0x03); - self.send_command(0x45); - self.send_data(0xAF); # RAM y address start at 20Fh; - self.send_data(0x02); - self.send_data(0x00); # RAM y address end at 00h; - self.send_data(0x00); + self.send_command(0x44) + self.send_data(0x00) # RAM x address start at 0 + self.send_data(0x00) + self.send_data(0x6F) # RAM x address end at 36Fh -> 879 + self.send_data(0x03) + self.send_command(0x45) + self.send_data(0xAF) # RAM y address start at 20Fh + self.send_data(0x02) + self.send_data(0x00) # RAM y address end at 00h + self.send_data(0x00) - self.send_command(0x3C); # VBD - self.send_data(0x01); # LUT1, for white + self.send_command(0x3C) # VBD + self.send_data(0x01) # LUT1, for white - self.send_command(0x18); - self.send_data(0X80); - self.send_command(0x22); - self.send_data(0XB1); #Load Temperature and waveform setting. - self.send_command(0x20); - self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal + self.send_command(0x18) + self.send_data(0X80) + self.send_command(0x22) + self.send_data(0XB1) #Load Temperature and waveform setting. + self.send_command(0x20) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal - self.send_command(0x4E); - self.send_data(0x00); - self.send_data(0x00); - self.send_command(0x4F); - self.send_data(0xAF); - self.send_data(0x02); + self.send_command(0x4E) + self.send_data(0x00) + self.send_data(0x00) + self.send_command(0x4F) + self.send_data(0xAF) + self.send_data(0x02) return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) + logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): newx = y @@ -159,46 +161,46 @@ class EPD: return buf def display(self, imageblack, imagered): - self.send_command(0x4F); - self.send_data(0xAf); + self.send_command(0x4F) + self.send_data(0xAf) self.send_command(0x24) for i in range(0, int(self.width * self.height / 8)): - self.send_data(imageblack[i]); + self.send_data(imageblack[i]) self.send_command(0x26) for i in range(0, int(self.width * self.height / 8)): - self.send_data(~imagered[i]); + self.send_data(~imagered[i]) - self.send_command(0x22); - self.send_data(0xC7); #Load LUT from MCU(0x32) - self.send_command(0x20); - epdconfig.delay_ms(200); #!!!The delay here is necessary, 200uS at least!!! - self.ReadBusy(); + self.send_command(0x22) + self.send_data(0xC7) #Load LUT from MCU(0x32) + self.send_command(0x20) + epdconfig.delay_ms(200) #!!!The delay here is necessary, 200uS at least!!! + self.ReadBusy() def Clear(self): - self.send_command(0x4F); - self.send_data(0xAf); + self.send_command(0x4F) + self.send_data(0xAf) self.send_command(0x24) for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xff); + self.send_data(0xff) self.send_command(0x26) for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00); + self.send_data(0x00) - self.send_command(0x22); - self.send_data(0xC7); #Load LUT from MCU(0x32) - self.send_command(0x20); - epdconfig.delay_ms(200); #!!!The delay here is necessary, 200uS at least!!! - self.ReadBusy(); + self.send_command(0x22) + self.send_data(0xC7) #Load LUT from MCU(0x32) + self.send_command(0x20) + epdconfig.delay_ms(200) #!!!The delay here is necessary, 200uS at least!!! + self.ReadBusy() def sleep(self): - self.send_command(0x10); #deep sleep - self.send_data(0x01); + self.send_command(0x10) #deep sleep + self.send_data(0x01) epdconfig.delay_ms(2000) epdconfig.module_exit() diff --git a/lib/waveshare_epd/epd7in5b_V2.py b/lib/waveshare_epd/epd7in5b_V2.py index e3bb295..8ae62dd 100644 --- a/lib/waveshare_epd/epd7in5b_V2.py +++ b/lib/waveshare_epd/epd7in5b_V2.py @@ -4,8 +4,8 @@ # * | Function : Electronic paper driver # * | Info : # *---------------- -# * | This version: V4.1 -# * | Date : 2020-11-30 +# * | This version: V4.2 +# * | Date : 2022-01-08 # # | Info : python demo # ----------------------------------------------------------------------------- # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 800 EPD_HEIGHT = 480 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -43,6 +45,7 @@ class EPD: self.cs_pin = epdconfig.CS_PIN self.width = EPD_WIDTH self.height = EPD_HEIGHT + self.partFlag=1 # Hardware reset def reset(self): @@ -64,111 +67,232 @@ class EPD: epdconfig.digital_write(self.cs_pin, 0) epdconfig.spi_writebyte([data]) epdconfig.digital_write(self.cs_pin, 1) - + + def send_data2(self, data): #faster + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") self.send_command(0x71) busy = epdconfig.digital_read(self.busy_pin) while(busy == 0): self.send_command(0x71) busy = epdconfig.digital_read(self.busy_pin) epdconfig.delay_ms(200) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): return -1 - - self.reset() - # self.send_command(0x06) # btst - # self.send_data(0x17) - # self.send_data(0x17) - # self.send_data(0x38) # If an exception is displayed, try using 0x38 - # self.send_data(0x17) + # EPD hardware init start + self.reset() - self.send_command(0x01); #POWER SETTING - self.send_data(0x07); - self.send_data(0x07); #VGH=20V,VGL=-20V - self.send_data(0x3f); #VDH=15V - self.send_data(0x3f); #VDL=-15V + self.send_command(0x01) + self.send_data(0x07) + self.send_data(0x07) + self.send_data(0x3f) + self.send_data(0x3f) - self.send_command(0x04); #POWER ON - epdconfig.delay_ms(100); - self.ReadBusy(); + self.send_command(0x06) + self.send_data(0x17) + self.send_data(0x17) + self.send_data(0x28) + self.send_data(0x17) - self.send_command(0X00); #PANNEL SETTING - self.send_data(0x0F); #KW-3f KWR-2F BWROTP 0f BWOTP 1f + self.send_command(0x04) + epdconfig.delay_ms(100) + self.ReadBusy() - self.send_command(0x61); #tres - self.send_data(0x03); #source 800 - self.send_data(0x20); - self.send_data(0x01); #gate 480 - self.send_data(0xE0); + self.send_command(0X00) + self.send_data(0x0F) - self.send_command(0X15); - self.send_data(0x00); + self.send_command(0x61) + self.send_data(0x03) + self.send_data(0x20) + self.send_data(0x01) + self.send_data(0xE0) - self.send_command(0X50); #VCOM AND DATA INTERVAL SETTING - self.send_data(0x11); - self.send_data(0x07); + self.send_command(0X15) + self.send_data(0x00) - self.send_command(0X60); #TCON SETTING - self.send_data(0x22); + self.send_command(0X50) + self.send_data(0x11) + self.send_data(0x07) - self.send_command(0x65); - self.send_data(0x00); - self.send_data(0x00); - self.send_data(0x00); - self.send_data(0x00); + self.send_command(0X60) + self.send_data(0x22) + + return 0 + def init_Fast(self): + if (epdconfig.module_init() != 0): + return -1 + + # EPD hardware init start + self.reset() + + self.send_command(0X00) + self.send_data(0x0F) + + self.send_command(0x04) + epdconfig.delay_ms(100) + self.ReadBusy() + + self.send_command(0x06) + self.send_data(0x27) + self.send_data(0x27) + self.send_data(0x18) + self.send_data(0x17) + + self.send_command(0xE0) + self.send_data(0x02) + self.send_command(0xE5) + self.send_data(0x5A) + + self.send_command(0X50) + self.send_data(0x11) + self.send_data(0x07) + + return 0 + + def init_part(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0X00) + self.send_data(0x1F) + + self.send_command(0x04) + epdconfig.delay_ms(100) + self.ReadBusy() + + self.send_command(0xE0) + self.send_data(0x02) + self.send_command(0xE5) + self.send_data(0x6E) + + self.send_command(0X50) + self.send_data(0xA9) + self.send_data(0x07) + + # EPD hardware init end return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) - buf = [0xFF] * (int(self.width/8) * self.height) - image_monocolor = image.convert('1') - imwidth, imheight = image_monocolor.size - pixels = image_monocolor.load() - logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) + img = image + imwidth, imheight = img.size if(imwidth == self.width and imheight == self.height): - logging.debug("Horizontal") - for y in range(imheight): - for x in range(imwidth): - # Set the bits for the column of pixels at the current position. - if pixels[x, y] == 0: - buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + img = img.convert('1') elif(imwidth == self.height and imheight == self.width): - logging.debug("Vertical") - for y in range(imheight): - for x in range(imwidth): - newx = y - newy = self.height - x - 1 - if pixels[x, y] == 0: - buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + # image has correct dimensions, but needs to be rotated + img = img.rotate(90, expand=True).convert('1') + else: + logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) + # return a blank buffer + return [0x00] * (int(self.width/8) * self.height) + + buf = bytearray(img.tobytes('raw')) + # The bytes need to be inverted, because in the PIL world 0=black and 1=white, but + # in the e-paper world 0=white and 1=black. + for i in range(len(buf)): + buf[i] ^= 0xFF return buf def display(self, imageblack, imagered): self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(imageblack[i]); - + # The black bytes need to be inverted back from what getbuffer did + for i in range(len(imageblack)): + imageblack[i] ^= 0xFF + self.send_data2(imageblack) + self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(~imagered[i]); + self.send_data2(imagered) self.send_command(0x12) epdconfig.delay_ms(100) self.ReadBusy() + + def display_Base_color(self, color): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + self.send_command(0x10) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(color) + + self.send_command(0x13) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(~color) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def display_Partial(self, Image, Xstart, Ystart, Xend, Yend): + if((Xstart % 8 + Xend % 8 == 8 & Xstart % 8 > Xend % 8) | Xstart % 8 + Xend % 8 == 0 | (Xend - Xstart)%8 == 0): + Xstart = Xstart // 8 * 8 + Xend = Xend // 8 * 8 + else: + Xstart = Xstart // 8 * 8 + if Xend % 8 == 0: + Xend = Xend // 8 * 8 + else: + Xend = Xend // 8 * 8 + 1 + + Width = (Xend - Xstart) // 8 + Height = Yend - Ystart + + # self.send_command(0x50) + # self.send_data(0xA9) + # self.send_data(0x07) + + self.send_command(0x91) #This command makes the display enter partial mode + self.send_command(0x90) #resolution setting + self.send_data (Xstart//256) + self.send_data (Xstart%256) #x-start + + self.send_data ((Xend-1)//256) + self.send_data ((Xend-1)%256) #x-end + + self.send_data (Ystart//256) # + self.send_data (Ystart%256) #y-start + + self.send_data ((Yend-1)//256) + self.send_data ((Yend-1)%256) #y-end + self.send_data (0x01) + + if self.partFlag == 1: + self.partFlag = 0 + self.send_command(0x10) + for j in range(Height): + for i in range(Width): + self.send_data(0xff) + + self.send_command(0x13) #Write Black and White image to RAM + self.send_data2(Image) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() def Clear(self): + buf = [0x00] * (int(self.width/8) * self.height) + buf2 = [0xff] * (int(self.width/8) * self.height) self.send_command(0x10) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xff) + self.send_data2(buf2) self.send_command(0x13) - for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00) + self.send_data2(buf) self.send_command(0x12) epdconfig.delay_ms(100) diff --git a/lib/waveshare_epd/epd7in5b_V2_old.py b/lib/waveshare_epd/epd7in5b_V2_old.py new file mode 100644 index 0000000..80140bc --- /dev/null +++ b/lib/waveshare_epd/epd7in5b_V2_old.py @@ -0,0 +1,192 @@ +# ***************************************************************************** +# * | File : epd7in5b_V2.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V4.2 +# * | Date : 2022-01-08 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 800 +EPD_HEIGHT = 480 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(4) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data2(self, data): #faster + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + self.send_command(0x71) + busy = epdconfig.digital_read(self.busy_pin) + while(busy == 0): + self.send_command(0x71) + busy = epdconfig.digital_read(self.busy_pin) + epdconfig.delay_ms(200) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + # self.send_command(0x06) # btst + # self.send_data(0x17) + # self.send_data(0x17) + # self.send_data(0x38) # If an exception is displayed, try using 0x38 + # self.send_data(0x17) + + self.send_command(0x01) # POWER SETTING + self.send_data(0x07) + self.send_data(0x07) # VGH=20V,VGL=-20V + self.send_data(0x3f) # VDH=15V + self.send_data(0x3f) # VDL=-15V + + self.send_command(0x04) # POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() + + self.send_command(0X00) # PANNEL SETTING + self.send_data(0x0F) # KW-3f KWR-2F BWROTP-0f BWOTP-1f + + self.send_command(0x61) # tres + self.send_data(0x03) # source 800 + self.send_data(0x20) + self.send_data(0x01) # gate 480 + self.send_data(0xE0) + + self.send_command(0X15) + self.send_data(0x00) + + self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING + self.send_data(0x11) + self.send_data(0x07) + + self.send_command(0X60) # TCON SETTING + self.send_data(0x22) + + self.send_command(0x65) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + + return 0 + + def getbuffer(self, image): + img = image + imwidth, imheight = img.size + if(imwidth == self.width and imheight == self.height): + img = img.convert('1') + elif(imwidth == self.height and imheight == self.width): + # image has correct dimensions, but needs to be rotated + img = img.rotate(90, expand=True).convert('1') + else: + logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) + # return a blank buffer + return [0x00] * (int(self.width/8) * self.height) + + buf = bytearray(img.tobytes('raw')) + # The bytes need to be inverted, because in the PIL world 0=black and 1=white, but + # in the e-paper world 0=white and 1=black. + for i in range(len(buf)): + buf[i] ^= 0xFF + return buf + + def display(self, imageblack, imagered): + self.send_command(0x10) + # The black bytes need to be inverted back from what getbuffer did + for i in range(len(imageblack)): + imageblack[i] ^= 0xFF + self.send_data2(imageblack) + + self.send_command(0x13) + self.send_data2(imagered) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def Clear(self): + buf = [0x00] * (int(self.width/8) * self.height) + buf2 = [0xff] * (int(self.width/8) * self.height) + self.send_command(0x10) + self.send_data2(buf2) + + self.send_command(0x13) + self.send_data2(buf) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/lib/waveshare_epd/epd7in5bc.py b/lib/waveshare_epd/epd7in5bc.py index 3b78068..14c491c 100644 --- a/lib/waveshare_epd/epd7in5bc.py +++ b/lib/waveshare_epd/epd7in5bc.py @@ -35,6 +35,8 @@ from . import epdconfig EPD_WIDTH = 640 EPD_HEIGHT = 384 +logger = logging.getLogger(__name__) + class EPD: def __init__(self): self.reset_pin = epdconfig.RST_PIN @@ -66,10 +68,10 @@ class EPD: epdconfig.digital_write(self.cs_pin, 1) def ReadBusy(self): - logging.debug("e-Paper busy") + logger.debug("e-Paper busy") while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy epdconfig.delay_ms(100) - logging.debug("e-Paper busy release") + logger.debug("e-Paper busy release") def init(self): if (epdconfig.module_init() != 0): @@ -117,21 +119,21 @@ class EPD: return 0 def getbuffer(self, image): - # logging.debug("bufsiz = ",int(self.width/8) * self.height) + # logger.debug("bufsiz = ",int(self.width/8) * self.height) buf = [0xFF] * (int(self.width/8) * self.height) image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size pixels = image_monocolor.load() - logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) + logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) if(imwidth == self.width and imheight == self.height): - logging.debug("Horizontal") + logger.debug("Horizontal") for y in range(imheight): for x in range(imwidth): # Set the bits for the column of pixels at the current position. if pixels[x, y] == 0: buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) elif(imwidth == self.height and imheight == self.width): - logging.debug("Vertical") + logger.debug("Vertical") for y in range(imheight): for x in range(imwidth): newx = y diff --git a/lib/waveshare_epd/epdconfig.py b/lib/waveshare_epd/epdconfig.py index 028f231..b390252 100644 --- a/lib/waveshare_epd/epdconfig.py +++ b/lib/waveshare_epd/epdconfig.py @@ -319,4 +319,4 @@ else: for func in [x for x in dir(implementation) if not x.startswith('_')]: setattr(sys.modules[__name__], func, getattr(implementation, func)) -### END OF FILE ### \ No newline at end of file +### END OF FILE ### diff --git a/lib/waveshare_epd/epdconfig.pyc b/lib/waveshare_epd/epdconfig.pyc index 5f8398e..be4996b 100644 Binary files a/lib/waveshare_epd/epdconfig.pyc and b/lib/waveshare_epd/epdconfig.pyc differ