epd4in26.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. # *****************************************************************************
  2. # * | File : epd4in26.py
  3. # * | Author : Waveshare team
  4. # * | Function : Electronic paper driver
  5. # * | Info :
  6. # *----------------
  7. # * | This version: V1.0
  8. # * | Date : 2023-12-20
  9. # # | Info : python demo
  10. # -----------------------------------------------------------------------------
  11. # Permission is hereby granted, free of charge, to any person obtaining a copy
  12. # of this software and associated documnetation files (the "Software"), to deal
  13. # in the Software without restriction, including without limitation the rights
  14. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. # copies of the Software, and to permit persons to whom the Software is
  16. # furished to do so, subject to the following conditions:
  17. #
  18. # The above copyright notice and this permission notice shall be included in
  19. # all copies or substantial portions of the Software.
  20. #
  21. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. # THE SOFTWARE.
  28. #
  29. import logging
  30. from . import epdconfig
  31. # Display resolution
  32. EPD_WIDTH = 800
  33. EPD_HEIGHT = 480
  34. GRAY1 = 0xff #white
  35. GRAY2 = 0xC0
  36. GRAY3 = 0x80 #gray
  37. GRAY4 = 0x00 #Blackest
  38. logger = logging.getLogger(__name__)
  39. class EPD:
  40. def __init__(self):
  41. self.reset_pin = epdconfig.RST_PIN
  42. self.dc_pin = epdconfig.DC_PIN
  43. self.busy_pin = epdconfig.BUSY_PIN
  44. self.cs_pin = epdconfig.CS_PIN
  45. self.width = EPD_WIDTH
  46. self.height = EPD_HEIGHT
  47. self.GRAY1 = GRAY1 #white
  48. self.GRAY2 = GRAY2
  49. self.GRAY3 = GRAY3 #gray
  50. self.GRAY4 = GRAY4 #Blackest
  51. LUT_DATA_4Gray = [# #112bytes
  52. 0x80, 0x48, 0x4A, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  53. 0x0A, 0x48, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  54. 0x88, 0x48, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  55. 0xA8, 0x48, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  56. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  57. 0x07, 0x1E, 0x1C, 0x02, 0x00,
  58. 0x05, 0x01, 0x05, 0x01, 0x02,
  59. 0x08, 0x01, 0x01, 0x04, 0x04,
  60. 0x00, 0x02, 0x00, 0x02, 0x01,
  61. 0x00, 0x00, 0x00, 0x00, 0x00,
  62. 0x00, 0x00, 0x00, 0x00, 0x00,
  63. 0x00, 0x00, 0x00, 0x00, 0x00,
  64. 0x00, 0x00, 0x00, 0x00, 0x00,
  65. 0x00, 0x00, 0x00, 0x00, 0x00,
  66. 0x00, 0x00, 0x00, 0x00, 0x01,
  67. 0x22, 0x22, 0x22, 0x22, 0x22,
  68. 0x17, 0x41, 0xA8, 0x32, 0x30,
  69. 0x00, 0x00 ]
  70. # Hardware reset
  71. def reset(self):
  72. epdconfig.digital_write(self.reset_pin, 1)
  73. epdconfig.delay_ms(20)
  74. epdconfig.digital_write(self.reset_pin, 0)
  75. epdconfig.delay_ms(2)
  76. epdconfig.digital_write(self.reset_pin, 1)
  77. epdconfig.delay_ms(20)
  78. def send_command(self, command):
  79. epdconfig.digital_write(self.dc_pin, 0)
  80. epdconfig.digital_write(self.cs_pin, 0)
  81. epdconfig.spi_writebyte([command])
  82. epdconfig.digital_write(self.cs_pin, 1)
  83. def send_data(self, data):
  84. epdconfig.digital_write(self.dc_pin, 1)
  85. epdconfig.digital_write(self.cs_pin, 0)
  86. epdconfig.spi_writebyte([data])
  87. epdconfig.digital_write(self.cs_pin, 1)
  88. def send_data2(self, data):
  89. epdconfig.digital_write(self.dc_pin, 1)
  90. epdconfig.digital_write(self.cs_pin, 0)
  91. epdconfig.SPI.writebytes2(data)
  92. epdconfig.digital_write(self.cs_pin, 1)
  93. def ReadBusy(self):
  94. logger.debug("e-Paper busy")
  95. busy = epdconfig.digital_read(self.busy_pin)
  96. while(busy == 1):
  97. busy = epdconfig.digital_read(self.busy_pin)
  98. epdconfig.delay_ms(20)
  99. epdconfig.delay_ms(20)
  100. logger.debug("e-Paper busy release")
  101. def TurnOnDisplay(self):
  102. self.send_command(0x22) #Display Update Control
  103. self.send_data(0xF7)
  104. self.send_command(0x20) #Activate Display Update Sequence
  105. self.ReadBusy()
  106. def TurnOnDisplay_Fast(self):
  107. self.send_command(0x22) #Display Update Control
  108. self.send_data(0xC7)
  109. self.send_command(0x20) #Activate Display Update Sequence
  110. self.ReadBusy()
  111. def TurnOnDisplay_Part(self):
  112. self.send_command(0x22) #Display Update Control
  113. self.send_data(0xFF)
  114. self.send_command(0x20) #Activate Display Update Sequence
  115. self.ReadBusy()
  116. def TurnOnDisplay_4GRAY(self):
  117. self.send_command(0x22) #Display Update Control
  118. self.send_data(0xC7)
  119. self.send_command(0x20) #Activate Display Update Sequence
  120. self.ReadBusy()
  121. '''
  122. function : Setting the display window
  123. parameter:
  124. xstart : X-axis starting position
  125. ystart : Y-axis starting position
  126. xend : End position of X-axis
  127. yend : End position of Y-axis
  128. '''
  129. def SetWindow(self, x_start, y_start, x_end, y_end):
  130. self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION
  131. self.send_data(x_start & 0xFF)
  132. self.send_data((x_start>>8) & 0x03)
  133. self.send_data(x_end & 0xFF)
  134. self.send_data((x_end>>8) & 0x03)
  135. self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION
  136. self.send_data(y_start & 0xFF)
  137. self.send_data((y_start >> 8) & 0xFF)
  138. self.send_data(y_end & 0xFF)
  139. self.send_data((y_end >> 8) & 0xFF)
  140. '''
  141. function : Set Cursor
  142. parameter:
  143. x : X-axis starting position
  144. y : Y-axis starting position
  145. '''
  146. def SetCursor(self, x, y):
  147. self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER
  148. # x point must be the multiple of 8 or the last 3 bits will be ignored
  149. self.send_data(x & 0xFF)
  150. self.send_data((x>>8) & 0x03)
  151. self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER
  152. self.send_data(y & 0xFF)
  153. self.send_data((y >> 8) & 0xFF)
  154. def init(self):
  155. if (epdconfig.module_init() != 0):
  156. return -1
  157. # EPD hardware init start
  158. self.reset()
  159. self.ReadBusy()
  160. self.send_command(0x12) #SWRESET
  161. self.ReadBusy()
  162. self.send_command(0x18) # use the internal temperature sensor
  163. self.send_data(0x80)
  164. self.send_command(0x0C) #set soft start
  165. self.send_data(0xAE)
  166. self.send_data(0xC7)
  167. self.send_data(0xC3)
  168. self.send_data(0xC0)
  169. self.send_data(0x80)
  170. self.send_command(0x01) # drive output control
  171. self.send_data((self.height-1)%256) # Y
  172. self.send_data((self.height-1)//256) # Y
  173. self.send_data(0x02)
  174. self.send_command(0x3C) # Border Border setting
  175. self.send_data(0x01)
  176. self.send_command(0x11) # data entry mode
  177. self.send_data(0x01) # X-mode x+ y-
  178. self.SetWindow(0, self.height-1, self.width-1, 0)
  179. self.SetCursor(0, 0)
  180. self.ReadBusy()
  181. # EPD hardware init end
  182. return 0
  183. def init_Fast(self):
  184. if (epdconfig.module_init() != 0):
  185. return -1
  186. # EPD hardware init start
  187. self.reset()
  188. self.ReadBusy()
  189. self.send_command(0x12) #SWRESET
  190. self.ReadBusy()
  191. self.send_command(0x18) # use the internal temperature sensor
  192. self.send_data(0x80)
  193. self.send_command(0x0C) #set soft start
  194. self.send_data(0xAE)
  195. self.send_data(0xC7)
  196. self.send_data(0xC3)
  197. self.send_data(0xC0)
  198. self.send_data(0x80)
  199. self.send_command(0x01) # drive output control
  200. self.send_data((self.height-1)%256) # Y
  201. self.send_data((self.height-1)//256) # Y
  202. self.send_data(0x02)
  203. self.send_command(0x3C) # Border Border setting
  204. self.send_data(0x01)
  205. self.send_command(0x11) # data entry mode
  206. self.send_data(0x01) # X-mode x+ y-
  207. self.SetWindow(0, self.height-1, self.width-1, 0)
  208. self.SetCursor(0, 0)
  209. self.ReadBusy()
  210. #TEMP (1.5s)
  211. self.send_command(0x1A)
  212. self.send_data(0x5A)
  213. self.send_command(0x22)
  214. self.send_data(0x91)
  215. self.send_command(0x20)
  216. self.ReadBusy()
  217. # EPD hardware init end
  218. return 0
  219. def Lut(self):
  220. self.send_command(0x32)
  221. for count in range(0, 105):
  222. self.send_data(self.LUT_DATA_4Gray[count])
  223. self.send_command(0x03) #VGH
  224. self.send_data(self.LUT_DATA_4Gray[105])
  225. self.send_command(0x04) #
  226. self.send_data(self.LUT_DATA_4Gray[106]) #VSH1
  227. self.send_data(self.LUT_DATA_4Gray[107]) #VSH2
  228. self.send_data(self.LUT_DATA_4Gray[108]) #VSL
  229. self.send_command(0x2C) #VCOM Voltage
  230. self.send_data(self.LUT_DATA_4Gray[109]) #0x1C
  231. def init_4GRAY(self):
  232. if (epdconfig.module_init() != 0):
  233. return -1
  234. # EPD hardware init start
  235. self.reset()
  236. self.ReadBusy()
  237. self.send_command(0x12) #SWRESET
  238. self.ReadBusy()
  239. self.send_command(0x18) # use the internal temperature sensor
  240. self.send_data(0x80)
  241. self.send_command(0x0C) #set soft start
  242. self.send_data(0xAE)
  243. self.send_data(0xC7)
  244. self.send_data(0xC3)
  245. self.send_data(0xC0)
  246. self.send_data(0x80)
  247. self.send_command(0x01) # drive output control
  248. self.send_data((self.height-1)%256) # Y
  249. self.send_data((self.height-1)//256) # Y
  250. self.send_data(0x02)
  251. self.send_command(0x3C) # Border Border setting
  252. self.send_data(0x01)
  253. self.send_command(0x11) # data entry mode
  254. self.send_data(0x01) # X-mode x+ y-
  255. self.SetWindow(0, self.height-1, self.width-1, 0)
  256. self.SetCursor(0, 0)
  257. self.ReadBusy()
  258. self.Lut()
  259. # EPD hardware init end
  260. return 0
  261. def getbuffer(self, image):
  262. # logger.debug("bufsiz = ",int(self.width/8) * self.height)
  263. buf = [0xFF] * (int(self.width / 8) * self.height)
  264. image_monocolor = image.convert('1')
  265. imwidth, imheight = image_monocolor.size
  266. pixels = image_monocolor.load()
  267. # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight)
  268. if imwidth == self.width and imheight == self.height:
  269. logger.debug("Horizontal")
  270. for y in range(imheight):
  271. for x in range(imwidth):
  272. # Set the bits for the column of pixels at the current position.
  273. if pixels[x, y] == 0:
  274. buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
  275. elif imwidth == self.height and imheight == self.width:
  276. logger.debug("Vertical")
  277. for y in range(imheight):
  278. for x in range(imwidth):
  279. newx = y
  280. newy = self.height - x - 1
  281. if pixels[x, y] == 0:
  282. buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8))
  283. return buf
  284. def getbuffer_4Gray(self, image):
  285. # logger.debug("bufsiz = ",int(self.width/8) * self.height)
  286. buf = [0xFF] * (int(self.width / 4) * self.height)
  287. image_monocolor = image.convert('L')
  288. imwidth, imheight = image_monocolor.size
  289. pixels = image_monocolor.load()
  290. i=0
  291. # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight)
  292. if(imwidth == self.width and imheight == self.height):
  293. logger.debug("Vertical")
  294. for y in range(imheight):
  295. for x in range(imwidth):
  296. # Set the bits for the column of pixels at the current position.
  297. if(pixels[x, y] == 0xC0):
  298. pixels[x, y] = 0x80
  299. elif (pixels[x, y] == 0x80):
  300. pixels[x, y] = 0x40
  301. i= i+1
  302. if(i%4 == 0):
  303. 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)
  304. elif(imwidth == self.height and imheight == self.width):
  305. logger.debug("Horizontal")
  306. for x in range(imwidth):
  307. for y in range(imheight):
  308. newx = y
  309. newy = self.height - x - 1
  310. if(pixels[x, y] == 0xC0):
  311. pixels[x, y] = 0x80
  312. elif (pixels[x, y] == 0x80):
  313. pixels[x, y] = 0x40
  314. i= i+1
  315. if(i%4 == 0):
  316. 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)
  317. return buf
  318. def display(self, image):
  319. self.send_command(0x24)
  320. self.send_data2(image)
  321. self.TurnOnDisplay()
  322. def display_Base(self, image):
  323. self.send_command(0x24)
  324. self.send_data2(image)
  325. self.send_command(0x26)
  326. self.send_data2(image)
  327. self.TurnOnDisplay()
  328. def display_Fast(self, image):
  329. self.send_command(0x24)
  330. self.send_data2(image)
  331. self.TurnOnDisplay_Fast()
  332. def display_Partial(self, Image):
  333. # Reset
  334. self.reset()
  335. self.send_command(0x18) #BorderWavefrom
  336. self.send_data(0x80)
  337. self.send_command(0x3C) #BorderWavefrom
  338. self.send_data(0x80)
  339. self.send_command(0x01) # drive output control
  340. self.send_data((self.height-1)%256) # Y
  341. self.send_data((self.height-1)//256) # Y
  342. self.send_command(0x11) # data entry mode
  343. self.send_data(0x01) # X-mode x+ y-
  344. self.SetWindow(0, self.height-1, self.width-1, 0)
  345. self.SetCursor(0, 0)
  346. self.send_command(0x24) #Write Black and White image to RAM
  347. self.send_data2(Image)
  348. self.TurnOnDisplay_Part()
  349. def display_4Gray(self, image):
  350. self.send_command(0x24)
  351. for i in range(0, 48000): #5808*4 46464
  352. temp3=0
  353. for j in range(0, 2):
  354. temp1 = image[i*2+j]
  355. for k in range(0, 2):
  356. temp2 = temp1&0xC0
  357. if(temp2 == 0xC0):
  358. temp3 |= 0x00
  359. elif(temp2 == 0x00):
  360. temp3 |= 0x01
  361. elif(temp2 == 0x80):
  362. temp3 |= 0x01
  363. else: #0x40
  364. temp3 |= 0x00
  365. temp3 <<= 1
  366. temp1 <<= 2
  367. temp2 = temp1&0xC0
  368. if(temp2 == 0xC0):
  369. temp3 |= 0x00
  370. elif(temp2 == 0x00):
  371. temp3 |= 0x01
  372. elif(temp2 == 0x80):
  373. temp3 |= 0x01
  374. else : #0x40
  375. temp3 |= 0x00
  376. if(j!=1 or k!=1):
  377. temp3 <<= 1
  378. temp1 <<= 2
  379. self.send_data(temp3)
  380. self.send_command(0x26)
  381. for i in range(0, 48000): #5808*4 46464
  382. temp3=0
  383. for j in range(0, 2):
  384. temp1 = image[i*2+j]
  385. for k in range(0, 2):
  386. temp2 = temp1&0xC0
  387. if(temp2 == 0xC0):
  388. temp3 |= 0x00
  389. elif(temp2 == 0x00):
  390. temp3 |= 0x01
  391. elif(temp2 == 0x80):
  392. temp3 |= 0x00
  393. else: #0x40
  394. temp3 |= 0x01
  395. temp3 <<= 1
  396. temp1 <<= 2
  397. temp2 = temp1&0xC0
  398. if(temp2 == 0xC0):
  399. temp3 |= 0x00
  400. elif(temp2 == 0x00):
  401. temp3 |= 0x01
  402. elif(temp2 == 0x80):
  403. temp3 |= 0x00
  404. else: #0x40
  405. temp3 |= 0x01
  406. if(j!=1 or k!=1):
  407. temp3 <<= 1
  408. temp1 <<= 2
  409. self.send_data(temp3)
  410. self.TurnOnDisplay_4GRAY()
  411. def Clear(self):
  412. self.send_command(0x24)
  413. self.send_data2([0xFF] * (int(self.width/8) * self.height))
  414. self.send_command(0x26)
  415. self.send_data2([0xFF] * (int(self.width/8) * self.height))
  416. self.TurnOnDisplay()
  417. def sleep(self):
  418. self.send_command(0x10) # DEEP_SLEEP
  419. self.send_data(0x01)
  420. epdconfig.delay_ms(2000)
  421. epdconfig.module_exit()
  422. ### END OF FILE ###