diff --git a/internal_filesystem/lib/mpos/board/cyd.py b/internal_filesystem/lib/mpos/board/cyd.py new file mode 100644 index 00000000..eadade09 --- /dev/null +++ b/internal_filesystem/lib/mpos/board/cyd.py @@ -0,0 +1,174 @@ +print("cyd.py initialization") +""" +Cheap Yellow Display: + https://github.com/witnessmenow/ESP32-Cheap-Yellow-Display +Tested with "ESP32-2432S028" + + * Display: ili9341 320x240 + * Touch: xpt2046 + +Original author: https://github.com/jedie +""" + +import time + +import drivers.display.ili9341 as ili9341 +import lcd_bus +import lvgl as lv +import machine +import mpos.ui +from drivers.indev.xpt2046 import XPT2046 +from machine import ADC, Pin +from micropython import const +from mpos import InputManager + +# Display (HSPI) +SPI_HOST = const(0) +SPI_FREQ = const(8_000_000) # 8MHz max for ILI9341 +SPI_DC = const(2) # TFT_RS / TFT_DC +SPI_CS = const(15) # TFT_CS +SPI_RST = const(15) # No reset pin, so use CS pin +SPI_SCK = const(14) # TFT_SCK +SPI_MISO = const(12) # TFT_SDO / TFT_MISO +SPI_MOSI = const(13) # TFT_SDI / TFT_MOSI + +BACKLIGHT_PIN = const(21) # TFT_BL (also on P3) +DISPLAY_WIDTH = const(320) +DISPLAY_HEIGHT = const(240) +LCD_TYPE = const(2) # ILI9341 type 2 + +# Touch Screen (XPT2046) +TOUCH_SPI_HOST = const(1) +TOUCH_SPI_FREQ = const(1_000_000) # 1MHz +TOUCH_SPI_SCK = const(25) +TOUCH_SPI_MOSI = const(32) +TOUCH_SPI_MISO = const(39) +TOUCH_SPI_CS = const(33) +TOUCH_SPI_INT = const(36) + +# SD Card (VSPI) +SDCARD_SLOT = const(2) +SDCARD_SCK = const(18) +SDCARD_MISO = const(19) +SDCARD_MOSI = const(23) +SDCARD_CS = const(5) + +# RGB LED (active low) +LED_RED = const(4) +LED_GREEN = const(16) +LED_BLUE = const(17) + +# Light Sensor +LIGHTSENSOR_ADC_PIN = const(34) + +# Speaker (amplified) +SPEAKER_PIN = const(26) + +# Buttons +BUTTON_BOOT = const(0) + +# Connectors +P3_IO35 = const(35) # Input only +P3_IO22 = const(22) +CN1_IO22 = const(22) +CN1_IO27 = const(27) +P1_IO1 = const(1) # TX (maybe usable as GPIO) +P1_IO3 = const(3) # RX (maybe usable as GPIO) + + +# RGB LED at the back +red_led = Pin(LED_RED, Pin.OUT) +green_led = Pin(LED_GREEN, Pin.OUT) +blue_led = Pin(LED_BLUE, Pin.OUT) + +# RGB LED (and backlight) will also work with machine.PWM for dimming + +# Turn on all LEDs (active low): +red_led.on() +green_led.on() +blue_led.on() + + +# Read light sensor +lightsensor = ADC(LIGHTSENSOR_ADC_PIN, atten=ADC.ATTN_0DB) +print(f"{lightsensor.read_uv()=}") + + +print("cyd.py machine.SPI.Bus() initialization") +try: + spi_bus = machine.SPI.Bus( + host=TOUCH_SPI_HOST, sck=SPI_SCK, mosi=SPI_MOSI, miso=SPI_MISO + ) +except Exception as e: + print(f"Error initializing SPI bus: {e}") + print("Attempting hard reset in 3sec...") + time.sleep(3) + machine.reset() + +print("cyd.py lcd_bus.SPIBus() initialization") +display_bus = lcd_bus.SPIBus(spi_bus=spi_bus, freq=SPI_FREQ, dc=SPI_DC, cs=SPI_CS) + +print("cyd.py ili9341.ILI9341() initialization") +try: + mpos.ui.main_display = ili9341.ILI9341( + data_bus=display_bus, + display_width=DISPLAY_WIDTH, + display_height=DISPLAY_HEIGHT, + color_space=lv.COLOR_FORMAT.RGB565, + color_byte_order=ili9341.BYTE_ORDER_BGR, + rgb565_byte_swap=True, + reset_pin=SPI_RST, + reset_state=ili9341.STATE_LOW, + backlight_pin=BACKLIGHT_PIN, + backlight_on_state=ili9341.STATE_PWM, + ) +except Exception as e: + print(f"Error initializing ILI9341: {e}") + print("Attempting hard reset in 3sec...") + time.sleep(3) + machine.reset() + + +print("cyd.py display.init()") +mpos.ui.main_display.init(LCD_TYPE) +mpos.ui.main_display.set_power(True) +mpos.ui.main_display.set_color_inversion(False) +mpos.ui.main_display.set_backlight(100) + +print("cyd.py lv.init() initialization") +lv.init() + +print("cyd.py Touch initialization") +touch_dev = machine.SPI.Device(spi_bus=spi_bus, freq=TOUCH_SPI_FREQ, cs=TOUCH_SPI_CS) + +indev = XPT2046( + touch_dev, + lcd_cs=SPI_CS, + touch_cs=TOUCH_SPI_CS, + display_width=DISPLAY_WIDTH, + display_height=DISPLAY_HEIGHT, + startup_rotation=lv.DISPLAY_ROTATION._0, +) + + +group = lv.group_create() +group.set_default() +# +# # Create and set up the input device +# indev = lv.indev_create() +# indev.set_type(lv.INDEV_TYPE.KEYPAD) +# +indev.set_group( + group +) # is this needed? maybe better to move the default group creation to main.py so it's available everywhere... +# disp = lv.display_get_default() # NOQA +# indev.set_display(disp) # different from display +indev.enable(True) # NOQA +InputManager.register_indev(indev) + +# Turn off all LEDs to indicate initialization is done: +red_led.off() +green_led.off() +blue_led.off() + +print("\ncyd.py init finished\n") diff --git a/internal_filesystem/lib/mpos/main.py b/internal_filesystem/lib/mpos/main.py index e7b83948..3b48e58d 100644 --- a/internal_filesystem/lib/mpos/main.py +++ b/internal_filesystem/lib/mpos/main.py @@ -172,6 +172,10 @@ def detect_board(): if unique_id_prefixes == b'\x30\xae\xa4': return "odroid_go" + print("cyd - Cheap Yellow Display ?") + if unique_id_prefixes == b'\xec\xe34': # FIXME: Use other detection! MAC seems to be random! + return "cyd" + # Do I2C-based board detection # IMPORTANT: ESP32 GPIO 6-11 are internal SPI flash pins and will cause WDT reset if used. # ESP32-S3 has more usable GPIOs (up to 48). Detect chip variant first to skip unsafe probes. @@ -247,6 +251,9 @@ def detect_board(): print(f"Detected {board} system, importing mpos.board.{board}") DeviceInfo.set_hardware_id(board) __import__(f"mpos.board.{board}") +else: + # It makes no sense to continue, because we have no display etc... + raise RuntimeError("No board detected, exit initialization!") # Allow LVGL M:/path/to/file or M:relative/path/to/file to work for image set_src etc import mpos.fs_driver diff --git a/internal_filesystem/main.py b/internal_filesystem/main.py index c44ee8a6..f0fcb96b 100644 --- a/internal_filesystem/main.py +++ b/internal_filesystem/main.py @@ -28,4 +28,11 @@ ) print("Passing execution over to mpos.main") -import mpos.main # noqa: F401 +try: + import mpos.main # noqa: F401 +except Exception as e: + sys.print_exception(e) + import time + print(f"Error in mpos.main, sleep for 5 seconds and end then...") + time.sleep(5) + diff --git a/scripts/build_mpos.sh b/scripts/build_mpos.sh index 4308b4a9..8827fbcc 100755 --- a/scripts/build_mpos.sh +++ b/scripts/build_mpos.sh @@ -8,14 +8,15 @@ target="$1" buildtype="$2" if [ -z "$target" ]; then - echo "Usage: $0 target" - echo "Usage: $0 " - echo "Example: $0 unix" - echo "Example: $0 macOS" - echo "Example: $0 esp32" - echo "Example: $0 esp32s3" - echo "Example: $0 unphone" - echo "Example: $0 clean" + echo "Usage: $0 target" + echo "Usage: $0 " + echo "Example: $0 unix" + echo "Example: $0 macOS" + echo "Example: $0 esp32" + echo "Example: $0 esp32-small" + echo "Example: $0 esp32s3" + echo "Example: $0 unphone" + echo "Example: $0 clean" exit 1 fi @@ -106,20 +107,27 @@ popd echo "Refreshing freezefs..." "$codebasedir"/scripts/freezefs_mount_builtin.sh -if [ "$target" == "esp32" -o "$target" == "esp32s3" -o "$target" == "unphone" ]; then - partition_size="4194304" - flash_size="16" +if [ "$target" == "esp32" -o "$target" == "esp32s3" -o "$target" == "unphone" -o "$target" == "esp32-small" ]; then + partition_size="4194304" + flash_size="16" otasupport="--ota" extra_configs="" - if [ "$target" == "esp32" ]; then + if [ "$target" == "esp32" ]; then BOARD=ESP32_GENERIC BOARD_VARIANT=SPIRAM + elif [ "$target" == "esp32-small" ]; then + # No PSRAM, so do not set SPIRAM-specific options + BOARD=ESP32_GENERIC + BOARD_VARIANT= + partition_size="3900000" + flash_size="4" + otasupport="" # too small for 2 OTA partitions + internal storage else # esp32s3 or unphone - if [ "$target" == "unphone" ]; then - partition_size="3900000" - flash_size="8" + if [ "$target" == "unphone" ]; then + partition_size="3900000" + flash_size="8" otasupport="" # too small for 2 OTA partitions + internal storage - fi + fi BOARD=ESP32_GENERIC_S3 BOARD_VARIANT=SPIRAM_OCT # These options disable hardware AES, SHA and MPI because they give warnings in QEMU: [AES] Error reading from GDMA buffer @@ -128,6 +136,12 @@ if [ "$target" == "esp32" -o "$target" == "esp32s3" -o "$target" == "unphone" ]; # --py-freertos: add MicroPython FreeRTOS module to expose internals extra_configs="$extra_configs --py-freertos" fi + + if [ "$BOARD_VARIANT" == "SPIRAM" -o "$BOARD_VARIANT" == "SPIRAM_OCT" ]; then + # Camera only works on boards configured with spiram, otherwise the build breaks + extra_configs="$extra_configs USER_C_MODULE=$codebasedir/micropython-camera-API/src/micropython.cmake" + fi + manifest=$(readlink -f "$codebasedir"/manifests/manifest.py) frozenmanifest="FROZEN_MANIFEST=$manifest" # Comment this out if you want to make a build without any frozen files, just an empty MicroPython + whatever files you have on the internal storage echo "Note that you can also prevent the builtin filesystem from being mounted by umounting it and creating a builtin/ folder." @@ -148,17 +162,17 @@ if [ "$target" == "esp32" -o "$target" == "esp32s3" -o "$target" == "unphone" ]; # CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y # CONFIG_ADC_MIC_TASK_CORE=1 because with the default (-1) it hangs the CPU # CONFIG_SPIRAM_XIP_FROM_PSRAM: load entire firmware into RAM to reduce SD vs PSRAM contention (recommended at https://github.com/MicroPythonOS/MicroPythonOS/issues/17) - python3 make.py "$otasupport" --optimize-size --partition-size=$partition_size --flash-size=$flash_size esp32 BOARD=$BOARD BOARD_VARIANT=$BOARD_VARIANT \ - 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 \ - CONFIG_ADC_MIC_TASK_CORE=1 \ - $extra_configs \ - "$frozenmanifest" - + set -x + python3 make.py $otasupport --optimize-size --partition-size=$partition_size --flash-size=$flash_size esp32 BOARD=$BOARD BOARD_VARIANT=$BOARD_VARIANT \ + 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 \ + CONFIG_ADC_MIC_TASK_CORE=1 \ + $extra_configs \ + "$frozenmanifest" + set +x popd elif [ "$target" == "unix" -o "$target" == "macOS" ]; then manifest=$(readlink -f "$codebasedir"/manifests/manifest.py)