Other

技术解读

以下内容由 GitRead 中文社区 编辑团队基于项目 README 与官方资料整理, 结合中文开发者的常见使用场景补充技术选型建议。具体以项目官方文档为准。

让 MicroPython 把屏幕刷新速度提升约十倍:s3lcd 技术剖析

项目背景与痛点

在 ESP32-S3 上使用 MicroPython 驱动 ST7789 这类 SPI 屏幕,过去通常有两种做法:一种是纯 Python 的 machine.SPI 驱动,另一种是像 st7789_mpy 那样自行编写命令序列的 C 模块。

这两种做法都有明显问题。纯 Python 方案在每次写像素时都要切换 DC 引脚,并反复调用 SPI.write();Python 层的循环、切片和 bytearray 拼接会耗尽 CPU,导致 240×240 的全屏填充要几十毫秒甚至上百毫秒,刷新过程中主循环基本被阻塞,LVGL 之类的上层框架也就无法运行流畅。

st7789_mpy 虽然把最关键的处理路径转移到了 C 语言层,但它仍然自己管理 SPI 时序、初始化序列和 MADCTL 寄存器,本质上是在重新实现 IDF 已经实现过的功能。ESP32-S3 本身具备 SPI DMA、esp_lcd 抽象层,而 IDF 官方已经内置了 ST7789 面板驱动;开发者真正缺的是一个把 MicroPython 对象模型接到 esp_lcd 上的轻量适配层。

s3lcd 正是这一适配层。它不发明新 API,而是把底层依赖整体替换为 esp_lcd。

核心技术揭秘

s3lcd 的架构可以概括为“薄 Python、厚 C、靠 IDF”。它分为三层:高层绘图 API(字体、图形、JPEG/位图解码)几乎原样沿用 st7789_mpy 的实现;中间是 s3lcd 自己的 C 模块,负责 mp_obj_t 与 esp_lcd 句柄之间的转换和生命周期管理;底层完全交给 esp_lcd_panel_io_spi 与 esp_lcd_new_panel_st7789。

graph TD A[用户 Python 代码<br/>tft.fill, tft.text, tft.jpg] --> B[高层绘图层<br/>字体渲染, 图形, JPEG 解码] B --> C[s3lcd C 模块<br/>mp_obj 与参数转换] C --> D{"操作类型?"} D -->|"命令与寄存器配置"| E[esp_lcd_panel_io_tx_param] D -->|"像素数据流"| F[esp_lcd_panel_draw_bitmap] E --> G[esp_lcd SPI 总线层<br/>DC 线由驱动内部翻转] F --> G G --> H[SPI DMA 通道<br/>RGB565 字节序处理] H --> I[ST7789 控制器] I --> J[液晶面板] F --> K[DMA 完成回调<br/>信号量, 异步等待] K --> L[Python 主循环继续执行]

这张图里有两个关键设计。

第一,DC 线不再出现在 Python 侧。esp_lcd_panel_io_spi 在发送命令时自动拉低 DC,发送数据时自动拉高,Python 层再也无需为每条命令额外做一次 GPIO 操作。看起来只是节省了几微秒,但在每帧数百次调用时,减少的开销非常可观。

第二,DMA 与队列深度。esp_lcd 的 SPI IO 支持 trans_queue_depth 大于 1 的传输队列,draw_bitmap 返回时,DMA 可能仍在搬运数据,完成回调中释放信号量。s3lcd 在此之上提供了显式的等待/刷新语义:需要撕裂控制就阻塞,需要流畅度就异步。这比“写完就返回、不知道数据到底上屏没有”的粗糙实现可靠得多。

最容易出问题的环节是内存。DMA 描述符与传输缓冲区必须落在内部 RAM 且满足对齐要求,而开启了 PSRAM 的 ESP32-S3 上,MicroPython 分配的 bytearray 很可能被放进 PSRAM,直接传给 draw_bitmap 就会出现静默失败或总线错误。s3lcd 必须显式处理缓冲区来源,这也是它比纯 Python 驱动更难写好、但在生产环境更稳的原因。

功能亮点与差异

API 向下兼容是最有价值的特性。 tft.init()、tft.text()、tft.jpg()、tft.bitmap() 的签名与资源格式保持一致,既有项目几乎只需重编固件、改一行 import,就能获得 DMA 带来的性能提升。

