diff --git a/Calendar/Epd7in5Adapter.py b/Calendar/Epd7in5Adapter.py new file mode 100644 index 0000000..aa53bfd --- /dev/null +++ b/Calendar/Epd7in5Adapter.py @@ -0,0 +1,47 @@ +from EpdAdapter import EpdAdapter, DISPLAY_REFRESH, DATA_START_TRANSMISSION_1 + +class Epd7in5Adapter (EpdAdapter): + def __init__ (): + super(Epd7in5Adapter, self).__init__(640, 384) + + def display_frame (self, frame_buffer): + self.send_command(DATA_START_TRANSMISSION_1) + for i in range(0, 30720): + temp1 = frame_buffer[i] + j = 0 + while (j < 8): + if(temp1 & 0x80): + temp2 = 0x03 + else: + temp2 = 0x00 + temp2 = (temp2 << 4) & 0xFF + temp1 = (temp1 << 1) & 0xFF + j += 1 + if(temp1 & 0x80): + temp2 |= 0x03 + else: + temp2 |= 0x00 + temp1 = (temp1 << 1) & 0xFF + self.send_data(temp2) + j += 1 + self.send_command(DISPLAY_REFRESH) + self.delay_ms(100) + self.wait_until_idle() + + def get_frame_buffer (self, image): + buf = [0x00] * int(self.width * self.height / 8) + # Set buffer to value of Python Imaging Library image. + # Image must be in mode 1. + image_monocolor = image.convert('1') #with ot withour dithering? + imwidth, imheight = image_monocolor.size + if imwidth != self.width or imheight != self.height: + raise ValueError('Image must be same dimensions as display \ + ({0}x{1}).' .format(self.width, self.height)) + + pixels = image_monocolor.load() + for y in range(self.height): + for x in range(self.width): + # 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) + return buf \ No newline at end of file diff --git a/Calendar/Epd7in5bAdapter.py b/Calendar/Epd7in5bAdapter.py new file mode 100644 index 0000000..f2311a2 --- /dev/null +++ b/Calendar/Epd7in5bAdapter.py @@ -0,0 +1,60 @@ +from EpdAdapter import EpdAdapter, DISPLAY_REFRESH, DATA_START_TRANSMISSION_1 + +class Epd7in5bAdapter (EpdAdapter): + def __init__ (): + super(Epd7in5bAdapter, self).__init__(640, 384) + + def display_frame (self, frame_buffer): + self.send_command(DATA_START_TRANSMISSION_1) + for i in range(0, int(self.width / 4 * self.height)): + #the above line had to be modified due to python2 -> python3 + #the issue lies in division, which returns integers in python2 + #but floats in python3 + temp1 = frame_buffer[i] + j = 0 + while (j < 4): + if ((temp1 & 0xC0) == 0xC0): + temp2 = 0x03 + elif ((temp1 & 0xC0) == 0x00): + temp2 = 0x00 + else: + temp2 = 0x04 + temp2 = (temp2 << 4) & 0xFF + temp1 = (temp1 << 2) & 0xFF + j += 1 + if((temp1 & 0xC0) == 0xC0): + temp2 |= 0x03 + elif ((temp1 & 0xC0) == 0x00): + temp2 |= 0x00 + else: + temp2 |= 0x04 + temp1 = (temp1 << 2) & 0xFF + self.send_data(temp2) + j += 1 + self.send_command(DISPLAY_REFRESH) + self.delay_ms(100) + self.wait_until_idle() + + def get_frame_buffer (self, image): + buf = [0x00] * int(self.width * self.height / 4) + # Set buffer to value of Python Imaging Library image. + # Image must be in mode L. + image_grayscale = image.convert('L', dither=None) + imwidth, imheight = image_grayscale.size + if imwidth != self.width or imheight != self.height: + raise ValueError('Image must be same dimensions as display \ + ({0}x{1}).' .format(self.width, self.height)) + + pixels = image_grayscale.load() + for y in range(self.height): + for x in range(self.width): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] < 75: #was 64 # black + buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2)) + elif pixels[x, y] < 110: #was 192 # convert gray to red + buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2)) + buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2) + else: # white + buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2) + return buf #due to python2 -> python3, int had to be added in 'get_frame + #_buffer \ No newline at end of file diff --git a/Calendar/EpdAdapter.py b/Calendar/EpdAdapter.py new file mode 100644 index 0000000..9a79868 --- /dev/null +++ b/Calendar/EpdAdapter.py @@ -0,0 +1,177 @@ +from DisplayAdapter import DisplayAdapter +import spidev +import RPi.GPIO as GPIO +import time +from PIL import Image + +RST_PIN = 17 +DC_PIN = 25 +CS_PIN = 8 +BUSY_PIN = 24 + +# Commands +PANEL_SETTING = 0x00 +POWER_SETTING = 0x01 +POWER_OFF = 0x02 +POWER_OFF_SEQUENCE_SETTING = 0x03 +POWER_ON = 0x04 +POWER_ON_MEASURE = 0x05 +BOOSTER_SOFT_START = 0x06 +DEEP_SLEEP = 0x07 +DATA_START_TRANSMISSION_1 = 0x10 +DATA_STOP = 0x11 +DISPLAY_REFRESH = 0x12 +IMAGE_PROCESS = 0x13 +LUT_FOR_VCOM = 0x20 +LUT_BLUE = 0x21 +LUT_WHITE = 0x22 +LUT_GRAY_1 = 0x23 +LUT_GRAY_2 = 0x24 +LUT_RED_0 = 0x25 +LUT_RED_1 = 0x26 +LUT_RED_2 = 0x27 +LUT_RED_3 = 0x28 +LUT_XON = 0x29 +PLL_CONTROL = 0x30 +TEMPERATURE_SENSOR_COMMAND = 0x40 +TEMPERATURE_CALIBRATION = 0x41 +TEMPERATURE_SENSOR_WRITE = 0x42 +TEMPERATURE_SENSOR_READ = 0x43 +VCOM_AND_DATA_INTERVAL_SETTING = 0x50 +LOW_POWER_DETECTION = 0x51 +TCON_SETTING = 0x60 +TCON_RESOLUTION = 0x61 +SPI_FLASH_CONTROL = 0x65 +REVISION = 0x70 +GET_STATUS = 0x71 +AUTO_MEASUREMENT_VCOM = 0x80 +READ_VCOM_VALUE = 0x81 +VCM_DC_SETTING = 0x82 + +class EpdAdapter (DisplayAdapter): + """Generalized adapter for epd7in5 and epd7in5b""" + def __init__ (self, width, height): + self.width = width + self.height = height + + self.reset_pin = RST_PIN + self.dc_pin = DC_PIN + self.busy_pin = BUSY_PIN + + self.epd_init() + + def display_frame (self, frame_buffer): + raise NotImplementedError("Functions needs to be implemented") + + def get_frame_buffer (self, image): + raise NotImplementedError("Functions needs to be implemented") + + def render (self, design): + self.init_render() + time.sleep(5) + + prepared_image = design.get_image().rotate(270, expand=1) + self.display_frame(self.get_frame_buffer(prepared_image)) + + # Powering off the E-Paper until the next loop + self.sleep() + + def init_render (self): + if (self.epd_init() != 0): + return -1 + self.reset() + + self.send_command(POWER_SETTING) + self.send_data(0x37) + self.send_data(0x00) + + self.send_command(PANEL_SETTING) + self.send_data(0xCF) + self.send_data(0x08) + + self.send_command(BOOSTER_SOFT_START) + self.send_data(0xc7) + self.send_data(0xcc) + self.send_data(0x28) + + self.send_command(POWER_ON) + self.wait_until_idle() + + self.send_command(PLL_CONTROL) + self.send_data(0x3c) + + self.send_command(TEMPERATURE_CALIBRATION) + self.send_data(0x00) + + self.send_command(VCOM_AND_DATA_INTERVAL_SETTING) + self.send_data(0x77) + + self.send_command(TCON_SETTING) + self.send_data(0x22) + + self.send_command(TCON_RESOLUTION) + self.send_data(0x02) #source 640 + self.send_data(0x80) + self.send_data(0x01) #gate 384 + self.send_data(0x80) + + self.send_command(VCM_DC_SETTING) + self.send_data(0x1E) #decide by LUT file + + self.send_command(0xe5) #FLASH MODE + self.send_data(0x03) + + def digital_write (self, pin, value): + GPIO.output(pin, value) + + def digital_read (self, pin): + return GPIO.input(pin) + + def delay_ms (self, delaytime): + time.sleep(delaytime / 1000.0) + + def spi_transfer (self, data): + SPI.writebytes(data) + + def epd_init (self): + # SPI device, bus = 0, device = 0 + SPI = spidev.SpiDev(0, 0) + #SPI.no_cs = True + + GPIO.setmode(GPIO.BCM) + GPIO.setwarnings(False) + GPIO.setup(RST_PIN, GPIO.OUT) + GPIO.setup(DC_PIN, GPIO.OUT) + GPIO.setup(CS_PIN, GPIO.OUT) + GPIO.setup(BUSY_PIN, GPIO.IN) + SPI.max_speed_hz = 2000000 + SPI.mode = 0b00 + return 0 + + def sleep (self): + self.send_command(POWER_OFF) + self.wait_until_idle() + self.send_command(DEEP_SLEEP) + self.send_data(0xa5) + + def wait_until_idle (self): + while(self.digital_read(self.busy_pin) == 0): # 0: busy, 1: idle + self.delay_ms(100) + + def reset (self): + self.digital_write(self.reset_pin, GPIO.LOW) # module reset + self.delay_ms(200) + self.digital_write(self.reset_pin, GPIO.HIGH) + self.delay_ms(200) + + def send_command (self, command): + self.digital_write(self.dc_pin, GPIO.LOW) + # the parameter type is list but not int + # so use [command] instead of command + self.spi_transfer([ command ]) + + def send_data (self, data): + self.digital_write(self.dc_pin, GPIO.HIGH) + # the parameter type is list but not int + # so use [data] instead of data + self.spi_transfer([ data ]) \ No newline at end of file