e-Paper icon indicating copy to clipboard operation
e-Paper copied to clipboard

提升 python Clear() 和 display() 的性能

Open BoringCat opened this issue 5 years ago • 3 comments

Python脚本在跑 Clear() 和 display() 时有严重的性能问题,CPU利用率一直位于100%,后面发现是send_data消耗大量性能。 spi_writebyte最多可以输入4096bytes

  • 测试平台:Raspberry Pi Zero W
  • 测试系统:ArchLinux ARM (armv6l Linux 4.19.97-1-ARCH)
  • Python版本:Python 3.8.1
  • 问题代码: https://github.com/waveshare/e-Paper/blob/8973995e53cb78bac6d1f8a66c2d398c18392f71/RaspberryPi%26JetsonNano/python/lib/waveshare_epd/epd5in83.py#L62-L66
  • 改进方式:
    加入以下代码
    @@ -43,6 +43,7 @@ class EPD:
             self.cs_pin = epdconfig.CS_PIN
             self.width = EPD_WIDTH
             self.height = EPD_HEIGHT
    +        self.SPIMaxDatas = 4096
         
         # Hardware reset
         def reset(self):
    @@ -64,7 +65,29 @@ class EPD:
             epdconfig.digital_write(self.cs_pin, 0)
             epdconfig.spi_writebyte([data])
             epdconfig.digital_write(self.cs_pin, 1)
    -        
    +
    +    @staticmethod
    +    def _chunks(lst, n):
    +        """Yield successive n-sized chunks from lst."""
    +        for i in range(0, len(lst), n):
    +            yield lst[i:i + n]
    +
    +    def _send_large_datas(self, datas):
    +        for data in self._chunks(datas, self.SPIMaxDatas):
    +            self._send_datas(data)    
    +
    +    def _send_datas(self, datas):
    +        epdconfig.digital_write(self.dc_pin, 1)
    +        epdconfig.digital_write(self.cs_pin, 0)
    +        epdconfig.spi_writebyte(datas) 
    +        epdconfig.digital_write(self.cs_pin, 1)
    +
    +    def send_datas(self, datas):
    +        if len(datas) > self.SPIMaxDatas:
    +            self._send_large_datas(datas)
    +        else:
    +            self._send_datas(datas)
    
    修改Clear() 与 display() 中有关 send_data 的代码,改为 append 到数组
    @@ -153,6 +169,7 @@ class EPD:
     
         def display(self, image):
             self.send_command(0x10)
    +        senddatas = []
             for i in range(0, int(self.width / 4 * self.height)):
                 temp1 = image[i]
                 j = 0
    @@ -173,18 +190,16 @@ class EPD:
                     else:
                         temp2 |= 0x04
                     temp1 = (temp1 << 2) & 0xFF
    -                self.send_data(temp2)
    +                senddatas.append(temp2)
                     j += 1
    -                
    +        self.send_datas(senddatas)
             self.send_command(0x12)
             epdconfig.delay_ms(100)
             self.ReadBusy()
             
         def Clear(self):
             self.send_command(0x10)
    -        for i in range(0, int(self.width / 4 * self.height)):
    -            for j in range(0, 4):
    -                self.send_data(0x33)
    +        self.send_datas([0x33] * int(self.width / 4 * self.height) * 4)
             self.send_command(0x12)
             self.ReadBusy()
    
测试结果
  • epd5in83_old 为 git clone的版本, epd5in83 为修改版

epd_5in83_test_old.py中仅将epd5in83修改为epd5in83_old

[root@rpi examples]# time python epd_5in83_test.py 
INFO:root:epd5in83 Demo
INFO:root:init and Clear
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
INFO:root:1.Drawing on the Horizontal image...
DEBUG:root:imwidth = 600  imheight =  448 
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
INFO:root:2.Drawing on the Vertical image...
DEBUG:root:imwidth = 448  imheight =  600 
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
INFO:root:3.read bmp file
DEBUG:root:imwidth = 600  imheight =  448 
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
INFO:root:4.read bmp file on window
DEBUG:root:imwidth = 448  imheight =  600 
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
INFO:root:Clear...
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
INFO:root:Goto Sleep...
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
DEBUG:root:spi end
DEBUG:root:close 5V, Module enters 0 power consumption ...

real	2m2.305s
user	1m11.051s
sys	0m0.360s
[root@rpi examples]# time python epd_5in83_test_old.py 
INFO:root:epd5in83 Demo
INFO:root:init and Clear
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
INFO:root:1.Drawing on the Horizontal image...
DEBUG:root:imwidth = 600  imheight =  448 
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
INFO:root:2.Drawing on the Vertical image...
DEBUG:root:imwidth = 448  imheight =  600 
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
INFO:root:3.read bmp file
DEBUG:root:imwidth = 600  imheight =  448 
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
INFO:root:4.read bmp file on window
DEBUG:root:imwidth = 448  imheight =  600 
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
INFO:root:Clear...
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
INFO:root:Goto Sleep...
DEBUG:root:e-Paper busy
DEBUG:root:e-Paper busy release
DEBUG:root:spi end
DEBUG:root:close 5V, Module enters 0 power consumption ...

real	6m31.419s
user	3m38.717s
sys	1m13.439s

或许可以考虑一下提升getbuffer的性能

BoringCat avatar Feb 02 '20 10:02 BoringCat

加上 display() 和 getbuffer() 的性能优化方案

  • 屏幕:5.83inch e-Paper HAT
    def display(self, image):
        imwidth, imheight = image.size
        image_monocolor = image.convert('1')
        logging.debug('imwidth = %d  imheight =  %d ',imwidth, imheight)
        if(imwidth == self.width and imheight == self.height):
            pixels = image_monocolor.getdata()
        elif(imwidth == self.height and imheight == self.width):
            pixels = image_monocolor.rotate(90, expand=True).getdata()
        else:
            pixels = image_monocolor.resize((self.width,self.height)).getdata()
        buf = [ (pixels[i]>>6<<4) + (pixels[i+1]>>6) for i in range(0, len(pixels), 2)]
        self.send_command(0x10)
        self.send_datas(buf)
        self.send_command(0x12)
        epdconfig.delay_ms(100)
        self.ReadBusy()

BoringCat avatar Feb 02 '20 15:02 BoringCat

这个是很好的点子,等疫情过去,我到公司测试一遍

hnwangkg-ezio avatar Feb 03 '20 02:02 hnwangkg-ezio

ReadBusy 耗时是由硬件决定的吗?

CodeGueas avatar Apr 27 '21 17:04 CodeGueas