diff --git a/boards/hosyond-es3c28p/audio.yaml b/boards/hosyond-es3c28p/audio.yaml new file mode 100644 index 0000000..b4b2d53 --- /dev/null +++ b/boards/hosyond-es3c28p/audio.yaml @@ -0,0 +1,54 @@ +# Copyright 2025 Vinicius Fortuna +# SPDX-License-Identifier: Apache-2.0 + +# Audio codec: ES8311 (I2C control + I2S data), shared I2C bus on GPIO15/16 +# Amplifier: FM8002E, enabled via GPIO1 (active low) +# Microphone: MEMS LMA2718B381 (via ES8311 ADC) +# Speaker connector: 1.25mm 2P + +i2s_audio: + - id: i2s_audio_bus + i2s_mclk_pin: GPIO4 # MCLK + i2s_bclk_pin: GPIO5 # BCLK + i2s_lrclk_pin: GPIO7 # LRCK + +audio_dac: + - id: es8311_dac + platform: es8311 + i2c_id: i2c_bus + use_microphone: true + bits_per_sample: 16bit + sample_rate: 48000 + +# TODO(fortuna): I haven't validated the microphone config yet. +microphone: + - id: main_microphone + platform: i2s_audio + i2s_audio_id: i2s_audio_bus + i2s_din_pin: GPIO6 # ASDOUT from Codec -> I2S_DI on ESP32 + adc_type: external + bits_per_sample: 16bit + sample_rate: 48000 + +speaker: + - id: main_speaker + platform: i2s_audio + i2s_audio_id: i2s_audio_bus + i2s_dout_pin: GPIO8 # I2S_DO from ESP32 -> DSDIN on Codec + dac_type: external + audio_dac: es8311_dac + bits_per_sample: 16bit + sample_rate: 48000 + channel: mono + +switch: + # FM8002E amplifier enable — must be on (low) to hear speaker output + - id: enable_speaker_amp + platform: gpio + name: Enable Speaker + pin: + number: GPIO1 + inverted: true # Active low + restore_mode: RESTORE_DEFAULT_ON + entity_category: config + disabled_by_default: true diff --git a/boards/hosyond-es3c28p/board.yaml b/boards/hosyond-es3c28p/board.yaml new file mode 100644 index 0000000..507dd94 --- /dev/null +++ b/boards/hosyond-es3c28p/board.yaml @@ -0,0 +1,73 @@ +# Copyright 2025 Vinicius Fortuna +# SPDX-License-Identifier: Apache-2.0 + +# Hosyond ES3C28P — 2.8" 240×320 IPS TFT ESP32-S3 display board with capacitive touch +# +# References: +# - https://hosyond.com/ +# - https://www.lcdwiki.com/2.8inch_ESP32-S3_Display +# - Schematic: https://www.lcdwiki.com/res/ES3C28P/2.8inch_ESP32-S3_Display_Schematic.pdf +# - User manual: https://www.lcdwiki.com/res/ES3C28P/2.8inch_IPS_ESP32-S3_ES3C28P_ES3N28P_User_Manual.pdf + +packages: + display: !include ./display.yaml + audio: !include ./audio.yaml + +esp32: + board: esp32-s3-devkitc-1 + flash_size: 16MB + framework: + type: esp-idf + +psram: + mode: octal + speed: 80MHz + +# SPI bus — shared by the ILI9341 display +spi: + - id: spi_bus + clk_pin: GPIO12 # LCD_CLK + mosi_pin: GPIO11 # LCD_MOSI + miso_pin: GPIO13 # LCD_MISO + +# I2C bus — shared by FT6336 touch controller and ES8311 audio codec +i2c: + - id: i2c_bus + scl: GPIO15 + sda: GPIO16 + scan: true + frequency: 400kHz + +# NOTE: ESPHome does not yet implement sd_mmc_card. Uncomment once supported: +# SD card (SDIO 4-bit): CLK=IO38, CMD=IO40, D0=IO39, D1=IO41, D2=IO48, D3=IO47 +# +# sd_mmc_card: +# id: sd_card +# clk_pin: GPIO38 +# cmd_pin: GPIO40 +# data0_pin: GPIO39 +# data1_pin: GPIO41 +# data2_pin: GPIO48 +# data3_pin: GPIO47 +# mode_1bit: false + +binary_sensor: + - id: boot_button + platform: gpio + name: Boot Button + pin: + number: GPIO0 + inverted: true + mode: + input: true + pullup: true + +sensor: + - id: battery_voltage + platform: adc + pin: GPIO9 + name: Battery Voltage + attenuation: 12dB + update_interval: 60s + filters: + - multiply: 2.0 # Voltage divider on the ADC pin diff --git a/boards/hosyond-es3c28p/demo.yaml b/boards/hosyond-es3c28p/demo.yaml new file mode 100644 index 0000000..b3d99e1 --- /dev/null +++ b/boards/hosyond-es3c28p/demo.yaml @@ -0,0 +1,175 @@ +# Copyright 2025 Vinicius Fortuna +# SPDX-License-Identifier: Apache-2.0 + +packages: + board: !include ./board.yaml + +esphome: + name: hosyond-es3c28p-demo + friendly_name: Hosyond ES3C28P Demo + on_boot: + priority: -100 + then: + - switch.turn_on: enable_speaker_amp + - delay: 500ms + # Set a reasonable default volume + - speaker.volume_set: + id: main_speaker + volume: 0.5 + - light.turn_on: + id: status_led + red: 0% + green: 100% + blue: 0% + brightness: 50% + - rtttl.play: "boot:d=1,o=4,b=60:c" + +logger: + +rtttl: + speaker: main_speaker + gain: 0.2 + +# Boot button: play a sound and toggle LED +binary_sensor: + - id: !extend boot_button + on_press: + - light.toggle: status_led + - rtttl.play: "click:d=8,o=5,b=160:c6,e6" + +# Update battery label when ADC fires +sensor: + - id: !extend battery_voltage + on_value: + - lvgl.label.update: + id: battery_label + text: + format: "%.2fV" + args: [x] + +lvgl: + displays: [main_display] + touchscreens: [main_touchscreen] + pages: + - id: main_page + widgets: + - label: + align: top_mid + y: 8 + text: "ES3C28P Demo" + - label: + id: battery_label + align: top_right + x: -8 + y: 8 + text: "--V" + + - label: + x: 8 + y: 52 + text: "R" + - slider: + id: red_slider + x: 28 + y: 42 + width: 190 + min_value: 0 + max_value: 255 + on_value: + - light.turn_on: + id: status_led + red: !lambda "return lv_slider_get_value(id(red_slider)) / 255.0f;" + green: !lambda "return lv_slider_get_value(id(green_slider)) / 255.0f;" + blue: !lambda "return lv_slider_get_value(id(blue_slider)) / 255.0f;" + brightness: 1.0 + + - label: + x: 8 + y: 102 + text: "G" + - slider: + id: green_slider + x: 28 + y: 92 + width: 190 + min_value: 0 + max_value: 255 + on_value: + - light.turn_on: + id: status_led + red: !lambda "return lv_slider_get_value(id(red_slider)) / 255.0f;" + green: !lambda "return lv_slider_get_value(id(green_slider)) / 255.0f;" + blue: !lambda "return lv_slider_get_value(id(blue_slider)) / 255.0f;" + brightness: 1.0 + + - label: + x: 8 + y: 152 + text: "B" + - slider: + id: blue_slider + x: 28 + y: 142 + width: 190 + min_value: 0 + max_value: 255 + on_value: + - light.turn_on: + id: status_led + red: !lambda "return lv_slider_get_value(id(red_slider)) / 255.0f;" + green: !lambda "return lv_slider_get_value(id(green_slider)) / 255.0f;" + blue: !lambda "return lv_slider_get_value(id(blue_slider)) / 255.0f;" + brightness: 1.0 + + - label: + x: 8 + y: 202 + text: "BL" + - slider: + id: backlight_slider + x: 28 + y: 192 + width: 190 + min_value: 0 + max_value: 100 + value: 100 + on_value: + - light.turn_on: + id: display_backlight_light + brightness: !lambda "return lv_slider_get_value(id(backlight_slider)) / 100.0f;" + + - label: + x: 8 + y: 255 + text: "Amp" + - switch: + id: amp_ui_switch + x: 44 + y: 248 + state: + checked: true + on_click: + - if: + condition: + lambda: 'return lv_obj_has_state(id(amp_ui_switch), LV_STATE_CHECKED);' + then: + - switch.turn_on: enable_speaker_amp + else: + - switch.turn_off: enable_speaker_amp + - button: + id: sound_btn + x: 130 + y: 242 + width: 100 + height: 36 + on_click: + - rtttl.play: "ui:d=8,o=5,b=160:e6,g6" + widgets: + - label: + align: center + text: "Sound" + + - label: + align: bottom_mid + y: -8 + text: "Boot btn: toggle LED + sound" diff --git a/boards/hosyond-es3c28p/display.yaml b/boards/hosyond-es3c28p/display.yaml new file mode 100644 index 0000000..eedf888 --- /dev/null +++ b/boards/hosyond-es3c28p/display.yaml @@ -0,0 +1,52 @@ +# Copyright 2025 Vinicius Fortuna +# SPDX-License-Identifier: Apache-2.0 + +# Display: ILI9341V, 2.8" IPS TFT, 240×320, SPI +# Touch: FT6336G capacitive, I2C +# RGB LED: WS2812B on GPIO42 + +output: + - id: display_backlight + platform: ledc + pin: GPIO45 # LCD_BL (active high) + +light: + - id: display_backlight_light + platform: monochromatic + name: Display Backlight + icon: "mdi:television" + entity_category: config + output: display_backlight + restore_mode: RESTORE_DEFAULT_ON + default_transition_length: 0ms + + - id: status_led + platform: esp32_rmt_led_strip + name: Status LED + pin: GPIO42 # WS2812B + num_leds: 1 + rgb_order: GRB + chipset: WS2812 + +display: + - id: main_display + platform: ili9xxx + model: ILI9341 + spi_id: spi_bus + cs_pin: GPIO10 # LCD_CS + dc_pin: GPIO46 # LCD_DC + # RST is tied to the EN (system reset) pin; no software reset available. + invert_colors: false + data_rate: 40MHz + update_interval: never + auto_clear_enabled: false + +touchscreen: + - id: main_touchscreen + platform: ft63x6 + i2c_id: i2c_bus + display: main_display + interrupt_pin: GPIO17 # Touch IRQ (active low) + # RST is active low. ESPHome ft63x6 drives the pin LOW then HIGH to reset, + # so inverted must NOT be set (that would leave the chip held in reset). + reset_pin: GPIO18 diff --git a/boards/hosyond-es3c28p/docs/2.8inch_ESP32-S3_Display_Schematic.pdf b/boards/hosyond-es3c28p/docs/2.8inch_ESP32-S3_Display_Schematic.pdf new file mode 100644 index 0000000..005c576 Binary files /dev/null and b/boards/hosyond-es3c28p/docs/2.8inch_ESP32-S3_Display_Schematic.pdf differ diff --git a/boards/hosyond-es3c28p/docs/2.8inch_IPS_ESP32-S3_ES3C28P_ES3N28P_User_Manual.pdf b/boards/hosyond-es3c28p/docs/2.8inch_IPS_ESP32-S3_ES3C28P_ES3N28P_User_Manual.pdf new file mode 100644 index 0000000..814c97b Binary files /dev/null and b/boards/hosyond-es3c28p/docs/2.8inch_IPS_ESP32-S3_ES3C28P_ES3N28P_User_Manual.pdf differ diff --git a/boards/hosyond-es3c28p/docs/ES3C28P_ES2N28P_Specification_V1.0.pdf b/boards/hosyond-es3c28p/docs/ES3C28P_ES2N28P_Specification_V1.0.pdf new file mode 100644 index 0000000..6595889 Binary files /dev/null and b/boards/hosyond-es3c28p/docs/ES3C28P_ES2N28P_Specification_V1.0.pdf differ