复用 IDF 生态。 初始化序列、色彩格式、镜像与偏移由 esp_lcd 的面板驱动统一管理,不必手写 MADCTL、COLMOD 等寄存器魔数;后续要迁移到 GC9A01、ILI9341 等兼容面板,或转向 RGB 并口、lcd_cam,底层路径也是通的。

与 LVGL 生态的衔接。 在 lvgl_micropython 体系中,s3lcd 可以作为显示后端之一;由于刷屏走 DMA,LVGL 的渲染循环不再被 SPI 传输完全卡住,帧率表现明显优于纯 Python 驱动。

应用场景与落地建议

它适合带 SPI 屏的 ESP32-S3 产品:智能家居面板、仪表盘、可穿戴设备、相机取景预览、LVGL 图形界面,尤其是画面尺寸在 240×240 到 320×240、且对刷新率有要求的场景。

落地时有几点必须注意。版本要锁定:esp_lcd 的 ST7789 组件在 IDF 5.x 才相对独立,而 s3lcd 又必须与特定 MicroPython 版本匹配,随意升级容易编译失败。缓冲区要分层:全屏帧缓冲(320×240×2 ≈ 150KB)应放在 PSRAM,但 DMA 传输缓冲必须小块、内部 RAM、对齐分配。不要与 machine.SPI 混用同一总线,以免总线被重复初始化。背光用 machine.PWM 单独控制,注意上电时序。做大面积刷新时,尽量采用“双缓冲 + 局部区域”策略,而不整屏 fill,这样配合 DMA 才能把撕裂降到可接受范围。

综合评价

优点:把 esp_lcd 的 DMA 能力完整引入 MicroPython,性能与纯 Python 驱动相比提升约一个数量级;API 与 st7789_mpy 对齐,迁移成本极低;依赖 IDF 官方面板驱动,长期维护性优于自行手写寄存器的方案。

缺点:强耦合 IDF 与 MicroPython 版本,需要自行编译固件,对只想“pip 装个库”的开发者门槛偏高;仓库文档与示例相对精简,很多配置细节要靠读源码;PSRAM、DMA 缓冲区、多总线共享等内存与时序问题属于隐性成本,一旦出错表现往往是黑屏而没有任何提示,调试不友好。

一句话总结:它不是“又一个屏幕驱动”,而是 MicroPython 与 ESP-IDF 图形栈之间缺失的那块转接层;如果你正在 ESP32-S3 上做有性能要求的显示项目,这条路值得走,但要准备好为此负责编译与调优。

关于

GitHub 原始描述(英文)

ESP_LCD based MicroPython driver for ESP32-S3 Devices with ST7789 or compatible displays.

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

语言占比

C
CMake
Python

README

ESP_LCD MicroPython driver for ESP32-S3 Devices with ST7789 or compatible displays.

Warning: This work in progress may contain bugs or incorrect documentation.

Overview

This is a driver for MicroPython for devices using the esp_lcd intel 8080 8-bit parallel bus and SPI interfaces. The driver is written in C and is based on devbis’ st7789_mpy driver.

I modified the original driver to add the following features:

  • Support for esp-idf ESP_LCD intel 8080 parallel and SPI interfaces using DMA.
  • Display framebuffer enabling alpha blending for many drawing methods.
  • Display Rotation.
  • Hardware Scrolling.
  • Writing text using fonts converted from True Type fonts.
  • Drawing text using eight and 16-bit wide bitmap fonts, including 12 bitmap fonts derived from classic pc text mode fonts.
  • Drawing text using 26 included Hershey vector fonts.
  • Drawing JPGs using the TJpgDec - Tiny JPEG Decompressor R0.01d. from http://elm-chan.org/fsw/tjpgd/00index.html.
  • Drawing PNGs using the pngle library from https://github.com/kikuchan/pngle.
  • Writing PNGs from the framebuffer using the PNGenc library from https://github.com/bitbank2/PNGenc
  • Drawing and rotating Polygons and filled Polygons.
  • Several example programs. The example programs require a tft_config.py module to be present. Some examples require a tft_buttons.py module as well. You may need to modify the tft_buttons.py module to match the pins your device uses.
  • tft_config.py and tft_buttons.py configuration examples are provided for:
    • ESP32S3-BOX and BOX-Lite
    • LilyGo T-Display-S3
    • LilyGo T-Dongle-S3
    • LilyGo T-Embed
    • LilyGo T-HMI
    • LilyGo T-QT Pro
    • Seeed Studio WT32-SC01 Plus
    • M5STACK ATOM-S3
    • M5STACK CORES3
    • BananaPi BPI-Centi-S3

