这是luma.lcd.device模块中st7735的驱动函数,我将他扣了下来,下面来详细解读一番 2024-5-11
第一,初始化函数
class st7735(backlit_device, __framebuffer_mixin):
"""
Serial interface to a 262K color (6-6-6 RGB) ST7735 LCD display.
On creation, an initialization sequence is pumped to the display to properly
configure it. Further control commands can then be called to affect the
brightness and other settings.
:param serial_interface: the serial interface (usually a
:py:class:`luma.core.interface.serial.spi` instance) to delegate sending
data and commands through.
:param width: The number of pixels laid out horizontally.
:type width: int
:param height: The number of pixels laid out vertically.
:type height: int
:param rotate: An integer value of 0 (default), 1, 2 or 3 only, where 0 is
no rotation, 1 is rotate 90° clockwise, 2 is 180° rotation and 3
represents 270° rotation.
:type rotate: int
:param framebuffer: Framebuffering strategy, currently instances of
``diff_to_previous()`` or ``full_frame()`` are only supported.
:type framebuffer: luma.core.framebuffer.framebuffer
:param bgr: Set to ``True`` if device pixels are BGR order (rather than RGB).
:type bgr: bool
:param inverse: Set to ``True`` if device pixels are inversed.
:type inverse: bool
:param h_offset: Horizontal offset (in pixels) of screen to device memory
(default: 0).
:type h_offset: int
:param v_offset: Vertical offset (in pixels) of screen to device memory
(default: 0).
:type v_offset: int
.. versionadded:: 0.3.0
"""
def __init__(self, serial_interface=None, width=160, height=128, rotate=0,
framebuffer=None, h_offset=0, v_offset=0, bgr=False, inverse=False, **kwargs):
super(st7735, self).__init__(luma.lcd.const.st7735, serial_interface, **kwargs)
self.capabilities(width, height, rotate, mode="RGB")
self.init_framebuffer(framebuffer, 16)
if h_offset != 0 or v_offset != 0:
def offset(bbox):
left, top, right, bottom = bbox
return (left + h_offset, top + v_offset, right + h_offset, bottom + v_offset)
self.apply_offsets = offset
else:
self.apply_offsets = lambda bbox: bbox
# Supported modes
supported = (width, height) in [(160, 80), (160, 128), (128, 128)]
if not supported:
raise luma.core.error.DeviceDisplayModeError(
"Unsupported display mode: {0} x {1}".format(width, height))
# RGB or BGR order
order = 0x08 if bgr else 0x00
self.command(0x01) # reset
self.command(0x11) # sleep out & booster on
self.command(0xB1, 0x01, 0x2C, 0x2D) # frame rate control: normal mode
self.command(0xB2, 0x01, 0x2C, 0x2D) # frame rate control: idle mode
self.command(0xB3, 0x01, 0x2C, 0x2D, # frame rate control: partial mode dot inversion mode
0x01, 0x2C, 0x2D) # frame rate control: line inversion mode
self.command(0xB4, 0x07) # display inversion: none
self.command(0xC0, 0xA2, 0x02, 0x84) # power control 1: -4.6V auto mode
self.command(0xC1, 0xC5) # power control 2: VGH
self.command(0xC2, 0x0A, 0x00) # power control 3: OpAmp current small, boost freq
self.command(0xC3, 0x8A, 0x2A) # power control 4: BCLK/2, Opamp current small & Medium low
self.command(0xC4, 0x8A, 0xEE) # power control 5: partial mode/full-color
self.command(0xC5, 0x0E) # VCOM Control 1
self.command(0x36, 0x60 | order) # memory data access control
self.command(0x21 if inverse else 0x20) # display inversion on(0x21)/off(0x20)
self.command(0x3A, 0x06) # interface pixel format
self.command(0x13) # partial off (normal)
self.command(0xE0, # gamma adjustment (+ polarity)
0x0F, 0x1A, 0x0F, 0x18, 0x2F, 0x28, 0x20, 0x22,
0x1F, 0x1B, 0x23, 0x37, 0x00, 0x07, 0x02, 0x10)
self.command(0xE1, # gamma adjustment (- polarity)
0x0F, 0x1B, 0x0F, 0x17, 0x33, 0x2C, 0x29, 0x2E,
0x30, 0x30, 0x39, 0x3F, 0x00, 0x07, 0x03, 0x10)
self.clear()
self.show()
首先就是这个初始化函数,定义了通讯协议,屏幕长宽,rotate图像翻转,缓存区(这里是none,后面又自定的init_framebuffer),bgr(和rbg相对),反转,水平垂直偏移等参数,继承了来自luma.lcd.const.st7735的LCD控制器类型
再对 它进行验证,看是否适配这些功能,保障一下把(应该)
self.capabilities(width, height, rotate, mode="RGB")
init_framebuffer)是来自其父类**__framebuffer_mixin**的一个函数
这里初始化时传入的是none,因此使用的是diff_to_previous这个函数:
顾名思义,就是比较和前一帧中和当前的帧的差异,先将图像依次分割为传入的平方数的方块,这里是16,(默认为4),因此将原图分成4x4的小方块,相同的地方就不用改,不同的地方就改.
通过字符串指定帧缓冲区类型的做法已被弃用,建议用户改用full_frame()
或diff_to_previous()
类的实例作为参数。但是你仍然可以能用这种方法做,只是不建议,代码是前后兼容的,最后返回的是分块的PIL.Image.Image图像和Tuple[int, int, int, int]一个四元组,表示是哪个切片矩形需要改变,[左上角x坐标, 左上角y坐标, 右下角x坐标, 右下角y坐标],后面叫做image和bounding_box
if h_offset != 0 or v_offset != 0:
def offset(bbox):
left, top, right, bottom = bbox
return (left + h_offset, top + v_offset, right + h_offset, bottom + v_offset)
self.apply_offsets = offset
else:
self.apply_offsets = lambda bbox: bbox
就是偏移的函数,传入的h,v_offset不全为0的话,就要改变bounding_box的坐标,就是依次多加一个偏移量,但是我不知道示例代码为啥呀多加偏移量,可能是屏幕显示从(0,0)开始的话有物理的误差吗,不清楚hhh
接着就是支持的屏幕大小,只有3种前面说过了…
命令方面需要查看屏幕自带的数据手册,就是些屏幕开始必须要做的一些初始化操作,下文在详细讲解,最后…
第二,display函数
def display(self, image):
"""
Renders a 24-bit RGB image to the ST7735 LCD display. The 8-bit RGB
values are passed directly to the devices internal storage, but only
the 6 most-significant bits are used by the display.
:param image: The image to render.
:type image: PIL.Image.Image
"""
assert image.mode == self.mode
assert image.size == self.size
image = self.preprocess(image)
for image, bounding_box in self.framebuffer.redraw(image):
left, top, right, bottom = self.apply_offsets(bounding_box)
self.command(0x2A, left >> 8, left & 0xFF, (right - 1) >> 8, (right - 1) & 0xFF) # Set column addr
self.command(0x2B, top >> 8, top & 0xFF, (bottom - 1) >> 8, (bottom - 1) & 0xFF) # Set row addr
self.command(0x2C) # Memory write
self.data(list(image.tobytes()))
1.看rgb还是gbr,看size是否匹配,不然抛异常
2.图像预处理,我开始还在说为什么预处理中的角度要*-90,而不是80 70…这些,
hhh类的文档已经说清楚了 就只有0 1 2 3
"param rotate: An integer value of 0 (default), 1, 2 or 3 only, where 0 is no rotation, 1 is rotate 90° clockwise, 2 is 180° rotation and 3 represents 270° rotation."
- self.framebuffer.redraw(image)解包这个,得到发生变化的切片图片和它的位置坐标,用command来发送指令和数据进行内存读写
第三,对比度函数
def contrast(self, level):
"""
NOT SUPPORTED
:param level: Desired contrast level in the range of 0-255.
:type level: int
"""
assert 0 <= level <= 255
NOT SUPPORTED已经不支持了,只是判断level在不在[0,255]的范围内
第四,发送指令或者数据的函数
def command(self, cmd, *args):
"""
Sends a command and an (optional) sequence of arguments through to the
delegated serial interface. Note that the arguments are passed through
as data.
"""
self._serial_interface.command(cmd)
if len(args) > 0:
self._serial_interface.data(list(args))
如果只有一个参数就是发送指令,多个参数就是用list的方式发送16进制的数据,详情可以见数据手册
这里的_serial_interface是指上文的serial_interface(不知道为什么为什么不用self.command虽然也是调用的这个函数,但是他写这个的意义是啥啊,不懂哈哈哈),这里就是spi, spi继承的是bitbang,使用的是bitbang的commnd和data函数来发送数据
为什么不用self.command虽然也是调用的这个函数,但是他写这个的意义是啥啊,不懂哈哈哈),这里就是spi, spi继承的是bitbang,使用的是bitbang的commnd和data函数来发送数据
好了,大部分代码都讲解完了,包括了我的一些思考和不懂的内容,接下来是数据手册的相关方面,但在此之前,我来概括一下st7735屏幕的过程(施工中)