diff --git a/internal_filesystem/lib/mpos/board/matouch_esp32_s3_2_8.py b/internal_filesystem/lib/mpos/board/matouch_esp32_s3_2_8.py new file mode 100644 index 00000000..c4acccd8 --- /dev/null +++ b/internal_filesystem/lib/mpos/board/matouch_esp32_s3_2_8.py @@ -0,0 +1,152 @@ + +print("matouch_esp32_s3_2_8.py initialization") +# Hardware initialization for Makerfabs MaTouch ESP32-S3 SPI 2.8" with Camera +# Manufacturer's website: https://www.makerfabs.com/matouch-esp32-s3.html +# Hardware Specifications: +# - MCU: ESP32-S3 with 16MB Flash, 8MB Octal PSRAM +# - Display: 2.8" IPS LCD, 320x240 resolution, ST7789 driver, SPI interface +# - Touch: GT911 capacitive touch controller (5-point), I2C interface +# - Camera: OV3660 (3MP, up to 2048x1536) +# - No IMU sensor (unlike Fri3d and Waveshare boards) +# - No NeoPixel LEDs +# - No buzzer or I2S audio + +from micropython import const +import st7789 +import lcd_bus +import machine +import gt911 +import i2c + +import lvgl as lv +import task_handler + +import mpos.ui + +# Pin configuration for Display (SPI) +# Correct pins from hardware schematic +SPI_BUS = 1 +SPI_FREQ = 40000000 +LCD_SCLK = 14 +LCD_MOSI = 13 +LCD_MISO = 12 +LCD_DC = 21 +LCD_CS = 15 +LCD_RST = -1 +LCD_BL = 48 + +# Pin configuration for Touch (I2C) +# Correct pins from hardware schematic: +# TOUCH_SDA = 39, TOUCH_SCL = 38, TOUCH_INT = 40, TOUCH_RST = 1 +I2C_BUS = 0 +I2C_FREQ = 400000 +TP_SDA = 39 +TP_SCL = 38 +TP_INT = 40 +TP_RST = 1 + +# Display resolution +TFT_HOR_RES = 320 +TFT_VER_RES = 240 + +# Initialize SPI bus for display +spi_bus = machine.SPI.Bus( + host=SPI_BUS, + mosi=LCD_MOSI, + miso=LCD_MISO, + sck=LCD_SCLK +) + +display_bus = lcd_bus.SPIBus( + spi_bus=spi_bus, + freq=SPI_FREQ, + dc=LCD_DC, + cs=LCD_CS, +) + +# Allocate frame buffers +# Buffer size calculation: 2 bytes per pixel (RGB565) * width * height / divisor +# Using 28800 bytes (same as Waveshare and Fri3d) for good performance +_BUFFER_SIZE = const(28800) +fb1 = display_bus.allocate_framebuffer(_BUFFER_SIZE, lcd_bus.MEMORY_INTERNAL | lcd_bus.MEMORY_DMA) +fb2 = display_bus.allocate_framebuffer(_BUFFER_SIZE, lcd_bus.MEMORY_INTERNAL | lcd_bus.MEMORY_DMA) + +# Initialize ST7789 display +mpos.ui.main_display = st7789.ST7789( + data_bus=display_bus, + frame_buffer1=fb1, + frame_buffer2=fb2, + display_width=TFT_HOR_RES, + display_height=TFT_VER_RES, + color_space=lv.COLOR_FORMAT.RGB565, + color_byte_order=st7789.BYTE_ORDER_BGR, + rgb565_byte_swap=True, + reset_pin=LCD_RST, + backlight_pin=LCD_BL, + backlight_on_state=st7789.STATE_PWM, +) + +mpos.ui.main_display.init() +mpos.ui.main_display.set_power(True) +mpos.ui.main_display.set_backlight(100) + +# Touch handling: +i2c_bus = i2c.I2C.Bus(host=I2C_BUS, scl=TP_SCL, sda=TP_SDA, freq=I2C_FREQ, use_locks=False) +touch_dev = i2c.I2C.Device(bus=i2c_bus, dev_id=gt911.I2C_ADDR, reg_bits=gt911.BITS) +indev = gt911.GT911(touch_dev) + +# Initialize LVGL +lv.init() + +# Set display rotation if needed (adjust based on physical orientation) +# mpos.ui.main_display.set_rotation(lv.DISPLAY_ROTATION._0) + +# === BATTERY VOLTAGE MONITORING === +# Note: MaTouch ESP32-S3 battery monitoring configuration may vary +# This is a placeholder - adjust ADC pin and conversion formula based on actual hardware +from mpos import BatteryManager + +def adc_to_voltage(adc_value): + """ + Convert raw ADC value to battery voltage. + Currently uses simple linear scaling: voltage = adc * 0.00262 + + This should be calibrated with actual battery voltages and ADC readings. + To calibrate: measure actual battery voltages and corresponding ADC readings, + then fit a linear or polynomial function. + """ + return adc_value * 0.00262 + +# Note: Adjust ADC pin number based on actual hardware schematic +# BatteryManager.init_adc(5, adc_to_voltage) + +# === AUDIO HARDWARE === +# Note: MaTouch ESP32-S3 has no buzzer or I2S audio hardware +# AudioManager will not be initialized + +# === LED HARDWARE === +# Note: MaTouch ESP32-S3 has no NeoPixel LEDs +# LightsManager will not be initialized (functions will return False) + +# === SENSOR HARDWARE === +# Note: MaTouch ESP32-S3 has no IMU sensor +# SensorManager will not be initialized + +# === CAMERA HARDWARE === +from mpos import CameraManager + +# MaTouch ESP32-S3 has OV3660 camera (3MP, up to 2048x1536) +# Camera pins are available but initialization is handled by the camera driver +CameraManager.add_camera(CameraManager.Camera( + lens_facing=CameraManager.CameraCharacteristics.LENS_FACING_BACK, + name="OV3660", + vendor="OmniVision" +)) + +print("matouch_esp32_s3_2_8.py finished") +print("Board capabilities:") +print(" - Display: 320x240 ST7789 with GT911 touch") +print(" - Camera: OV3660 (3MP)") +print(" - No IMU sensor") +print(" - No LEDs") +print(" - No audio hardware") diff --git a/internal_filesystem/lib/mpos/main.py b/internal_filesystem/lib/mpos/main.py index 360a7423..532423ff 100644 --- a/internal_filesystem/lib/mpos/main.py +++ b/internal_filesystem/lib/mpos/main.py @@ -31,16 +31,89 @@ def detect_board(): if sys.platform == "linux" or sys.platform == "darwin": # linux and macOS return "linux" elif sys.platform == "esp32": + # Force MaTouch for ESP32-S3 with 8MB PSRAM + # This bypasses unreliable GT911 touch controller detection at boot + try: + import esp32 + if hasattr(esp32, 'spiram_size'): + psram_size = esp32.spiram_size() + print(f"Detected ESP32-S3 with PSRAM size: {psram_size} bytes ({psram_size // 1048576}MB)") + if psram_size == 8388608: # 8MB PSRAM + board_name = "matouch_esp32_s3_2_8" + print(f"Forcing board selection: {board_name}") + return board_name + except Exception as e: + print(f"PSRAM detection failed: {e}") + from machine import Pin, I2C - i2c0 = I2C(0, sda=Pin(48), scl=Pin(47)) - if {0x15, 0x6B} <= set(i2c0.scan()): # touch screen and IMU (at least, possibly more) - return "waveshare_esp32_s3_touch_lcd_2" - else: - i2c0 = I2C(0, sda=Pin(9), scl=Pin(18)) - if {0x6B} <= set(i2c0.scan()): # IMU (plus possibly the Communicator's LANA TNY at 0x38) + import time + + # Check for MaTouch ESP32-S3 (GT911 touch on I2C0) + # Correct pins from schematic: SDA=39, SCL=38, INT=40, RST=1 + # GT911 requires specific reset sequence with INT pin control for address selection + try: + # GT911 address selection via INT pin during reset: + # INT=LOW during reset -> address 0x5D + # INT=HIGH during reset -> address 0x14 + + # Try address 0x5D first (INT=LOW during reset) + tp_rst = Pin(1, Pin.OUT) + tp_int = Pin(40, Pin.OUT) + + # Reset sequence for address 0x5D + tp_int.value(0) # INT LOW for address 0x5D + tp_rst.value(0) + time.sleep_ms(10) + tp_rst.value(1) + time.sleep_ms(10) + tp_int.init(Pin.IN) # Release INT pin + time.sleep_ms(100) # Wait for GT911 to initialize + + # Now try I2C communication with correct pins from schematic + i2c0 = I2C(0, sda=Pin(39), scl=Pin(38), freq=400000) + devices = set(i2c0.scan()) + print(f"MaTouch I2C scan (SDA=39, SCL=38): {[hex(d) for d in devices]}") + + # GT911 touch controller uses addresses 0x5D or 0x14 + if 0x5D in devices or 0x14 in devices: + print("Detected MaTouch ESP32-S3 (GT911 found)") + return "matouch_esp32_s3_2_8" + + # Clean up pins + tp_rst.init(Pin.IN) + tp_int.init(Pin.IN) + except Exception as e: + print(f"MaTouch detection failed: {e}") + import sys + sys.print_exception(e) + + # Check for Waveshare ESP32-S3-Touch-LCD-2 + try: + i2c0 = I2C(0, sda=Pin(48), scl=Pin(47), freq=400000) + devices = set(i2c0.scan()) + print(f"Waveshare I2C scan (SDA=48, SCL=47): {[hex(d) for d in devices]}") + # Filter out invalid addresses (valid I2C range is 0x08-0x77) + valid_devices = {d for d in devices if 0x08 <= d <= 0x77} + if {0x15, 0x6B} <= valid_devices: # touch screen and IMU (at least, possibly more) + print("Detected Waveshare ESP32-S3-Touch-LCD-2") + return "waveshare_esp32_s3_touch_lcd_2" + except Exception as e: + print(f"Waveshare detection failed: {e}") + + # Check for Fri3d 2024 + try: + i2c0 = I2C(0, sda=Pin(9), scl=Pin(18), freq=400000) + devices = set(i2c0.scan()) + print(f"Fri3d I2C scan (SDA=9, SCL=18): {[hex(d) for d in devices]}") + if {0x6B} <= devices: # IMU (plus possibly the Communicator's LANA TNY at 0x38) + print("Detected Fri3d 2024") return "fri3d_2024" else: # if {0x6A} <= set(i2c0.scan()): # IMU (plus a few others, to be added later, but this should work) + print("Detected Fri3d 2026") return "fri3d_2026" + except Exception as e: + print(f"Fri3d detection failed: {e}") + return "fri3d_2026" # Default fallback board = detect_board() diff --git a/scripts/build_all.sh b/scripts/build_all.sh index c7a5ea8c..e5150418 100755 --- a/scripts/build_all.sh +++ b/scripts/build_all.sh @@ -47,6 +47,23 @@ if [ $result -ne 0 ]; then fi cp "$buildfile" "$outdir"/MicroPythonOS_waveshare-esp32-s3-touch-lcd-2_dev_"$version".bin +./scripts/build_lvgl_micropython.sh esp32 prod matouch-esp32-s3-2-8 +result=$? +if [ $result -ne 0 ]; then + echo "build_lvgl_micropython.sh esp32 prod matouch-esp32-s3-2-8 got error: $result" + exit 1 +fi +cp "$buildfile" "$outdir"/MicroPythonOS_matouch-esp32-s3-2-8_prod_"$version".bin +cp "$updatefile" "$updatesdir"/MicroPythonOS_matouch-esp32-s3-2-8_prod_"$version".ota + +./scripts/build_lvgl_micropython.sh esp32 dev matouch-esp32-s3-2-8 +result=$? +if [ $result -ne 0 ]; then + echo "build_lvgl_micropython.sh esp32 dev matouch-esp32-s3-2-8 got error: $result" + exit 1 +fi +cp "$buildfile" "$outdir"/MicroPythonOS_matouch-esp32-s3-2-8_dev_"$version".bin + ./scripts/build_lvgl_micropython.sh unix dev cp "$builddir"/lvgl_micropy_unix "$outdir"/MicroPythonOS_amd64_linux_"$version".elf result=$? diff --git a/scripts/build_mpos.sh b/scripts/build_mpos.sh index 797c592b..03254d34 100755 --- a/scripts/build_mpos.sh +++ b/scripts/build_mpos.sh @@ -14,6 +14,10 @@ if [ -z "$target" ]; then echo "Example: $0 unix" echo "Example: $0 macOS" echo "Example: $0 esp32" + echo "" + echo "Note: For TOML-based builds (e.g., MaTouch ESP32-S3), use:" + echo " cd lvgl_micropython && python3 make.py esp32 --toml=display_configs/MaTouch-ESP32-S3-SPI-2.8.toml" + echo " Or use build_lvgl_micropython.sh wrapper script" echo exit 1 fi @@ -112,7 +116,8 @@ if [ "$target" == "esp32" ]; then # CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y pushd "$codebasedir"/lvgl_micropython/ rm -rf lib/micropython/ports/esp32/build-ESP32_GENERIC_S3-SPIRAM_OCT/ - python3 make.py --ota --partition-size=4194304 --flash-size=16 esp32 BOARD=ESP32_GENERIC_S3 BOARD_VARIANT=SPIRAM_OCT DISPLAY=st7789 INDEV=cst816s USER_C_MODULE="$codebasedir"/micropython-camera-API/src/micropython.cmake USER_C_MODULE="$codebasedir"/secp256k1-embedded-ecdh/micropython.cmake USER_C_MODULE="$codebasedir"/c_mpos/micropython.cmake CONFIG_FREERTOS_USE_TRACE_FACILITY=y CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y "$frozenmanifest" + python3 make.py --ota --partition-size=4194304 --flash-size=16 esp32 BOARD=ESP32_GENERIC_S3 BOARD_VARIANT=SPIRAM_OCT DISPLAY=st7789 INDEV=gt911 USER_C_MODULE="$codebasedir"/micropython-camera-API/src/micropython.cmake USER_C_MODULE="$codebasedir"/secp256k1-embedded-ecdh/micropython.cmake USER_C_MODULE="$codebasedir"/c_mpos/micropython.cmake CONFIG_FREERTOS_USE_TRACE_FACILITY=y CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y "$frozenmanifest" + # python3 make.py --ota --partition-size=4194304 --flash-size=16 esp32 BOARD=ESP32_GENERIC_S3 BOARD_VARIANT=SPIRAM_OCT DISPLAY=st7789 INDEV=gt911 USER_C_MODULE="$codebasedir"/micropython-camera-API/src/micropython.cmake USER_C_MODULE="$codebasedir"/secp256k1-embedded-ecdh/micropython.cmake USER_C_MODULE="$codebasedir"/c_mpos/micropython.cmake CONFIG_FREERTOS_USE_TRACE_FACILITY=y CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y "$frozenmanifest" popd echo "Grepping..." pwd