Pre-compiled firmware

The firmware directory contains pre-compiled MicroPython v1.20.0 firmware compiled using ESP IDF v4.4.4. In addition, the firmware includes the C driver and several frozen Python font files. See the README.md file in the fonts folder for more information about the font files.

Driver API

Note: Curly braces { and } enclose optional parameters and do not imply a Python dictionary.

I80_BUS Methods

  • s3lcd.I80_BUS(data, dc, wr, {rd, cs, pclk, bus_width, lcd_cmd_bits, lcd_param_bits, dc_idle_level, dc_cmd_level, dc_dummy_level, dc_data_level, cs_active_high, reverse_color_bits, swap_color_bytes, pclk_active_neg, pclk_idle_low})

    This method sets the interface configuration of an intel 8080 parallel bus for the ESPLCD driver. The ESPLCD driver will automatically initialize and deinitialize the I80 bus.

    Required Parameters:

    • data tuple of pin numbers attached to the data bus in least to most significant bit order
    • dc data/command pin number
    • wr write pin number

    Optional Parameters:

    • rd read pin number
    • cs chip select pin number
    • pclk pixel clock frequency in Hz
    • bus_width bus width in bits
    • lcd_cmd_bits number of bits used to send commands to the LCD
    • lcd_param_bits number of bits used to send parameters to the LCD
    • dc_idle_level D/C pin level when idle
    • dc_cmd_level D/C pin level when sending commands
    • dc_dummy_level D/C pin level when sending dummy data
    • dc_data_level D/C pin level when sending data
    • cs_active_high CS pin level when active
    • reverse_color_bits reverse the order of color bits
    • swap_color_bytes swap the order of color bytes
    • pclk_active_neg pixel clock is active negative
    • pclk_idle_low pixel clock is idle low

SPI_BUS Methods

  • s3lcd.SPI_BUS(spi_host, sck, mosi, dc, {cs, spi_mode, pclk, lcd_cmd_bits, lcd_param_bits, dc_idle_level, dc_as_cmd_phase, dc_low_on_data, octal_mode, lsb_first, swap_color_bytes})

    This method sets the interface configuration of an SPI bus for the ESPLCD driver. The ESPLCD driver will automatically initialize and deinitialize the SPI bus.

    Required Parameters:

    • spi_host SPI host to use.
    • sck sck pin number
    • mosi MOSI pin number
    • dc D/C pin number

    Optional Parameters:

    • cs CS pin number
    • spi_mode Traditional SPI mode (0~3)
    • pclk Frequency of pixel clock
    • lcd_cmd_bits Bit-width of LCD command
    • lcd_param_bits Bit-width of LCD parameter
    • dc_idle_level D/C pin level when idle
    • dc_as_cmd_phase D/C line value is encoded into SPI transaction command phase
    • dc_low_on_data If this flag is enabled, D/C line = 0 means transfer data, D/C line = 1 means transfer command
    • octal_mode transmit using octal mode (8 data lines)
    • lsb_first transmit LSB bit first
    • swap_color_bytes (bool) Swap data byte order

