diff --git a/configs/sdkconfig_display_waveshares3_touch_lcd35.defaults b/configs/sdkconfig_display_waveshares3_touch_lcd35.defaults new file mode 100644 index 000000000..cae3d167d --- /dev/null +++ b/configs/sdkconfig_display_waveshares3_touch_lcd35.defaults @@ -0,0 +1,85 @@ +# display waveshares3 touch lcd35 +CONFIG_APP_REPRODUCIBLE_BUILD=y +CONFIG_BF20A6_SUPPORT=n +CONFIG_BF3005_SUPPORT=n +CONFIG_BOARD_TYPE_WS_TOUCH_LCD35=y +CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y +CONFIG_BOOTLOADER_WDT_ENABLE=n +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU=517 +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN=11 +CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=5632 +CONFIG_BT_NIMBLE_LOG_LEVEL_NONE=y +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL=y +CONFIG_BT_NIMBLE_NVS_PERSIST=y +CONFIG_BT_NIMBLE_ROLE_BROADCASTER=n +CONFIG_BT_NIMBLE_ROLE_CENTRAL=n +CONFIG_BT_NIMBLE_ROLE_OBSERVER=n +CONFIG_BT_NIMBLE_SM_LEGACY=n +CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME="j" +CONFIG_BUTTON_LONG_PRESS_HOLD_SERIAL_TIME_MS=100 +CONFIG_BUTTON_LONG_PRESS_TIME_MS=500 +CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y +CONFIG_COMPILER_WARN_WRITE_STRINGS=y +CONFIG_DEBUG_MODE=y +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_ESP_CONSOLE_NONE=y +CONFIG_ESP_CONSOLE_SECONDARY_NONE=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_ESP_ERR_TO_NAME_LOOKUP=n +CONFIG_ESP_MAIN_TASK_STACK_SIZE=12288 +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=n +CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=n +CONFIG_ESP_SYSTEM_BBPLL_RECALIB=n +CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y +CONFIG_ESP_TASK_WDT_EN=n +CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=n +CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=n +CONFIG_ESP_WIFI_IRAM_OPT=n +CONFIG_ESP_WIFI_MBEDTLS_TLS_CLIENT=n +CONFIG_ESP_WIFI_NVS_ENABLED=n +CONFIG_ESP_WIFI_RX_IRAM_OPT=n +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n +CONFIG_ETH_USE_SPI_ETHERNET=n +CONFIG_FATFS_LFN_HEAP=y +CONFIG_FATFS_VFS_FSTAT_BLKSIZE=4096 +CONFIG_FATFS_VOLUME_COUNT=1 +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=3 +CONFIG_GC032A_SUPPORT=n +CONFIG_GC2145_SUPPORT=n +CONFIG_IDF_TARGET="esp32s3" +CONFIG_LIBC_NEWLIB_NANO_FORMAT=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n +CONFIG_MBEDTLS_ECP_RESTARTABLE=y +CONFIG_LIBC_STDIN_LINE_ENDING_LF=y +CONFIG_LIBC_STDOUT_LINE_ENDING_LF=y +CONFIG_NT99141_SUPPORT=n +CONFIG_OV3660_SUPPORT=n +CONFIG_OV7670_SUPPORT=n +CONFIG_OV7725_SUPPORT=n +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitionss3.csv" +CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=n +CONFIG_SC030IOT_SUPPORT=n +CONFIG_SPIRAM=y +CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y +CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=256 +CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=65536 +CONFIG_SPIRAM_MEMTEST=n +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_RODATA=y +CONFIG_SPIRAM_SPEED_80M=y +CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y +CONFIG_SPI_FLASH_VERIFY_WRITE=y +CONFIG_SPI_MASTER_ISR_IN_IRAM=n +CONFIG_SPI_SLAVE_ISR_IN_IRAM=n +CONFIG_TINYUSB_CDC_ENABLED=y +CONFIG_TINYUSB_CDC_RX_BUFSIZE=64 +CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Waveshare" +CONFIG_TINYUSB_DESC_PRODUCT_STRING="S3 Touch LCD 3.5" diff --git a/diy/README.md b/diy/README.md index e551577ab..7bf79aee2 100644 --- a/diy/README.md +++ b/diy/README.md @@ -147,6 +147,24 @@ There are a number of hardware devices that can run Jade firmware with minimal c (BT enabled, see next section for disabling) * [Assembly Guide & Hardware Notes](./waveshare/) +### Waveshare S3 Touch LCD 3.5 +![](img/ws-touch-lcd35.jpg) +* Costs ~$26 USD from manufacturer ($33 USD for the "-C" version with case and OV5640 camera) +* 3.5 inch 320x480 IPS display (ST7796), touch screen interface (virtual buttons) +* Wifi/Bluetooth +* AXP2101 power management with battery charging and level indicator +* Easy USB debugging and flashing +* Typically supports Secure Boot V2 +* Hardware Required (No Soldering Required) + * [Waveshare S3 Touch LCD 3.5](https://www.waveshare.com/esp32-s3-touch-lcd-3.5.htm) (SKU 30733, or SKU 30934 for the -C version) + * OV5640/OV2640 Camera module (included in the -C version) + * 3.7V Lithium battery with MX1.25 connector (optional) +* NOTE: only the plain `3.5` model is supported - the `3.5B` variant uses a + different (QSPI) display controller and does NOT work with this firmware +* Build [config](../configs/sdkconfig_display_waveshares3_touch_lcd35.defaults) + (BT enabled, see next section for disabling) +* [Assembly Guide & Hardware Notes](./waveshare/) + # Modifying Configuration Files for Use Once you are familiar with the process of flashing the firmware using the sdkconfig templates that are included in the /config folder of this repository, there are some additional changes that you should make to these files before using the device with actual funds. diff --git a/diy/img/ws-touch-lcd35.jpg b/diy/img/ws-touch-lcd35.jpg new file mode 100644 index 000000000..fbd8a59a6 Binary files /dev/null and b/diy/img/ws-touch-lcd35.jpg differ diff --git a/diy/waveshare/README.md b/diy/waveshare/README.md index 9e8f4c306..a710b90a0 100644 --- a/diy/waveshare/README.md +++ b/diy/waveshare/README.md @@ -6,6 +6,19 @@ The device uses touchscreen navigation and the BOOT button for sleep/wake. Bluetooth is enabled by default but can be turned off with the NORADIO config script. +## S3 Touch LCD 3.5 + +Same navigation model as the Touch LCD 2 (virtual touch buttons, BOOT button +long-press for sleep/wake). The camera plugs into the onboard DVP FPC +connector (the -C version ships with an OV5640 fitted). Battery charging and +level reporting are handled by the onboard AXP2101 PMU; an optional 3.7V +lithium battery can be attached to the MX1.25 header (check the connector +polarity before plugging it in). A long press of the PWR button (4s) cuts +power; when off on battery, the PWR button powers the device back on. + +NOTE: the `3.5B` variant is a different device (QSPI display controller) and +is not supported. + ## Flashing To prepare the board for flashing, hold down the `BOOT` button and plug in the diff --git a/gitlab/diy_fw.yml b/gitlab/diy_fw.yml index 4b957a2ab..846a09f61 100644 --- a/gitlab/diy_fw.yml +++ b/gitlab/diy_fw.yml @@ -56,3 +56,6 @@ build_diy_diycam_tcameraplus: build_diy_display_waveshares3_touch_lcd2: extends: .build_diy_template + +build_diy_display_waveshares3_touch_lcd35: + extends: .build_diy_template diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 439c82664..5dc9ef5b6 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -116,6 +116,11 @@ menu "Blockstream Jade" select HAS_CAMERA select HAS_BATTERY select DISPLAY_TOUCHSCREEN + config BOARD_TYPE_WS_TOUCH_LCD35 + bool "Waveshare Touch LCD 3.5 (esp32s3)" + select HAS_CAMERA + select HAS_BATTERY + select DISPLAY_TOUCHSCREEN config BOARD_TYPE_QEMU bool "qemu display via websocket" config BOARD_TYPE_QEMU_LARGER @@ -143,7 +148,7 @@ menu "Blockstream Jade" config DISPLAY_TOUCHSCREEN bool "Set if touchscreen is available" - default y if BOARD_TYPE_M5_CORES3 || BOARD_TYPE_M5_CORE2 || BOARD_TYPE_TTGO_TWATCHS3 || BOARD_TYPE_WS_TOUCH_LCD2 + default y if BOARD_TYPE_M5_CORES3 || BOARD_TYPE_M5_CORE2 || BOARD_TYPE_TTGO_TWATCHS3 || BOARD_TYPE_WS_TOUCH_LCD2 || BOARD_TYPE_WS_TOUCH_LCD35 default n choice DISPLAY_TOUCHSCREEN_CONTROLLER @@ -166,12 +171,12 @@ menu "Blockstream Jade" config DISPLAY_SPI_CLOCK int "SPI Clock" - default 40000000 if BOARD_TYPE_JADE_V2_ANY || BOARD_TYPE_M5_CORES3 || BOARD_TYPE_TTGO_TWATCHS3 + default 40000000 if BOARD_TYPE_JADE_V2_ANY || BOARD_TYPE_M5_CORES3 || BOARD_TYPE_TTGO_TWATCHS3 || BOARD_TYPE_WS_TOUCH_LCD35 default 32000000 config DISPLAY_SPI_HOST int "SPI host" - default 2 if BOARD_TYPE_JADE_V2_ANY || BOARD_TYPE_M5_CORES3 + default 2 if BOARD_TYPE_JADE_V2_ANY || BOARD_TYPE_M5_CORES3 || BOARD_TYPE_WS_TOUCH_LCD35 default 1 config DISPLAY_INVERT @@ -179,7 +184,8 @@ menu "Blockstream Jade" default y if BOARD_TYPE_JADE_ANY || \ BOARD_TYPE_TTGO_TDISPLAY || BOARD_TYPE_M5_STICKC_PLUS || BOARD_TYPE_M5_STICKC_PLUS_2 || \ BOARD_TYPE_M5_FIRE || BOARD_TYPE_TTGO_TDISPLAYS3 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA || \ - BOARD_TYPE_M5_BLACK_GRAY || BOARD_TYPE_TTGO_TWATCHS3 || BOARD_TYPE_WS_TOUCH_LCD2 + BOARD_TYPE_M5_BLACK_GRAY || BOARD_TYPE_TTGO_TWATCHS3 || BOARD_TYPE_WS_TOUCH_LCD2 || \ + BOARD_TYPE_WS_TOUCH_LCD35 help Invert the colors in the dipslay. Some devices may have inverted colors depending on revision @@ -203,6 +209,7 @@ menu "Blockstream Jade" config I2C_SDA int "I2C SDA Pin" default 4 if BOARD_TYPE_JADE_V1_ANY + default 8 if BOARD_TYPE_WS_TOUCH_LCD35 default 12 if BOARD_TYPE_M5_CORES3 default 21 if BOARD_TYPE_M5_STICKC_PLUS || BOARD_TYPE_M5_CORE2 || BOARD_TYPE_M5_FIRE || BOARD_TYPE_M5_BLACK_GRAY default 42 if BOARD_TYPE_JADE_V2_ANY @@ -211,6 +218,7 @@ menu "Blockstream Jade" config I2C_SCL int "I2C SCL Pin" default 2 if BOARD_TYPE_JADE + default 7 if BOARD_TYPE_WS_TOUCH_LCD35 default 11 if BOARD_TYPE_M5_CORES3 || BOARD_TYPE_TTGO_TWATCHS3 default 14 if BOARD_TYPE_JADE_V1_1 default 22 if BOARD_TYPE_M5_STICKC_PLUS || BOARD_TYPE_M5_CORE2 || BOARD_TYPE_M5_FIRE || BOARD_TYPE_M5_BLACK_GRAY @@ -227,6 +235,7 @@ menu "Blockstream Jade" default 21 if BOARD_TYPE_M5_CORE2 default 39 if BOARD_TYPE_TTGO_TWATCHS3 default 48 if BOARD_TYPE_WS_TOUCH_LCD2 + default 8 if BOARD_TYPE_WS_TOUCH_LCD35 default -1 config I2C_TOUCH_SCL depends on DISPLAY_TOUCHSCREEN @@ -235,6 +244,7 @@ menu "Blockstream Jade" default 40 if BOARD_TYPE_TTGO_TWATCHS3 default 22 if BOARD_TYPE_M5_CORE2 default 47 if BOARD_TYPE_WS_TOUCH_LCD2 + default 7 if BOARD_TYPE_WS_TOUCH_LCD35 default -1 endmenu @@ -359,7 +369,7 @@ menu "Blockstream Jade" int "Camera pin D0" default 13 if BOARD_TYPE_JADE_V2 default 39 if BOARD_TYPE_M5_CORES3 - default 45 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA + default 45 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA || BOARD_TYPE_WS_TOUCH_LCD35 default 12 if BOARD_TYPE_WS_TOUCH_LCD2 default 32 config CAMERA_D1 @@ -368,6 +378,7 @@ menu "Blockstream Jade" default 40 if BOARD_TYPE_M5_CORES3 default 41 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 13 if BOARD_TYPE_WS_TOUCH_LCD2 + default 47 if BOARD_TYPE_WS_TOUCH_LCD35 default 35 config CAMERA_D2 int "Camera pin D2" @@ -375,12 +386,14 @@ menu "Blockstream Jade" default 41 if BOARD_TYPE_M5_CORES3 default 40 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 15 if BOARD_TYPE_WS_TOUCH_LCD2 + default 48 if BOARD_TYPE_WS_TOUCH_LCD35 default 34 config CAMERA_D3 int "Camera pin D3" default 14 if BOARD_TYPE_JADE_V2 default 42 if BOARD_TYPE_M5_CORES3 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 11 if BOARD_TYPE_WS_TOUCH_LCD2 + default 46 if BOARD_TYPE_WS_TOUCH_LCD35 default 5 config CAMERA_D4 int "Camera pin D4" @@ -389,6 +402,7 @@ menu "Blockstream Jade" default 12 if BOARD_TYPE_JADE_V2 default 1 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 14 if BOARD_TYPE_WS_TOUCH_LCD2 + default 42 if BOARD_TYPE_WS_TOUCH_LCD35 default -1 config CAMERA_D5 int "Camera pin D5" @@ -396,6 +410,7 @@ menu "Blockstream Jade" default 16 if BOARD_TYPE_M5_CORES3 default 3 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 10 if BOARD_TYPE_WS_TOUCH_LCD2 + default 40 if BOARD_TYPE_WS_TOUCH_LCD35 default 18 config CAMERA_D6 int "Camera pin D6" @@ -403,6 +418,7 @@ menu "Blockstream Jade" default 48 if BOARD_TYPE_M5_CORES3 default 10 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 7 if BOARD_TYPE_WS_TOUCH_LCD2 + default 39 if BOARD_TYPE_WS_TOUCH_LCD35 default 36 config CAMERA_D7 int "Camera pin D7" @@ -410,6 +426,7 @@ menu "Blockstream Jade" default 47 if BOARD_TYPE_M5_CORES3 default 4 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 2 if BOARD_TYPE_WS_TOUCH_LCD2 + default 21 if BOARD_TYPE_WS_TOUCH_LCD35 default 19 config CAMERA_XCLK @@ -417,10 +434,11 @@ menu "Blockstream Jade" default 8 if BOARD_TYPE_JADE_V2 || BOARD_TYPE_WS_TOUCH_LCD2 default -1 if BOARD_TYPE_M5_CORES3 default 11 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA + default 38 if BOARD_TYPE_WS_TOUCH_LCD35 default 27 config CAMERA_XCLK_FREQ int "Camera XCLK frequency" - default "16000000" if BOARD_TYPE_JADE_V2 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA || BOARD_TYPE_M5_CORES3 + default "16000000" if BOARD_TYPE_JADE_V2 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA || BOARD_TYPE_M5_CORES3 || BOARD_TYPE_WS_TOUCH_LCD35 default "20000000" config CAMERA_PCLK @@ -431,6 +449,7 @@ menu "Blockstream Jade" default 45 if BOARD_TYPE_M5_CORES3 default 2 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 9 if BOARD_TYPE_WS_TOUCH_LCD2 + default 41 if BOARD_TYPE_WS_TOUCH_LCD35 default -1 config CAMERA_VSYNC @@ -439,6 +458,7 @@ menu "Blockstream Jade" default 46 if BOARD_TYPE_M5_CORES3 default 7 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 6 if BOARD_TYPE_WS_TOUCH_LCD2 + default 17 if BOARD_TYPE_WS_TOUCH_LCD35 default 22 config CAMERA_HREF @@ -447,6 +467,7 @@ menu "Blockstream Jade" default 38 if BOARD_TYPE_M5_CORES3 default 15 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 4 if BOARD_TYPE_WS_TOUCH_LCD2 + default 18 if BOARD_TYPE_WS_TOUCH_LCD35 default 26 config CAMERA_SDA @@ -455,6 +476,7 @@ menu "Blockstream Jade" default 12 if BOARD_TYPE_M5_CORES3 default 5 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 21 if BOARD_TYPE_WS_TOUCH_LCD2 + default 8 if BOARD_TYPE_WS_TOUCH_LCD35 default 25 config CAMERA_SCL int "Camera SCL" @@ -462,6 +484,7 @@ menu "Blockstream Jade" default 11 if BOARD_TYPE_M5_CORES3 default 6 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 16 if BOARD_TYPE_WS_TOUCH_LCD2 + default 7 if BOARD_TYPE_WS_TOUCH_LCD35 default 23 config CAMERA_RESET @@ -485,7 +508,7 @@ menu "Blockstream Jade" int "Display width in pixels" range 0 640 default 320 if BOARD_TYPE_JADE_V2_ANY || BOARD_TYPE_QEMU_LARGER || BOARD_TYPE_M5_FIRE || BOARD_TYPE_M5_BLACK_GRAY || BOARD_TYPE_TTGO_TDISPLAYS3 || BOARD_TYPE_M5_CORES3 || BOARD_TYPE_M5_CORE2 - default 480 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA + default 480 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA || BOARD_TYPE_WS_TOUCH_LCD35 default 240 config DISPLAY_HEIGHT int "Display height in pixels" @@ -495,16 +518,16 @@ menu "Blockstream Jade" default 170 if BOARD_TYPE_JADE_V2_ANY || BOARD_TYPE_QEMU_LARGER || BOARD_TYPE_TTGO_TDISPLAYS3 default 200 if BOARD_TYPE_M5_CORES3 || BOARD_TYPE_TTGO_TWATCHS3 default 222 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA - default 280 if BOARD_TYPE_WS_TOUCH_LCD2 + default 280 if BOARD_TYPE_WS_TOUCH_LCD2 || BOARD_TYPE_WS_TOUCH_LCD35 default 135 config DCS_ADDRESS_MODE_BGR_SELECTED bool "BGR" - default y if BOARD_TYPE_M5_FIRE || BOARD_TYPE_M5_BLACK_GRAY || BOARD_TYPE_M5_CORES3 || BOARD_TYPE_M5_CORE2 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA + default y if BOARD_TYPE_M5_FIRE || BOARD_TYPE_M5_BLACK_GRAY || BOARD_TYPE_M5_CORES3 || BOARD_TYPE_M5_CORE2 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA || BOARD_TYPE_WS_TOUCH_LCD35 config DCS_ADDRESS_MODE_MIRROR_X_SELECTED bool "Mirror X" default y if BOARD_TYPE_JADE_ANY || \ BOARD_TYPE_TTGO_TDISPLAY || BOARD_TYPE_M5_STICKC_PLUS || BOARD_TYPE_M5_STICKC_PLUS_2 || BOARD_TYPE_TTGO_TDISPLAYS3 || BOARD_TYPE_TTGO_TWATCHS3 - default n if BOARD_TYPE_M5_FIRE || BOARD_TYPE_M5_BLACK_GRAY || BOARD_TYPE_M5_CORES3 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA || BOARD_TYPE_WS_TOUCH_LCD2 + default n if BOARD_TYPE_M5_FIRE || BOARD_TYPE_M5_BLACK_GRAY || BOARD_TYPE_M5_CORES3 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA || BOARD_TYPE_WS_TOUCH_LCD2 || BOARD_TYPE_WS_TOUCH_LCD35 config DCS_ADDRESS_MODE_MIRROR_Y_SELECTED bool "Mirror Y" default y if BOARD_TYPE_TTGO_TWATCHS3 @@ -512,19 +535,19 @@ menu "Blockstream Jade" config DCS_ADDRESS_MODE_SWAP_XY_SELECTED bool "Swap X and Y" default y if BOARD_TYPE_JADE_ANY - default y if BOARD_TYPE_TTGO_TDISPLAY || BOARD_TYPE_M5_STICKC_PLUS || BOARD_TYPE_M5_STICKC_PLUS_2 || BOARD_TYPE_TTGO_TDISPLAYS3 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA + default y if BOARD_TYPE_TTGO_TDISPLAY || BOARD_TYPE_M5_STICKC_PLUS || BOARD_TYPE_M5_STICKC_PLUS_2 || BOARD_TYPE_TTGO_TDISPLAYS3 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA || BOARD_TYPE_WS_TOUCH_LCD35 default n if BOARD_TYPE_M5_FIRE || BOARD_TYPE_M5_BLACK_GRAY || BOARD_TYPE_M5_CORES3 || BOARD_TYPE_TTGO_TWATCHS3 || BOARD_TYPE_WS_TOUCH_LCD2 config DISPLAY_OFFSET_X int "X offset" default 0 if BOARD_TYPE_JADE_V2_ANY default 0 if BOARD_TYPE_M5_FIRE || BOARD_TYPE_M5_BLACK_GRAY || BOARD_TYPE_TTGO_TDISPLAYS3 || BOARD_TYPE_TTGO_TWATCHS3 - default 0 if BOARD_TYPE_M5_CORES3 || BOARD_TYPE_M5_CORE2 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA || BOARD_TYPE_WS_TOUCH_LCD2 + default 0 if BOARD_TYPE_M5_CORES3 || BOARD_TYPE_M5_CORE2 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA || BOARD_TYPE_WS_TOUCH_LCD2 || BOARD_TYPE_WS_TOUCH_LCD35 default 40 help Adjust when using small display and image is not centered. config DISPLAY_OFFSET_Y int "Y offset" - default 0 if BOARD_TYPE_M5_FIRE || BOARD_TYPE_M5_BLACK_GRAY || BOARD_TYPE_M5_CORES3 || BOARD_TYPE_M5_CORE2 || BOARD_TYPE_WS_TOUCH_LCD2 + default 0 if BOARD_TYPE_M5_FIRE || BOARD_TYPE_M5_BLACK_GRAY || BOARD_TYPE_M5_CORES3 || BOARD_TYPE_M5_CORE2 || BOARD_TYPE_WS_TOUCH_LCD2 || BOARD_TYPE_WS_TOUCH_LCD35 default 35 if BOARD_TYPE_JADE_V2_ANY || BOARD_TYPE_TTGO_TDISPLAYS3 default 49 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 80 if BOARD_TYPE_TTGO_TWATCHS3 @@ -539,6 +562,7 @@ menu "Blockstream Jade" default 38 if BOARD_TYPE_M5_CORE2 default 8 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 40 if BOARD_TYPE_WS_TOUCH_LCD2 + default 2 if BOARD_TYPE_WS_TOUCH_LCD35 default -1 config DISPLAY_PIN_MOSI int "MOSI pin number" @@ -551,6 +575,7 @@ menu "Blockstream Jade" default 17 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 13 if BOARD_TYPE_TTGO_TWATCHS3 default 38 if BOARD_TYPE_WS_TOUCH_LCD2 + default 1 if BOARD_TYPE_WS_TOUCH_LCD35 default -1 config DISPLAY_PIN_CLK int "CLK pin number" @@ -561,6 +586,7 @@ menu "Blockstream Jade" default 18 if BOARD_TYPE_M5_FIRE || BOARD_TYPE_M5_BLACK_GRAY || BOARD_TYPE_TTGO_TDISPLAY || BOARD_TYPE_M5_CORE2 || BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA || BOARD_TYPE_TTGO_TWATCHS3 default 36 if BOARD_TYPE_M5_CORES3 default 39 if BOARD_TYPE_WS_TOUCH_LCD2 + default 5 if BOARD_TYPE_WS_TOUCH_LCD35 default -1 config DISPLAY_PIN_CS int "CS pin number" @@ -588,6 +614,7 @@ menu "Blockstream Jade" default 9 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 38 if BOARD_TYPE_TTGO_TWATCHS3 default 42 if BOARD_TYPE_WS_TOUCH_LCD2 + default 3 if BOARD_TYPE_WS_TOUCH_LCD35 default -1 config DISPLAY_PIN_RST int "RST pin number" @@ -607,6 +634,7 @@ menu "Blockstream Jade" default 48 if BOARD_TYPE_TTGO_TDISPLAYS3PROCAMERA default 45 if BOARD_TYPE_TTGO_TWATCHS3 default 1 if BOARD_TYPE_WS_TOUCH_LCD2 + default 6 if BOARD_TYPE_WS_TOUCH_LCD35 default -1 config PIN_NUM_DC int "DC pin number" diff --git a/main/camera.c b/main/camera.c index 5835dddb6..120e94307 100644 --- a/main/camera.c +++ b/main/camera.c @@ -281,10 +281,19 @@ static void jade_camera_init(void) .jpeg_quality = 0 }; +#if defined(CONFIG_DISPLAY_TOUCHSCREEN) + // On some boards the touchscreen i2c bus uses the same pins as the camera's + // sccb - stop it so the camera can drive them (it is restarted below), + // otherwise the sccb cannot claim the pins and the sensor is never found + touchscreen_deinit(); +#endif const esp_err_t err = esp_camera_init(&camera_config); JADE_LOGI("Camera init done"); if (err != ESP_OK) { JADE_LOGE("Camera init failed with error 0x%x", err); +#if defined(CONFIG_DISPLAY_TOUCHSCREEN) + touchscreen_init(); +#endif camera_post_exit_event_and_await_death(); } @@ -321,7 +330,7 @@ static void jade_camera_init(void) } #endif // !defined(CONFIG_ETH_USE_OPENETH) && defined(ESP_PLATFORM) #if defined(CONFIG_DISPLAY_TOUCHSCREEN) - touchscreen_deinit(); + // Restart the touchscreen stopped before esp_camera_init() above touchscreen_init(); #endif } diff --git a/main/display.c b/main/display.c index 591255611..ebab1df7b 100644 --- a/main/display.c +++ b/main/display.c @@ -186,7 +186,7 @@ void display_fill_rect(int x, int y, int w, int h, color_t color) JADE_LOGE( "display_fill_rect called with bad params (ignored) x %d y %d w %d h %d color %u\n", x, y, w, h, color); #if !defined(CONFIG_BOARD_TYPE_M5_CORES3) && !defined(CONFIG_BOARD_TYPE_TTGO_TWATCHS3) \ - && !defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) + && !defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) && !defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD35) return; #endif } @@ -253,7 +253,7 @@ void display_init(TaskHandle_t* gui_h) display_hw_init(gui_h); #if defined(CONFIG_BOARD_TYPE_TTGO_TWATCHS3) || defined(CONFIG_BOARD_TYPE_M5_CORES3) \ - || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) + || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD35) #define TOUCH_BUTTON_AREA 40 #define TOUCH_BUTTON_MARGIN 5 #define TOUCH_BUTTON_WIDTH 40 diff --git a/main/display_hw.c b/main/display_hw.c index 79629afc3..3afc0d533 100644 --- a/main/display_hw.c +++ b/main/display_hw.c @@ -87,7 +87,8 @@ static void esp_lcd_init(void* _ignored) esp_lcd_panel_io_handle_t io_handle = NULL; #if CONFIG_DISPLAY_PIN_BL != -1 && !defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) \ - && !defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) && !defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2) + && !defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD35) && !defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) \ + && !defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2) gpio_config_t bk_gpio_config = { .mode = GPIO_MODE_OUTPUT, .pin_bit_mask = 1ULL << CONFIG_DISPLAY_PIN_BL }; ESP_ERROR_CHECK(gpio_config(&bk_gpio_config)); ESP_ERROR_CHECK(gpio_set_level(CONFIG_DISPLAY_PIN_BL, 0)); @@ -285,7 +286,7 @@ inline void display_hw_draw_bitmap(int x, int y, int w, int h, const uint16_t* c const int calculatedx = x - CONFIG_DISPLAY_OFFSET_X; const int calculatedy = y - CONFIG_DISPLAY_OFFSET_Y; #if (defined(CONFIG_BOARD_TYPE_M5_CORES3) || defined(CONFIG_BOARD_TYPE_TTGO_TWATCHS3) \ - || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2)) \ + || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD35)) \ && defined(CONFIG_DISPLAY_FULL_FRAME_BUFFER) /* this is required for the virtual buttons */ if (calculatedy >= CONFIG_DISPLAY_HEIGHT) { diff --git a/main/input/touchscreen.inc b/main/input/touchscreen.inc index 4f1540f11..5a8e35481 100644 --- a/main/input/touchscreen.inc +++ b/main/input/touchscreen.inc @@ -24,14 +24,29 @@ static volatile bool shutdown_finished = false; esp_err_t _i2c_init_master(i2c_port_t port_num, int sda_io_num, int scl_io_num, i2c_master_bus_handle_t* handle); esp_err_t _i2c_deinit(i2c_master_bus_handle_t handle); +#ifdef CONFIG_BOARD_TYPE_WS_TOUCH_LCD35 +// The pmu shares these i2c pins and has no bus of its own - lend it ours for +// as long as it exists (see power/wslcdtouch35.inc) +void power_i2c_bus_attach(i2c_master_bus_handle_t bus); +void power_i2c_bus_detach(void); +#endif static void touchscreen_task(void* ignored) { esp_lcd_touch_handle_t ret_touch = NULL; // FIXME: check mirror flags? const esp_lcd_touch_config_t tp_cfg = { +#ifdef CONFIG_BOARD_TYPE_WS_TOUCH_LCD35 + // The panel is portrait-native (320x480) while the display is used in + // landscape. NOTE: esp_lcd_touch mirrors *before* swapping the axes, + // so these bounds are the panel's own axes, not the display's - and + // they include the virtual button strip below the gui area + .x_max = CONFIG_DISPLAY_HEIGHT + CONFIG_DISPLAY_OFFSET_Y + 40, + .y_max = CONFIG_DISPLAY_WIDTH + CONFIG_DISPLAY_OFFSET_X, +#else .x_max = CONFIG_DISPLAY_WIDTH + CONFIG_DISPLAY_OFFSET_X, .y_max = CONFIG_DISPLAY_HEIGHT + CONFIG_DISPLAY_OFFSET_Y, +#endif .rst_gpio_num = GPIO_NUM_NC, .int_gpio_num = GPIO_NUM_NC, .levels = { @@ -39,9 +54,17 @@ static void touchscreen_task(void* ignored) .interrupt = 0, }, .flags = { +#ifdef CONFIG_BOARD_TYPE_WS_TOUCH_LCD35 + // Verified on the hardware: display_x = panel_y and + // display_y = panel_max_x - panel_x + .swap_xy = 1, + .mirror_x = 1, + .mirror_y = 0, +#else .swap_xy = 0, .mirror_x = 0, .mirror_y = 0, +#endif }, }; @@ -49,6 +72,9 @@ static void touchscreen_task(void* ignored) ESP_ERROR_CHECK(_i2c_init_master( CONFIG_DISPLAY_TOUCHSCREEN_I2C, CONFIG_I2C_TOUCH_SDA, CONFIG_I2C_TOUCH_SCL, &touch_i2c_handle)); JADE_ASSERT(touch_i2c_handle); +#ifdef CONFIG_BOARD_TYPE_WS_TOUCH_LCD35 + power_i2c_bus_attach(touch_i2c_handle); +#endif esp_lcd_panel_io_handle_t tp_io_handle = NULL; esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CONFIG(); @@ -92,6 +118,9 @@ static void touchscreen_task(void* ignored) vTaskDelay(20 / portTICK_PERIOD_MS); } // Since IDF 5.5 the i2c bus cannot be deleted while devices are still attached +#ifdef CONFIG_BOARD_TYPE_WS_TOUCH_LCD35 + power_i2c_bus_detach(); +#endif ESP_ERROR_CHECK(esp_lcd_touch_del(ret_touch)); ESP_ERROR_CHECK(esp_lcd_panel_io_del(tp_io_handle)); ESP_ERROR_CHECK(_i2c_deinit(touch_i2c_handle)); diff --git a/main/power.c b/main/power.c index 1dd7624ba..d6f8d5b6a 100644 --- a/main/power.c +++ b/main/power.c @@ -27,6 +27,9 @@ #include "power/ip5306.inc" #elif defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) #include "power/wslcdtouch2.inc" +#elif defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD35) +// Waveshare Touch LCD 3.5 has AXP2101 +#include "power/wslcdtouch35.inc" #elif defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAYS3) // T-Display S3 can read battery level but lacks hardware to read charging status #include "power/tdisplays3.inc" diff --git a/main/power/wslcdtouch35.inc b/main/power/wslcdtouch35.inc new file mode 100644 index 000000000..37b975557 --- /dev/null +++ b/main/power/wslcdtouch35.inc @@ -0,0 +1,286 @@ +// Waveshare S3 Touch LCD 3.5 implementation +// Has an AXP2101 PMU and a TCA9554 io-expander which share the i2c pins with +// both the touch controller and the camera's sccb. +// As with the M5CoreS3, the bus is only held while configuring the pmu and is +// released immediately afterwards - otherwise the camera cannot drive the +// shared pins (esp_camera_init() blocks forever). +// +#include "power/i2c.inc" +#include +#include +#include +#include + +#include "button_gpio.h" +#include "iot_button.h" +#include "power.h" +#include "soc/gpio_num.h" +#include "tusb.h" + +#define AXP2101_ADDR 0x34 +#define TCA9554_ADDR 0x20 + +#define LCD_BL_LEDC_TIMER LEDC_TIMER_0 +#define LCD_BL_LEDC_MODE LEDC_LOW_SPEED_MODE + +#define LCD_BL_LEDC_CHANNEL LEDC_CHANNEL_0 +#define LCD_BL_LEDC_DUTY_RES LEDC_TIMER_10_BIT +#define LCD_BL_LEDC_DUTY (1024) +#define LCD_BL_LEDC_FREQUENCY (10000) + +static i2c_master_dev_handle_t axp2101 = NULL; +static i2c_master_dev_handle_t tca9554 = NULL; + +// The pmu shares the i2c pins with the touchscreen and the camera, so it +// cannot own a bus of its own. Instead the touchscreen code hands us its bus +// while it exists (see power_i2c_bus_attach()/power_i2c_bus_detach()) and we +// attach the pmu to it - the i2c driver serialises access between devices. +// While the bus is away (ie. the camera is in use) we report the last reading. +static SemaphoreHandle_t pmu_mutex = NULL; +static i2c_master_dev_handle_t axp2101_shared = NULL; +static uint16_t cached_vbat = 0; +static uint8_t cached_soc = 0; +static bool cached_charging = false; +static bool cached_vbus = true; + +void power_i2c_bus_attach(i2c_master_bus_handle_t bus) +{ + JADE_ASSERT(bus); + JADE_ASSERT(pmu_mutex); + xSemaphoreTake(pmu_mutex, portMAX_DELAY); + if (!axp2101_shared) { + const i2c_device_config_t cfg = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = AXP2101_ADDR, + .scl_speed_hz = CONFIG_I2C_MASTER_CLK }; + I2C_LOG_ANY_ERROR(i2c_master_bus_add_device(bus, &cfg, &axp2101_shared)); + } + xSemaphoreGive(pmu_mutex); +} + +void power_i2c_bus_detach(void) +{ + JADE_ASSERT(pmu_mutex); + xSemaphoreTake(pmu_mutex, portMAX_DELAY); + if (axp2101_shared) { + I2C_LOG_ANY_ERROR(i2c_master_bus_rm_device(axp2101_shared)); + axp2101_shared = NULL; + } + xSemaphoreGive(pmu_mutex); +} + +// Returns false (leaving 'out' untouched) if the bus is not currently ours +static bool pmu_read(const uint8_t reg, uint8_t* out, const size_t len) +{ + JADE_ASSERT(out); + if (!pmu_mutex) { + return false; + } + bool ok = false; + xSemaphoreTake(pmu_mutex, portMAX_DELAY); + if (axp2101_shared) { + ok = _power_master_read_slave(axp2101_shared, reg, out, len) == ESP_OK; + } + xSemaphoreGive(pmu_mutex); + return ok; +} + +static void tca9554_init(void) +{ + // Set expander pins P0 and P1 as outputs, drive both low, then release P1 + // (display/peripheral power sequencing - same sequence the vendor demo uses) + _power_write_command(tca9554, 0x03, 0xFC); + vTaskDelay(100 / portTICK_PERIOD_MS); + _power_write_command(tca9554, 0x01, 0x00); + vTaskDelay(100 / portTICK_PERIOD_MS); + _power_write_command(tca9554, 0x01, 0x02); +} + +static void axp2101_init(void) +{ + _power_write_command(axp2101, 0x22, 0x06); // PWRON > OFFLEVEL as POWEROFF source + _power_write_command(axp2101, 0x27, 0x10); // hold 4s to power off via PWRON + _power_write_command(axp2101, 0x80, 0x01); // disable all DCs except DC1 + _power_write_command(axp2101, 0x90, 0x00); // disable all LDOs + _power_write_command(axp2101, 0x91, 0x00); // disable all LDOs + _power_write_command(axp2101, 0x82, 0x12); // DC1 3.3v + _power_write_command(axp2101, 0x92, 0x1C); // ALDO1 3.3v + _power_write_command(axp2101, 0x96, 0x0A); // BLDO1 1.5v (camera DVDD) + _power_write_command(axp2101, 0x97, 0x17); // BLDO2 2.8v (camera AVDD) + _power_write_command(axp2101, 0x90, 0x31); // enable ALDO1, BLDO1, BLDO2 + _power_write_command(axp2101, 0x64, 0x02); // charge voltage 4.1v + _power_write_command(axp2101, 0x61, 0x02); // precharge current 50ma + _power_write_command(axp2101, 0x62, 0x0A); // charge current 400ma + _power_write_command(axp2101, 0x63, 0x01); // charge termination current 25ma + _power_write_command(axp2101, 0x30, 0x1D); // enable VBAT/VBUS/VSYS/TDIE adc +} + +static void button_shutdown(void* arg, void* ctx) +{ + power_backlight_off(); + while (gpio_get_level(GPIO_NUM_0) == 0) { + vTaskDelay(pdMS_TO_TICKS(10)); + } + power_shutdown(); +} + +static esp_err_t boot_button_init(void) +{ + const button_config_t btn_cfg = { + .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS, + .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS, + }; + const button_gpio_config_t btn_gpio_cfg = { + .gpio_num = 0, + .active_level = 0, + }; + button_handle_t btn_handle = NULL; + ESP_ERROR_CHECK(iot_button_new_gpio_device(&btn_cfg, &btn_gpio_cfg, &btn_handle)); + ESP_ERROR_CHECK(iot_button_register_cb(btn_handle, BUTTON_LONG_PRESS_HOLD, NULL, button_shutdown, NULL)); + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); + gpio_hold_en(GPIO_NUM_0); + gpio_deep_sleep_hold_en(); + esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0); + return ESP_OK; +} + +static esp_err_t brightness_init(void) +{ + gpio_reset_pin(CONFIG_DISPLAY_PIN_BL); + gpio_set_direction(CONFIG_DISPLAY_PIN_BL, GPIO_MODE_OUTPUT); + gpio_set_level(CONFIG_DISPLAY_PIN_BL, 1); + ledc_timer_config_t ledc_timer = { .speed_mode = LCD_BL_LEDC_MODE, + .timer_num = LCD_BL_LEDC_TIMER, + .duty_resolution = LCD_BL_LEDC_DUTY_RES, + .freq_hz = LCD_BL_LEDC_FREQUENCY, + .clk_cfg = LEDC_AUTO_CLK }; + ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); + ledc_channel_config_t ledc_channel = { .speed_mode = LCD_BL_LEDC_MODE, + .channel = LCD_BL_LEDC_CHANNEL, + .timer_sel = LCD_BL_LEDC_TIMER, + .intr_type = LEDC_INTR_DISABLE, + .gpio_num = CONFIG_DISPLAY_PIN_BL, + .duty = 0, + .hpoint = 0 }; + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + return ESP_OK; +} + +esp_err_t power_init(void) +{ + JADE_ASSERT(!pmu_mutex); + pmu_mutex = xSemaphoreCreateMutex(); + JADE_ASSERT(pmu_mutex); + + I2C_CHECK_RET(_power_i2c_init()); + I2C_CHECK_RET(_power_i2c_attach_device(TCA9554_ADDR, &tca9554)); + I2C_CHECK_RET(_power_i2c_attach_device(AXP2101_ADDR, &axp2101)); + + tca9554_init(); + axp2101_init(); + + vTaskDelay(100 / portTICK_PERIOD_MS); + // Release the bus so the touchscreen and the camera can drive these pins. + // Since IDF 5.5 the i2c bus cannot be deleted while devices are attached. + I2C_CHECK_RET(i2c_master_bus_rm_device(tca9554)); + I2C_CHECK_RET(i2c_master_bus_rm_device(axp2101)); + I2C_CHECK_RET(_i2c_deinit(NULL)); + + // Use the BOOT button as a sleep/wakeup button + ESP_ERROR_CHECK(boot_button_init()); + // Initialise backlight brightness + ESP_ERROR_CHECK(brightness_init()); + + return ESP_OK; +} + +esp_err_t power_shutdown(void) +{ + // NOTE: cannot use the pmu soft-poweroff as the i2c bus has been released + esp_deep_sleep_start(); +} + +esp_err_t power_screen_on(void) { return ESP_OK; } +esp_err_t power_screen_off(void) { return ESP_OK; } + +esp_err_t power_backlight_on(uint8_t brightness) +{ + if (brightness < BACKLIGHT_MIN) { + brightness = BACKLIGHT_MIN; + } else if (brightness > BACKLIGHT_MAX) { + brightness = BACKLIGHT_MAX; + } + const uint32_t duty = (brightness * (LCD_BL_LEDC_DUTY - 1)) / 5; + ESP_ERROR_CHECK(ledc_set_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL, duty)); + ESP_ERROR_CHECK(ledc_update_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL)); + return ESP_OK; +} + +esp_err_t power_backlight_off(void) +{ + ESP_ERROR_CHECK(ledc_set_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL, 0)); + ESP_ERROR_CHECK(ledc_update_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL)); + return ESP_OK; +} + +// Camera rails (BLDO1/BLDO2) are left enabled from power_init() +esp_err_t power_camera_on(void) { return ESP_OK; } +esp_err_t power_camera_off(void) { return ESP_OK; } + +uint16_t power_get_vbat(void) +{ + // 14-bit adc value split over two registers, lsb is 1mv + uint8_t buf[2] = { 0, 0 }; + if (pmu_read(0x34, buf, sizeof(buf))) { + cached_vbat = ((buf[0] & 0x3F) << 8) | buf[1]; + } + return cached_vbat; +} + +uint8_t power_get_battery_status(void) +{ + uint8_t soc = 0; + if (pmu_read(0xA4, &soc, sizeof(soc))) { + cached_soc = soc; + } + if (cached_soc > 90) { + return 5; + } else if (cached_soc > 70) { + return 4; + } else if (cached_soc > 50) { + return 3; + } else if (cached_soc > 30) { + return 2; + } else if (cached_soc > 10) { + return 1; + } + return 0; +} + +bool power_get_battery_charging(void) +{ + uint8_t status = 0; + if (pmu_read(0x01, &status, sizeof(status))) { + // status2 bits [6:5]: 01 = charging + cached_charging = ((status >> 5) & 0x03) == 0x01; + } + return cached_charging; +} + +uint16_t power_get_ibat_charge(void) { return 0; } +uint16_t power_get_ibat_discharge(void) { return 0; } +uint16_t power_get_vusb(void) { return 0; } +uint16_t power_get_iusb(void) { return 0; } +uint16_t power_get_temp(void) { return 0; } + +void disable_usb_host(void) {} +void enable_usb_host(void) {} + +bool usb_is_powered(void) +{ + uint8_t status = 0; + if (pmu_read(0x00, &status, sizeof(status))) { + // status1 bit 5: vbus present and good + cached_vbus = (status & (1 << 5)) != 0; + } + return cached_vbus; +} diff --git a/main/process/dashboard.c b/main/process/dashboard.c index 56cba90dd..fb1e3c6a3 100644 --- a/main/process/dashboard.c +++ b/main/process/dashboard.c @@ -1703,8 +1703,8 @@ static void handle_view_otps(void) // NOTE: Only boards listed here have brightness controls #if defined(CONFIG_BOARD_TYPE_JADE_V1_1) || defined(CONFIG_BOARD_TYPE_JADE_V2_ANY) \ - || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) \ - || defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2) + || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD35) \ + || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) || defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2) static void handle_screen_brightness(void) { static const char* LABELS[] = { "Min(1)", "Low(2)", "Medium(3)", "High(4)", "Max(5)" }; @@ -2061,6 +2061,12 @@ static void handle_display_battery_volts(void) const int ret = snprintf(power_status, sizeof(power_status), "%umv", vbat); JADE_ASSERT(ret > 0 && ret < sizeof(power_status)); } +#elif defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD35) + const uint16_t vbat = power_get_vbat(); // pmu adc value already in mv + if (vbat > 0) { + const int ret = snprintf(power_status, sizeof(power_status), "%umv", vbat); + JADE_ASSERT(ret > 0 && ret < sizeof(power_status)); + } #elif defined(CONFIG_HAS_IP5306) const float approx_voltage = power_get_vbat() / 1000.0; const int ret = snprintf(power_status, sizeof(power_status), "Approx %.1fv", approx_voltage); @@ -2291,8 +2297,8 @@ static void handle_settings(const bool startup_menu) // NOTE: Only boards listed here have brightness controls #if defined(CONFIG_BOARD_TYPE_JADE_V1_1) || defined(CONFIG_BOARD_TYPE_JADE_V2_ANY) \ - || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) \ - || defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2) + || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD35) \ + || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) || defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2) case BTN_SETTINGS_DISPLAY_BRIGHTNESS: handle_screen_brightness(); break; diff --git a/main/process/ota_defines.h b/main/process/ota_defines.h index bb1541232..86f12fdff 100644 --- a/main/process/ota_defines.h +++ b/main/process/ota_defines.h @@ -47,6 +47,8 @@ #define JADE_OTA_BOARD_TYPE "TTGO_TDISPLAYS3PROCAMERA" #elif defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) #define JADE_OTA_BOARD_TYPE "WAVESHARE_TOUCH_LCD2" +#elif defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD35) +#define JADE_OTA_BOARD_TYPE "WAVESHARE_TOUCH_LCD35" #elif defined(CONFIG_BOARD_TYPE_QEMU) || defined(CONFIG_BOARD_TYPE_QEMU_LARGER) #define JADE_OTA_BOARD_TYPE "QEMU" #else diff --git a/main/ui/dashboard.c b/main/ui/dashboard.c index 2001468c3..473dd132c 100644 --- a/main/ui/dashboard.c +++ b/main/ui/dashboard.c @@ -395,7 +395,8 @@ gui_activity_t* make_display_settings_activity(void) // NOTE: Only boards listed here have brightness controls // NOTE: Jade v1.1's do not support Flip Orientation because of issues with screen offsets #if defined(CONFIG_BOARD_TYPE_JADE_V2_ANY) || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) \ - || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) || defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2) + || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD35) || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) \ + || defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2) btn_data_t menubtns[] = { { .txt = "Display Brightness", .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_BRIGHTNESS }, { .txt = "Flip Orientation", .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_ORIENTATION },