|
2 | 2 |
|
3 | 3 | logger = logging.getLogger(__name__) |
4 | 4 |
|
5 | | -# Waveshare ESP32-P4-WIFI6-Touch-LCD-4.3 — bring-up stage 1 (#307): |
6 | | -# ESP32-P4 + ESP32-C6 Wi-Fi co-processor over SDIO (handled by MicroPython's |
7 | | -# C6_WIFI board variant), 4.3" 480x800 MIPI-DSI panel (ST7701, 2 lanes), |
8 | | -# GT911 touch on I2C (SDA=7, SCL=8), ES8311/ES7210 audio, SD card, camera. |
| 5 | +if __debug__: logger.debug("waveshare_esp32_p4_wifi6_touch_lcd_4_3.py initialization") |
| 6 | +# Hardware initialization for the Waveshare ESP32-P4-WIFI6-Touch-LCD-4.3: |
| 7 | +# ESP32-P4 (RISC-V) with an ESP32-C6 Wi-Fi 6 / BLE co-processor over SDIO |
| 8 | +# (esp_hosted), 32 MB flash, 32 MB PSRAM, 4.3" 480x800 portrait IPS over |
| 9 | +# 2-lane MIPI-DSI (ST7701), GT911 capacitive touch, ES8311 codec + ES7210 |
| 10 | +# microphone ADC, TF card slot (4-bit SDIO), MIPI-CSI camera connector, |
| 11 | +# USB host port. |
9 | 12 | # |
10 | | -# The MIPI-DSI display needs a DSI bus in lvgl_micropython that is not |
11 | | -# wired up yet, so this stage registers no display: MicroPythonOS stops at |
12 | | -# init_rootscreen() and leaves the REPL usable for the Wi-Fi/boot work. |
13 | | -# Display, touch, audio follow in later stages. |
| 13 | +# Manufacturer's wiki: https://www.waveshare.com/wiki/ESP32-P4-WIFI6-Touch-LCD-4.3 |
| 14 | +# Pins, panel timings and the ST7701 register table come from Waveshare's |
| 15 | +# ESP-IDF BSP (waveshare/esp32_p4_wifi6_touch_lcd_4_3 1.0.1). |
| 16 | +# |
| 17 | +# The panel is used in its native portrait orientation (480 wide, 800 high): |
| 18 | +# the ST7701 cannot swap rows and columns for the video interface, and the |
| 19 | +# enclosure's cable/button placement suits portrait. |
| 20 | + |
| 21 | +import time |
| 22 | + |
| 23 | +import i2c |
| 24 | +import lcd_bus |
| 25 | +import lvgl as lv |
| 26 | +import machine |
| 27 | +import mpos.ui |
| 28 | +from drivers.display.st7701_dsi import ST7701_DSI |
| 29 | +import drivers.indev.gt911 as gt911 |
| 30 | +from mpos import InputManager |
| 31 | + |
| 32 | +LCD_WIDTH = 480 |
| 33 | +LCD_HEIGHT = 800 |
| 34 | +LCD_RST = 27 |
| 35 | +LCD_BL = 26 # backlight enable, PWM dimmable, ACTIVE LOW (the BSP drives its LEDC channel inverted) |
| 36 | + |
| 37 | +I2C_SDA = 7 |
| 38 | +I2C_SCL = 8 |
| 39 | +I2C_FREQ = 400000 |
| 40 | + |
| 41 | +TOUCH_ADDRS = (0x5D, 0x14) # GT911; the strap at reset picks one |
| 42 | + |
| 43 | +# === BACKLIGHT === |
| 44 | +# Kept off (pin high) until the panel shows its first frame, so the boot does |
| 45 | +# not flash a white screen. |
| 46 | +_backlight = machine.PWM(machine.Pin(LCD_BL), freq=5000, duty_u16=65535) |
| 47 | +_backlight_percent = 0 |
| 48 | + |
| 49 | + |
| 50 | +def _set_backlight(percent): |
| 51 | + global _backlight_percent |
| 52 | + percent = max(0, min(100, int(percent))) |
| 53 | + _backlight_percent = percent |
| 54 | + _backlight.duty_u16(65535 - percent * 65535 // 100) # active low: 0% = pin high |
| 55 | + |
| 56 | + |
| 57 | +def _get_backlight(): |
| 58 | + return _backlight_percent |
| 59 | + |
| 60 | + |
| 61 | +# === DISPLAY (ST7701 over MIPI-DSI) === |
| 62 | +# Video mode: the DPI DMA scans two screen-sized frame buffers (in PSRAM) out |
| 63 | +# to the panel continuously, LVGL renders straight into them. The DSI PHY is |
| 64 | +# powered by the P4's internal LDO channel 3. |
| 65 | +display_bus = lcd_bus.DSIBus( |
| 66 | + bus_id=0, |
| 67 | + data_lanes=2, |
| 68 | + freq=500, # lane bit rate, Mbps |
| 69 | + dpi_clock_freq=30, # DPI pixel clock, MHz |
| 70 | + virtual_channel=0, |
| 71 | + hsync_back_porch=42, |
| 72 | + hsync_pulse_width=12, |
| 73 | + hsync_front_porch=42, |
| 74 | + vsync_back_porch=2, |
| 75 | + vsync_pulse_width=8, |
| 76 | + vsync_front_porch=60, |
| 77 | + phy_ldo_channel=3, |
| 78 | + phy_ldo_voltage_mv=2500, |
| 79 | +) |
| 80 | + |
| 81 | +_FB_SIZE = const(480 * 800 * 2) # RGB565, whole screen: 768000 bytes |
| 82 | +fb1 = display_bus.allocate_framebuffer(_FB_SIZE, lcd_bus.MEMORY_SPIRAM) |
| 83 | +fb2 = display_bus.allocate_framebuffer(_FB_SIZE, lcd_bus.MEMORY_SPIRAM) |
| 84 | + |
| 85 | +mpos.ui.main_display = ST7701_DSI( |
| 86 | + data_bus=display_bus, |
| 87 | + frame_buffer1=fb1, |
| 88 | + frame_buffer2=fb2, |
| 89 | + display_width=LCD_WIDTH, |
| 90 | + display_height=LCD_HEIGHT, |
| 91 | + reset_pin=LCD_RST, |
| 92 | + reset_state=ST7701_DSI.STATE_LOW, |
| 93 | + color_space=lv.COLOR_FORMAT.RGB565, |
| 94 | + color_byte_order=ST7701_DSI.BYTE_ORDER_RGB, |
| 95 | +) # triggers lv.init() |
| 96 | +mpos.ui.main_display.init() |
| 97 | +if __debug__: logger.debug("ST7701 panel ID: %s", mpos.ui.main_display.panel_id) |
| 98 | + |
| 99 | +mpos.ui.main_display.set_backlight = _set_backlight |
| 100 | +mpos.ui.main_display.get_backlight = _get_backlight |
| 101 | + |
| 102 | +# Push a first frame now: the bus starts the DSI video stream on the first |
| 103 | +# flush, and the backlight only goes on once the panel has something to show. |
| 104 | +try: |
| 105 | + lv.refr_now(None) |
| 106 | +except Exception as e: |
| 107 | + logger.error("initial refresh failed: %s" % (e)) |
| 108 | +mpos.ui.main_display.set_backlight(100) |
| 109 | + |
| 110 | +# === TOUCH (GT911) === |
| 111 | +# Neither its reset nor its interrupt line is wired to the P4 on this board, |
| 112 | +# so the controller is polled at whichever address its strap selected. |
| 113 | +i2c_bus = i2c.I2C.Bus(host=0, scl=I2C_SCL, sda=I2C_SDA, freq=I2C_FREQ, use_locks=False) |
| 114 | +try: |
| 115 | + present = i2c_bus.scan() |
| 116 | + touch_addr = next((a for a in TOUCH_ADDRS if a in present), None) |
| 117 | + if touch_addr is None: |
| 118 | + raise RuntimeError("GT911 not found on I2C (devices: %s)" % [hex(a) for a in present]) |
| 119 | + touch_dev = i2c.I2C.Device(bus=i2c_bus, dev_id=touch_addr, reg_bits=gt911.BITS) |
| 120 | + indev = gt911.GT911(touch_dev) |
| 121 | + InputManager.register_indev(indev) |
| 122 | +except Exception as e: |
| 123 | + logger.error("GT911 init failed: %s" % (e)) |
14 | 124 |
|
15 | | -logger.warning("Waveshare ESP32-P4-WIFI6-Touch-LCD-4.3: stage-1 board file, no display driver yet") |
| 125 | +if __debug__: logger.debug("waveshare_esp32_p4_wifi6_touch_lcd_4_3.py finished") |
0 commit comments