ESPLCD Methods

  • s3lcd.ESPLCD(bus, width, height, {reset, rotations, rotation, inversion, dma_rows, options})

    Required positional arguments:

    • bus I80_BUS or SPI_BUS object
    • width display width
    • height display height

    Optional keyword arguments:

    • reset reset pin number

    • rotations Creates a custom rotation table. A rotation table is a list of tuples for each rotation containing the width, height, x_gap, y_gap, swap_xy, mirror_x, and mirror_y values for each rotation.

      Default rotations are included for the following display sizes:

      Display Default Orientation Tables
      320x480 ((320, 480, 0, 0, false, true, false), (480, 320, 0, 0, true, false, false), (320, 480, 0, 0, false, false, true), (480, 320, 0, 0, true, true, true))
      240x320 ((240, 320, 0, 0, false, false, false), (320, 240, 0, 0, true, true, false), (240, 320, 0, 0, false, true, true), (320, 240, 0, 0, true, false, true))
      170x320 ((170, 320, 35, 0, false, false, false), (320, 170, 0, 35, true, true, false), (170, 320, 35, 0, false, true, true), (320, 170, 0, 35, true, false, true))
      240x240 ((240, 240, 0, 0, false, false, false), (240, 240, 0, 0, true, true, false), (240, 240, 0, 80, false, true, true), (240, 240, 80, 0, true, false, true))
      135x240 ((135, 240, 52, 40, false, false, false), (240, 135, 40, 53, true, true, false), (135, 240, 53, 40, false, true, true), (240, 135, 40, 52, true, false, true))
      128x160 ((128, 160, 0, 0, false, false, false), (160, 128, 0, 0, true, true, false), (128, 160, 0, 0, false, true, true), (160, 128, 0, 0, true, false, true))
      80x160 ((80, 160, 26, 1, false, false, false), (160, 80, 1, 26, true, true, false), (80, 160, 26, 1, false, true, true), (160, 80, 1, 26, true, false, true))
      128x128 ((128, 128, 2, 1, false, false, false), (128, 128, 1, 2, true, true, false), (128, 128, 2, 3, false, true, true), (128, 128, 3, 2, true, false, true))

      You may define up to 4 rotations.

    • rotation sets the active display rotation according to the orientation table.

      The default orientation table defines four counterclockwise rotations for 240x320, 240x240, 134x240, 128x160, 80x160, and 128x128 displays with the LCD’s ribbon cable at the bottom of the display. The default rotation is Portrait (0 degrees).

      Index Rotation
      0 Portrait (0 degrees)
      1 Landscape (90 degrees)
      2 Reverse Portrait (180 degrees)
      3 Reverse Landscape (270 degrees)
    • inversion Sets the display color inversion mode if True and clears the color inversion mode if false.

    • dma_rows Sets the number of the framebuffer rows to transfer to the display in a single DMA transaction. The default value is 16 rows. Larger values may perform better but use more DMA-capable memory from the ESP-IDF heap. On the other hand, using a large value may starve other ESP-IDF functions like WiFi of memory.

    • options Sets driver option flags.

      Option Description
      s3lcd.WRAP pixels, lines, polygons, and Hershey text will wrap around the display both horizontally and vertically.
      s3lcd.WRAP_H pixels, lines, polygons, and Hershey text will wrap around the display horizontally.
      s3lcd.WRAP_V pixels, lines, polygons, and Hershey text will wrap around the display vertically.
  • deinit()

    Frees the buffer memory and deinitializes the I80_BUF or SPI_BUF object. Call this method before reinitializing the display without performing a hard reset.

  • idle_mode(value)

    Set idle mode

    value: True to enable idle mode, False to idle disable idle mode.

  • show()

    Update the display from the framebuffer. You must use the show() method to transfer the framebuffer to the display. This method blocks until the display refresh is complete.

  • inversion_mode(bool) Sets the display color inversion mode if True, clears the display color inversion mode if False.

  • init()

    Must be called to initialize the display.

  • clear({ 8_bit_color})

    Fast clear the framebuffer by setting the high and low bytes of the color to the specified value.

    Optional parameters: – 8_bit_color defaults to 0x00 BLACK

  • fill({color, alpha})

    Fill the framebuffer with the specified color, optionally alpha blended with the background. The color defaults to BLACK, and the alpha defaults to 255.

  • pixel(x, y {, color, alpha})

    Set the specified pixel to the given color. The color defaults to WHITE, and the alpha defaults to 255.

  • line(x0, y0, x1, y1 {, color, alpha})

    Draws a single line with the provided color from (x0, y0) to (x1, y1). The color defaults to BLACK, and the alpha defaults to 255.

  • hline(x, y, w {, color, alpha})

    Draws a horizontal line with the provided color and length in pixels. The color defaults to BLACK, and the alpha defaults to 255.

  • vline(x, y, length {, color, alpha})

    Draws a vertical line with the provided color and length in pixels. The color defaults to BLACK, and the alpha defaults to 255.

  • rect(x, y, width, height {, color, alpha})

    Draws a rectangle with the specified dimensions from (x, y'). The colordefaults to BLACK, and thealpha` defaults to 255.

  • fill_rect(x, y, width, height {, color, alpha})

    Fills a rectangle width by height starting at x, y' with coloroptionallyalphablended with the background. Thecolordefaults to BLACK, andalpha` defaults to 255.

  • circle(x, y, r {, color, alpha})

    Draws a circle with radius r centered at the (x, y') coordinates in the given color. The colordefaults to BLACK, and thealpha` defaults to 255.

  • fill_circle(x, y, r {, color, alpha})

    Draws a filled circle with radius r centered at the (x, y') coordinates in the given color. The colordefaults to BLACK, and thealpha` defaults to 255.

  • blit_buffer(buffer, x, y, width, height {, alpha})

    Copy bytes() or bytearray() content to the framebuffer. Note: every color requires 2 bytes in the array, the alpha defaults to 255.

  • text(font, s, x, y {, fg, bg, alpha})

    Writes text to the framebuffer using the specified bitmap font with the coordinates as the upper-left corner of the text. The optional arguments fg and bg can set the foreground and background colors of the text; otherwise, the foreground color defaults to WHITE, and the background color defaults to BLACK. alpha defaults to 255. See the README.md in the fonts/bitmap directory, for example fonts.

  • write(bitmap_font, s, x, y {, fg, bg, alpha})

    Writes text to the framebuffer using the specified proportional or Monospace bitmap font module starting with the coordinates as the upper-left corner of the text. The foreground and background colors of the text are set by the optional arguments fg and bg; otherwise, the foreground color defaults to WHITE, and the background color defaults to BLACK. The alpha defaults to 255.

    See the README.md in the truetype/fonts directory, for example fonts. Returns the width of the string as printed in pixels. This method accepts UTF8 encoded strings.

    The font2bitmap utility creates compatible 1-bit per pixel bitmap modules from Proportional or Monospaced True Type fonts. The character size, foreground, background colors, and characters in the bitmap module may be specified as parameters. Use the -h option for details.

  • write_len(bitap_font, s)

    Returns the string’s width in pixels if printed in the specified font.

  • draw(vector_font, s, x, y {, fg, scale, alpha})

    Draws text to the framebuffer using the specified Hershey vector font with the coordinates as the lower-left corner of the text. The foreground color of the text can be set by the optional argument fg. Otherwise, the foreground color defaults to WHITE. The size of the text is modified by specifying a scale value. The scale value must be larger than 0 and can be a floating-point or an integer value. The scale value defaults to 1.0. The alpha defaults to 255. See the README.md in the vector/fonts directory, for example fonts and the utils directory for a font conversion program.

  • draw_len(vector_font, s {, scale})

    Returns the string’s width in pixels if drawn with the specified font.

  • jpg(jpg, x, y)

    Draws a JPG file in the framebuffer at the given x and `y’ coordinates as the upper left corner of the image. This method requires an additional 3100 bytes of memory for its work buffer. The jpg may be a filename or a bytes() or bytearray() object. The jpg will wil be clipped if is not able to fit fully in the framebuffer.

  • jpg_decode(jpg_filename {, x, y, width, height})

    Decodes a jpg file and returns it or a portion of it as a tuple composed of (buffer, width, height). The buffer is a color565 blit_buffer compatible byte array. The buffer will require width * height * 2 bytes of memory.

    If the optional x, y, width, and height parameters are given, the buffer will only contain the specified area of the image. See examples/T-DISPLAY/clock/clock.py and examples/T-DISPLAY/toasters_jpg/toasters_jpg.py for examples.

  • png(png, x, y)

    Draws a PNG file in the framebuffer with the upper left corner of the image at the given x and `y’ coordinates. The png may be a filename or a bytes() or bytearray() object. The png will wil be clipped if it is not able to fit fully in the framebuffer. Transparency is supported; see the alien.py program in the examples/png folder.

  • png_write(file_name{ x, y, width, height})

    Writes the framebuffer to a png file named file_name using PNGenc from https://github.com/bitbank2/PNGenc.

    optional parameters:
    • x: the first column of the framebuffer to start writing.
    • y: the first row of the framebuffer to start writing.
    • width: the width of the area to write
    • height: the height of the area to write

    Returns file size in bytes.

  • polygon_center(polygon)

    Returns the center of the polygon as an (x, y) tuple. The polygon should consist of a list of (x, y) tuples forming a closed convex polygon.

  • fill_polygon(polygon, x, y, color {, alpha, angle, center_x, center_y})

    Draws a filled polygon at the x, and y' coordinates in the colorgiven. Thealphadefaults to 255. The polygon may be rotatedangleradians about thecenter_xandcenter_y` points. The polygon should consist of a list of (x, y) tuples forming a closed convex polygon.

    See the TWATCH-2020 watch.py demo for an example.

  • polygon(polygon, x, y, color {, alpha, angle, center_x, center_y)

    Draws a polygon at the x, and y' coordinates in the colorgiven. Thealphadefaults to 255. The polygon may be rotatedangleradians about thecenter_xandcenter_y` points. The polygon should consist of a list of (x, y) tuples forming a closed convex polygon.

    See the roids.py for an example.

  • bitmap(bitmap, x , y {, alpha, index}) or bitmap((bitmap_as_bytes, w, h), x , y {, alpha})

    Draws a bitmap using the specified x, y' coordinates as the upper-left corner of the bitmap`.

    • If the bitmap parameter is a bitmap module, the index parameter may be specified to select a specific bitmap from the module. The index parameter must be an integer value greater than or equal to 0 and less than the number of bitmaps in the module. The index value defaults to 0. 8-bit per pixel.

    • If the bitmap_module parameter is a tuple, the tuple must contain a bitmap as a byte array, the width of the bitmap in pixels, and the height of the bitmap in pixels. alpha defaults to 255.

    Using the Pillow Python Imaging Library, the imgtobitmap.py utility creates compatible 1 to 8-bit per-pixel bitmap modules from image files.

    The monofont2bitmap.py utility creates compatible 1 to 8-bit per-pixel bitmap modules from Monospaced True Type fonts. See the inconsolata_16.py, inconsolata_32.py and inconsolata_64.py files in the examples/mono_fonts folder for sample modules and the mono_font.py program for an example using the generated modules.

    You can specify the character sizes, foreground and background colors, bit per pixel, and characters to include in the bitmap module as parameters. To learn more, use the -h option. Using bit-per-pixel settings larger than one can create antialiased characters at the cost of increased memory usage.

  • width()

    Returns the current width of the display in pixels. (i.e., a 135x240 display rotated 90 degrees is 240 pixels wide)

  • height()

    Returns the current height of the display in pixels. (i.e., a 135x240 display rotated 90 degrees is 135 pixels high)

  • rotation(r)

    Sets the rotation of the logical display in a counterclockwise direction. 0-Portrait (0 degrees), 1-Landscape (90 degrees), 2-Inverse Portrait (180 degrees), 3-Inverse Landscape (270 degrees)

  • scroll(xstep, ystep{, fill=0})

    Scrolls the framebuffer using software in the given direction.

    Required parameters:

    • xstep: Number of pixels to scroll in the x direction. Negative values scroll left, positive values scroll right.
    • ystep: Number of pixels to scroll in the y direction. Negative values scroll up, positive values scroll down.

    Optional parameters:

    • fill: Fill color for the new pixels.

The module exposes predefined colors: BLACK, BLUE, RED, GREEN, CYAN, MAGENTA, YELLOW, and WHITE

Hardware Scrolling

The st7789 display controller contains a 240 by 320-pixel frame buffer used to store the pixels for the display. For scrolling, the frame buffer consists of three separate areas: The (tfa) top fixed area, the (height) scrolling area, and the (bfa) bottom fixed area. The tfa is the upper portion of the frame buffer in pixels not to scroll. The height is the center portion of the frame buffer in pixels to scroll. The bfa is the lower portion of the frame buffer in pixels not to scroll. These values control the ability to scroll the entire or a part of the display.

For displays that are 320 pixels high, setting the tfa to 0, height to 320, and bfa to 0 will allow scrolling of the entire display. To scroll a portion of the display, you can set the tfa and bfa to a non-zero value. tfa + height + bfa = should equal 320; otherwise, the scrolling mode is undefined.

Displays less than 320 pixels high, the tfa, height, and bfa must be adjusted to compensate for the smaller LCD panel. The actual values will vary depending on the configuration of the LCD panel. For example, scrolling the entire 135x240 TTGO T-Display requires a tfa value of 40, height value of 240, and bfa value of 40 (40+240+40=320) because the T-Display LCD shows 240 rows starting at the 40th row of the frame buffer, leaving the last 40 rows of the frame buffer undisplayed.

Other displays, like the Waveshare Pico LCD 1.3-inch 240x240 display, require the tfa set to 0, height set to 240, and bfa set to 80 (0+240+80=320) to scroll the entire display. The Pico LCD 1.3 shows 240 rows starting at the 0th row of the frame buffer, leaving the last 80 rows undisplayed.

The vscsad method sets the (VSSA) Vertical Scroll Start Address. The VSSA sets the line in the frame buffer that will be the first line after the tfa.

The ST7789 datasheet warns:

The value of the vertical scrolling start address is absolute (with referenceto the frame memory), it must not enter the fixed area defined by Vertical Scrolling Definition, otherwise undesirable image will be displayed on the panel.
  • vscrdef(tfa, height, bfa) Set the vertical scrolling parameters.

    tfa is the top fixed area in pixels. The top fixed area is the upper portion of the display frame buffer that will not be scrolled.

    height is the total height in pixels of the area scrolled.

    bfa is the bottom fixed area in pixels. The bottom fixed area is the lower portion of the display frame buffer that will not be scrolled.

  • vscsad(vssa) Set the vertical scroll address.

    vssa is the vertical scroll start address in pixels. The vertical scroll start address is the line in the frame buffer that will be the first line shown after the TFA.

Helper functions

  • color565(r, g, b)

    Pack a color into 2-byte rgb565 format

  • map_bitarray_to_rgb565(bitarray, buffer, width {, color, bg_color})

    Convert a bitarray to the rgb565 color buffer suitable for blitting. Bit 1 in bitarray is a pixel with color and 0 - with bg_color.

Building the firmware

See the MicroPython Getting Started page for more detailed information on building the MicroPython firmware.

Clone the Repositories

git clone [email protected]:micropython/micropython.git
git clone https://github.com/russhughes/s3lcd.git

Compile the cross compiler if you haven’t already

make -C micropython/mpy-cross

ESP32 MicroPython 1.14 thru 1.19

Change to the ESP32 port directory

cd micropython/ports/esp32

Compile the module with specified USER_C_MODULES dir

make USER_C_MODULES=../../../../s3lcd/src/micropython.cmake clean submodules all

Erase the target device if this is the first time uploading this firmware

make USER_C_MODULES=../../../../s3lcd/src/micropython.cmake erase

Upload the new firmware

make USER_C_MODULES=../../../../s3lcd/src/micropython.cmake deploy

ESP32 MicroPython 1.20 and later

Change to the ESP32 port directory, and build the firmware

cd micropython/ports/esp32

make \
    BOARD=ESP32_GENERIC \
    BOARD_VARIANT=SPIRAM \
    USER_C_MODULES=../../../../s3lcd/src/micropython.cmake \
    FROZEN_MANIFEST=../../../../s3lcd/manifest.py \
    clean submodules all

Erase the flash and deploy on your device

make \
    BOARD=ESP32_GENERIC \
    BOARD_VARIANT=SPIRAM \
    USER_C_MODULES=../../../../s3lcd/src/micropython.cmake \
    FROZEN_MANIFEST=../../../../s3lcd/manifest.py \
    erase deploy

RP2040 MicroPython 1.20 and later

Change to the RP2 port directory, and build the firmware

cd micropython/ports/rp2
make \
    BOARD=RPI_PICO \
    FROZEN_MANIFEST=../../../../gc9a01c/manifest.py \
    USER_C_MODULES=../../../gc9a01c/src/micropython.cmake \
    clean submodules all

Flash the firmware.uf2 file from the build-${BOARD} directory to your device.

Thanks go out to:

– Russ

评论

暂无评论