마음 속 하늘은 항상 맑음~!

전자잉크를 업데이트 번쩍임 없애기 본문

카테고리 없음

전자잉크를 업데이트 번쩍임 없애기

파르셀수스 2025. 12. 21. 10:50

 Waveshare의 1.54인치 디스플레이를 사용하여 업데이트 하는 전자잉크는 화면이 업데이트 될 때 마다 번쩍번쩍 하는 효과가 나타난다. 이를 없앨려면 부분 리프레시(Partial Refresh)라는 디스플레이 모드2를 사용하는데 이게 제대로된 설명을 찾을 수 없었다.

 

1. 디스플레이 프레임 버퍼는 2개였다.

 디스플레이를 테스트 하는 중에 부분 리프레시를 위해 화면을 업데이트하는 명령을 보내면 2번마다 반복되는 화면을 얻었다. display_part_frame()을 사용하면 부분 리프레시를 수행하는데 2개의 디스플레이 프레임 반복하면서 2개의 프레임 메모리를 화면에 보여주었다.

 

2. 부분 리프레시 초기화에서는 전체 리프레시를 하고 부분 리프레시로 초기화를 해야한다.

 부분 리프레시를 하기 위해 초기화를 할 때, display_frame()을 호출해서 전체 리프레시를 하면 잘 안되었던 것 같다. 그리고 초기화에서 다른 중요한 점은 초기화 중에는 먼저 전체 리프레시를 하고 다음에 부분 리프레시로 초기화를 해야한다.

 그리고 초기화 후에는 2개의 프레임 버퍼를 초기화해야 하는데 display_part_base_white_image()라는 것을 사용한다. 프레임이 2개이기 때문에 한번만 하는게 아니라 2번을 해야 2개의 프레임 메모리가 모두 초기화 업데이트가 된다.

 

3. 이렇게 초기화가 끝나면 지금 현재의 프레임 메모리에 데이터를 보내고 모두 보내고 난 후에는 display_part_frame()으로 업데이트를 한다. 그러면 화면 번쩍임 없이 미세한 밝기가 변하면서 화면이 깜박이지 않고 조용히 업데이트 되는 것을 볼 수 있다.

 

4. 프레임 메모리 일부를 접근하도록 하면 마이크로 컨트롤러의 메모리를 절약할 수 있다.

 전자잉크의 프레임 메모리 크기가 마이크로컨트롤러에서 사용하기에는 큰 편이다. 더 큰 크기의 전자잉크를 사용하면 더 많은 프레임 메모리 버퍼를 할당해서 그 메모리 내용을 전자잉크의 프레임 메모리로 전달해야 하는 문제가 있는데 이러한 문제를 미리 해결하기 위해 준비가 되어 있었다.

  set_frame_memory()라는 함수가 있는데 이는 프레임 버퍼의 내용을 전자잉크의 특정 위치에 폭과 높이로 쓰기 작업을 할 수 있데 해준다. 파이썬에서 framebuf를 작게 표시에 필요한 만큼만 할당을 하고 그 내용을 전자잉크의 프레임 메모리로 옮기는 것을 할 수 있게 해주는 함수다. 이 함수를 이용해서 마이크로 컨트롤러에서 필요한 만큼의 프레임 버퍼만을 사용해서 이미지 데이터를 만들고 그 데이터를 전자잉크의 프레임 메모리로 전달을 하면 된다.

 

 내용을 보면 부분 리프레시라는 개념이 모호한 방법론이지만 깜박이면서 화면이 업데이트 되는 것을 피하는 것을 할 수 있는 좋은 방법론이라고 생각한다. 그 깜박이는 동작을 피하는데 필요한게 부분 리프레시 기능이라고 생각하면 될 것 같다.

 그리고 부분 리프레시를 하는 동안에 전자잉크의 프레임 메모리의 내용은 지워지지 않으므로 프레임 버퍼의 메모리를 지우거나 하는 방법도 생각해야 한다.

 

from machine import Timer, Pin, SPI
import micropython, re, time, network, random, uos

import epd1n54v2
import framebuf

# 초기화
if uos.uname().machine.find("C3")>-1:
    spi=SPI(1)
    spi.init(sck=Pin(4),mosi=Pin(6),miso=None)
    e = epd1n54v2.EPD(spi, cs=Pin(20), dc=Pin(3), rst=Pin(2), busy=Pin(1))
    e.init()
else:
    spi=SPI(2, sck=Pin(18), mosi=Pin(23))
    spi.init()
    e = epd1n54v2.EPD(spi, cs=Pin(14), dc=Pin(12), rst=Pin(13), busy=Pin(4))
    e.init()

# 프레임 버퍼를 할당하고 framebuf로 활용
dispbuf=bytearray(e.width // 8 * e.height)
disp=framebuf.FrameBuffer(dispbuf, e.width, e.height, framebuf.MONO_HLSB)

# 전자잉크 프레임 전체를 지우기
disp.fill(1)
# 전자잉크의 프레임 메모리가 2페이지라서 2번 호출
e.display_part_base_image(dispbuf)
e.display_part_base_image(dispbuf)

# 1개의 문자를 출력.
def drawtxt(x,y):
    data=bytearray(8)
    fimg=framebuf.FrameBuffer(data,8,8,framebuf.MONO_HLSB)
    fimg.fill(1)
    fimg.text('A',0,0,0)
    e.set_frame_memory(data,x,y,8,8)
    data=[]
    fimg=None

x=1
def doit():
    # draw image
    global x
    drawtxt(100+x*8,100)
    e.display_part_frame()
    x=x+1

# 부분 리프레시 모드로 전환
e.init(True)

# 전자잉크의 서로 다른 프레임에 문자가 번갈아가면서 찍히고 보여진다.
doit()