diff --git a/boards/espressif/esp32c6_devkitc/Kconfig b/boards/espressif/esp32c6_devkitc/Kconfig index c6a99b1032dc..e24ba970a9bb 100644 --- a/boards/espressif/esp32c6_devkitc/Kconfig +++ b/boards/espressif/esp32c6_devkitc/Kconfig @@ -3,4 +3,5 @@ config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 4096 + default 4096 if BOARD_ESP32C6_DEVKITC_ESP32C6_HPCORE + default 256 if BOARD_ESP32C6_DEVKITC_ESP32C6_LPCORE diff --git a/boards/espressif/esp32c6_devkitc/Kconfig.esp32c6_devkitc b/boards/espressif/esp32c6_devkitc/Kconfig.esp32c6_devkitc index 4bd1fce4efc3..9b30251fea4f 100644 --- a/boards/espressif/esp32c6_devkitc/Kconfig.esp32c6_devkitc +++ b/boards/espressif/esp32c6_devkitc/Kconfig.esp32c6_devkitc @@ -5,3 +5,5 @@ config BOARD_ESP32C6_DEVKITC select SOC_ESP32_C6_WROOM_1U_N8 + select SOC_ESP32C6_HPCORE if BOARD_ESP32C6_DEVKITC_ESP32C6_HPCORE + select SOC_ESP32C6_LPCORE if BOARD_ESP32C6_DEVKITC_ESP32C6_LPCORE diff --git a/boards/espressif/esp32c6_devkitc/doc/index.rst b/boards/espressif/esp32c6_devkitc/doc/index.rst index ab81b187d746..99d0de5a2de5 100644 --- a/boards/espressif/esp32c6_devkitc/doc/index.rst +++ b/boards/espressif/esp32c6_devkitc/doc/index.rst @@ -183,7 +183,7 @@ To build the sample application using sysbuild use the command: .. zephyr-app-commands:: :tool: west :zephyr-app: samples/hello_world - :board: esp32c6_devkitc + :board: esp32c6_devkitc/esp32c6/hpcore :goals: build :west-args: --sysbuild :compact: @@ -232,7 +232,7 @@ Build and flash applications as usual (see :ref:`build_an_application` and .. zephyr-app-commands:: :zephyr-app: samples/hello_world - :board: esp32c6_devkitc + :board: esp32c6_devkitc/esp32c6/hpcore :goals: build The usual ``flash`` target will work with the ``esp32c6_devkitc`` board @@ -241,7 +241,7 @@ application. .. zephyr-app-commands:: :zephyr-app: samples/hello_world - :board: esp32c6_devkitc + :board: esp32c6_devkitc/esp32c6/hpcore :goals: flash Open the serial monitor using the following command: @@ -256,7 +256,7 @@ message in the monitor: .. code-block:: console ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! esp32c6_devkitc + Hello World! esp32c6_devkitc/esp32c6/hpcore Debugging ********* @@ -273,7 +273,7 @@ Here is an example for building the :zephyr:code-sample:`hello_world` applicatio .. zephyr-app-commands:: :zephyr-app: samples/hello_world - :board: esp32c6_devkitc + :board: esp32c6_devkitc/esp32c6/hpcore :goals: build flash :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= @@ -281,9 +281,32 @@ You can debug an application in the usual way. Here is an example for the :zephy .. zephyr-app-commands:: :zephyr-app: samples/hello_world - :board: esp32c6_devkitc + :board: esp32c6_devkitc/esp32c6/hpcore :goals: debug +Low-Power CPU (LP CORE) +*********************** + +The ESP32-C6 SoC has two RISC-V cores: the High-Performance Core (HP CORE) and the Low-Power Core (LP CORE). +It features ultra low power consumption, an interrupt controller, a debug module and a system bus +interface for memory and peripheral access. + +The LP Core is in sleep mode by default. It has two application scenarios: + +- Power insensitive scenario: When the High-Performance CPU (HP Core) is active, the LP Core can assist the HP CPU with some speed and efficiency-insensitive controls and computations. +- Power sensitive scenario: When the HP CPU is in the power-down state to save power, the LP Core can be woken up to handle some external wake-up events. + +For more information, check the datasheet at `ESP32-C6 Datasheet`_ or the technical reference +manual at `ESP32-C6 Technical Reference Manual`_. + +The LP Core support is fully integrated with :ref:`sysbuild`. The user can enable the LP Core by adding +the following configuration to the project: + +.. code:: cfg + + CONFIG_ULP_COPROC_ENABLED=y + +See :zephyr:code-sample-category:`lp-core` folder as code reference. References ********** diff --git a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc-pinctrl.dtsi b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore-pinctrl.dtsi similarity index 100% rename from boards/espressif/esp32c6_devkitc/esp32c6_devkitc-pinctrl.dtsi rename to boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore-pinctrl.dtsi diff --git a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc.dts b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore.dts similarity index 93% rename from boards/espressif/esp32c6_devkitc/esp32c6_devkitc.dts rename to boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore.dts index 896ae30530cc..03b8a94e092d 100644 --- a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc.dts +++ b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore.dts @@ -7,12 +7,12 @@ /dts-v1/; #include -#include "esp32c6_devkitc-pinctrl.dtsi" +#include "esp32c6_devkitc_hpcore-pinctrl.dtsi" #include #include / { - model = "esp32c6_devkitc"; + model = "esp32c6_devkitc HP Core"; compatible = "espressif,esp32c6"; chosen { diff --git a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc.yaml b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore.yaml similarity index 69% rename from boards/espressif/esp32c6_devkitc/esp32c6_devkitc.yaml rename to boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore.yaml index 95385596d9de..2427b407845a 100644 --- a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc.yaml +++ b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore.yaml @@ -1,5 +1,5 @@ -identifier: esp32c6_devkitc -name: ESP32-C6 +identifier: esp32c6_devkitc/esp32c6/hpcore +name: ESP32-C6-DevKitC HP Core vendor: espressif type: mcu arch: riscv diff --git a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_defconfig b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore_defconfig similarity index 100% rename from boards/espressif/esp32c6_devkitc/esp32c6_devkitc_defconfig rename to boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore_defconfig diff --git a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore.dts b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore.dts new file mode 100644 index 000000000000..0d45b9087ec3 --- /dev/null +++ b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore.dts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include + +/ { + model = "Espressif ESP32C6-DevkitC LPCORE"; + compatible = "espressif,esp32c6"; + + chosen { + zephyr,sram = &sramlp; + zephyr,code-partition = &slot0_lpcore_partition; + zephyr,console = &lp_uart; + zephyr,shell-uart = &lp_uart; + }; + + // aliases { + // sw0 = &user_button1; + // }; + + // gpio_keys { + // compatible = "gpio-keys"; + // user_button1: button_1 { + // label = "User SW1"; + // gpios = <&lp_gpio 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + // zephyr,code = ; + // }; + // }; +}; + +&lp_uart { + status = "okay"; + current-speed = <115200>; +}; diff --git a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore.yaml b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore.yaml new file mode 100644 index 000000000000..aabe40164d5f --- /dev/null +++ b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore.yaml @@ -0,0 +1,16 @@ +identifier: esp32c6_devkitc/esp32c6/lpcore +name: ESP32-C6-DevKitC LP Core +type: mcu +arch: riscv +toolchain: + - zephyr +supported: + - cpu +testing: + only_tags: + - introduction + ignore_tags: + - kernel + - posix + - chre +vendor: espressif diff --git a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore_defconfig b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore_defconfig new file mode 100644 index 000000000000..7bb046103089 --- /dev/null +++ b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore_defconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_MAIN_STACK_SIZE=1024 +CONFIG_ISR_STACK_SIZE=64 +CONFIG_IDLE_STACK_SIZE=32 + +# Memory protection +CONFIG_THREAD_STACK_INFO=n +CONFIG_THREAD_CUSTOM_DATA=n + +# Boot +CONFIG_BOOT_BANNER=n + +# Console +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_PRINTK=n +CONFIG_CBPRINTF_NANO=y + +# Build +CONFIG_SIZE_OPTIMIZATIONS=y +CONFIG_BUSYWAIT_CPU_LOOPS_PER_USEC=4 diff --git a/drivers/clock_control/clock_control_esp32.c b/drivers/clock_control/clock_control_esp32.c index 902f186c10e5..6ee615b9bbab 100644 --- a/drivers/clock_control/clock_control_esp32.c +++ b/drivers/clock_control/clock_control_esp32.c @@ -105,7 +105,8 @@ static void esp32_clock_perip_init(void) soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); if ((rst_reason != RESET_REASON_CPU0_MWDT0) && (rst_reason != RESET_REASON_CPU0_MWDT1) && - (rst_reason != RESET_REASON_CPU0_SW) && (rst_reason != RESET_REASON_CPU0_RTC_WDT)) { + (rst_reason != RESET_REASON_CPU0_SW) && (rst_reason != RESET_REASON_CPU0_RTC_WDT) && + (rst_reason != RESET_REASON_CPU0_JTAG)) { periph_ll_disable_clk_set_rst(PERIPH_UART1_MODULE); periph_ll_disable_clk_set_rst(PERIPH_I2C0_MODULE); diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 6ed5384f03d5..134bf6c9f4ca 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -115,6 +115,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_XEC_V2 gpio_mchp_xec_v2.c) zephyr_library_sources_ifdef(CONFIG_GPIO_XLNX_AXI gpio_xlnx_axi.c) zephyr_library_sources_ifdef(CONFIG_GPIO_XLNX_PS gpio_xlnx_ps.c gpio_xlnx_ps_bank.c) zephyr_library_sources_ifdef(CONFIG_GPIO_XMC4XXX gpio_xmc4xxx.c) +zephyr_library_sources_ifdef(CONFIG_LPGPIO_ESP32 gpio_esp32_lpgpio.c) # zephyr-keep-sorted-stop # zephyr-keep-sorted-start diff --git a/drivers/gpio/Kconfig.esp32 b/drivers/gpio/Kconfig.esp32 index b04f6cd5e0ac..3ed9039bd50e 100644 --- a/drivers/gpio/Kconfig.esp32 +++ b/drivers/gpio/Kconfig.esp32 @@ -6,6 +6,13 @@ config GPIO_ESP32 bool "ESP32 GPIO" default y - depends on DT_HAS_ESPRESSIF_ESP32_GPIO_ENABLED + depends on DT_HAS_ESPRESSIF_ESP32_GPIO_ENABLED && !SOC_ESP32C6_LPCORE + help + Enables the ESP32 GPIO driver + +config LPGPIO_ESP32 + bool "ESP32 Low Power GPIO" + default y + depends on DT_HAS_ESPRESSIF_ESP32_GPIO_ENABLED && SOC_ESP32C6_LPCORE help Enables the ESP32 GPIO driver diff --git a/drivers/gpio/gpio_esp32_lpgpio.c b/drivers/gpio/gpio_esp32_lpgpio.c new file mode 100644 index 000000000000..c05148e09b52 --- /dev/null +++ b/drivers/gpio/gpio_esp32_lpgpio.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT espressif_esp32_lpgpio + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(gpio_esp32, CONFIG_LOG_DEFAULT_LEVEL); + +struct lp_gpio_esp32_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config drv_cfg; + lp_io_dev_t *const lp_io_dev; +}; + +struct lp_gpio_esp32_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + sys_slist_t cb; +}; + +void ulp_lp_core_lp_io_intr_handler(void) +{ + uint32_t intr_status = rtcio_ll_get_interrupt_status(); + const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(lp_gpio)); + struct lp_gpio_esp32_data *data = dev->data; + + rtcio_ll_clear_interrupt_status(); + printf("ulp_lp_core_lp_io_intr_handler\n"); + gpio_fire_callbacks(&data->cb, dev, intr_status); +} + +bool lp_gpio_is_valid(uint32_t pin) +{ + return rtc_io_num_map[pin] > 0; +} + +static int lp_gpio_esp32_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + int rtc_io_num = rtc_io_num_map[pin]; + + if (rtc_io_num < 0) { + LOG_ERR("Selected LP IO pin is not valid."); + return -EINVAL; + } + + rtcio_hal_function_select(rtc_io_num, RTCIO_FUNC_RTC); + + if (flags & GPIO_OUTPUT) { + rtcio_hal_set_direction(rtc_io_num, RTC_GPIO_MODE_OUTPUT_ONLY); + if (flags & GPIO_OUTPUT_INIT_HIGH) { + rtcio_hal_set_level(rtc_io_num, 1); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + rtcio_hal_set_level(rtc_io_num, 0); + } + } else if (flags & GPIO_INPUT) { + rtcio_hal_set_direction(rtc_io_num, RTC_GPIO_MODE_INPUT_ONLY); + } + + return 0; +} + +static int lp_gpio_esp32_port_get_raw(const struct device *port, uint32_t *value) +{ + const struct lp_gpio_esp32_config *const cfg = port->config; + + *value = cfg->lp_io_dev->in.val; + + return 0; +} + +static int lp_gpio_esp32_port_set_masked_raw(const struct device *port, uint32_t mask, + uint32_t value) +{ + const struct lp_gpio_esp32_config *const cfg = port->config; + + cfg->lp_io_dev->out_data.val = (cfg->lp_io_dev->out_data.val & ~mask) | (mask & value); + return 0; +} + +static int lp_gpio_esp32_port_set_bits_raw(const struct device *port, uint32_t pins) +{ + const struct lp_gpio_esp32_config *const cfg = port->config; + + cfg->lp_io_dev->out_data_w1ts.val = pins; + return 0; +} + +static int lp_gpio_esp32_port_clear_bits_raw(const struct device *port, + uint32_t pins) +{ + const struct lp_gpio_esp32_config *const cfg = port->config; + + cfg->lp_io_dev->out_data_w1tc.val = pins; + return 0; +} + +static int lp_gpio_esp32_port_toggle_bits(const struct device *port, + uint32_t pins) +{ + const struct lp_gpio_esp32_config *const cfg = port->config; + + cfg->lp_io_dev->out_data.val ^= pins; + return 0; +} + +static int lp_gpio_convert_int_type(enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + if (mode == GPIO_INT_MODE_DISABLED) { + return RTCIO_INTR_DISABLE; + } + + if (mode == GPIO_INT_MODE_LEVEL) { + switch (trig) { + case GPIO_INT_TRIG_LOW: + return RTCIO_INTR_LOW_LEVEL; + case GPIO_INT_TRIG_HIGH: + return RTCIO_INTR_HIGH_LEVEL; + default: + return -EINVAL; + } + } else { /* edge interrupts */ + switch (trig) { + case GPIO_INT_TRIG_HIGH: + return RTCIO_INTR_POSEDGE; + case GPIO_INT_TRIG_LOW: + return RTCIO_INTR_NEGEDGE; + case GPIO_INT_TRIG_BOTH: + return RTCIO_INTR_ANYEDGE; + default: + return -EINVAL; + } + } + + /* Any other type of interrupt triggering is invalid. */ + return -EINVAL; +} + +static int lp_gpio_esp32_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + int intr_trig_mode = lp_gpio_convert_int_type(mode, trig); + int rtc_io_num = rtc_io_num_map[pin]; + + if (rtc_io_num > 0) { + LOG_ERR("Selected LP IO pin is not valid."); + return -EINVAL; + } + + rtcio_ll_clear_interrupt_status(); + ulp_lp_core_intr_enable(); + + rtcio_ll_intr_enable(rtc_io_num, intr_trig_mode); + + return 0; +} + +static int lp_gpio_esp32_manage_callback(const struct device *dev, struct gpio_callback *callback, + bool set) +{ + struct lp_gpio_esp32_data *data = dev->data; + + return gpio_manage_callback(&data->cb, callback, set); +} + +static uint32_t lp_gpio_esp32_get_pending_int(const struct device *dev) +{ + ARG_UNUSED(dev); + + return rtcio_ll_get_interrupt_status(); +} + +static int lp_gpio_esp32_init(const struct device *dev) +{ + return 0; +} + +static DEVICE_API(gpio, lp_gpio_esp32_driver_api) = { + .pin_configure = lp_gpio_esp32_configure, + .port_get_raw = lp_gpio_esp32_port_get_raw, + .port_set_masked_raw = lp_gpio_esp32_port_set_masked_raw, + .port_set_bits_raw = lp_gpio_esp32_port_set_bits_raw, + .port_clear_bits_raw = lp_gpio_esp32_port_clear_bits_raw, + .port_toggle_bits = lp_gpio_esp32_port_toggle_bits, + .pin_interrupt_configure = lp_gpio_esp32_pin_interrupt_configure, + .manage_callback = lp_gpio_esp32_manage_callback, + .get_pending_int = lp_gpio_esp32_get_pending_int +}; + +static struct lp_gpio_esp32_data lp_gpio_esp32_data; +static struct lp_gpio_esp32_config lp_gpio_esp32_cfg = { + .drv_cfg = + { + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_NODE(DT_NODELABEL(lp_gpio)), + }, + .lp_io_dev = (lp_io_dev_t *)DT_REG_ADDR(DT_NODELABEL(lp_gpio)), +}; + +DEVICE_DT_DEFINE(DT_NODELABEL(lp_gpio), lp_gpio_esp32_init, NULL, &lp_gpio_esp32_data, + &lp_gpio_esp32_cfg, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, + &lp_gpio_esp32_driver_api); diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 05ef5c3bdfcd..c201114c688c 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -15,6 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_USB_CDC_ACM ${ZEPHYR_BASE}/misc/empty_file.c # zephyr-keep-sorted-start zephyr_library_sources_ifdef(CONFIG_LEUART_GECKO leuart_gecko.c) +zephyr_library_sources_ifdef(CONFIG_LPUART_ESP32 lpuart_esp32.c) zephyr_library_sources_ifdef(CONFIG_SERIAL_ESP32_USB serial_esp32_usb.c) zephyr_library_sources_ifdef(CONFIG_UART_ALTERA uart_altera.c) zephyr_library_sources_ifdef(CONFIG_UART_ALTERA_JTAG uart_altera_jtag.c) diff --git a/drivers/serial/Kconfig.esp32 b/drivers/serial/Kconfig.esp32 index 83dcc3f87802..e4ea9b5d6eee 100644 --- a/drivers/serial/Kconfig.esp32 +++ b/drivers/serial/Kconfig.esp32 @@ -43,3 +43,11 @@ config UART_ESP32_RX_FIFO_THRESH range 1 127 help Configure the RX FIFO threshold for ESP32 UART driver. + +config LPUART_ESP32 + bool "ESP32 LP UART driver" + default y + depends on DT_HAS_ESPRESSIF_ESP32_LPUART_ENABLED + select SERIAL_HAS_DRIVER + help + Enable the ESP32 LP UART. diff --git a/drivers/serial/lpuart_esp32.c b/drivers/serial/lpuart_esp32.c new file mode 100644 index 000000000000..620bd707f82b --- /dev/null +++ b/drivers/serial/lpuart_esp32.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT espressif_esp32_lpuart + +#include +#include + +#include +#if defined(CONFIG_SOC_ESP32C6_HPCORE) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#define ESP_LP_UART_TX_IDLE_NUM_DEFAULT (0U) + +struct lp_uart_esp32_data { + uart_hal_context_t hal; +}; + +struct lp_uart_esp32_config { + uint8_t tx_io_num; + uint8_t rx_io_num; + uint8_t rts_io_num; + uint8_t cts_io_num; + int baud_rate; + uint8_t data_bits; + uint8_t parity; + uint8_t stop_bits; + uint8_t flow_ctrl; + uint8_t rx_flow_ctrl_thresh; + uint8_t lp_uart_source_clk; +}; + +static int lp_uart_esp32_poll_in(const struct device *dev, unsigned char *p_char) +{ + struct lp_uart_esp32_data *data = dev->data; + int inout_rd_len = 1; + + if (uart_hal_get_rxfifo_len(&data->hal) == 0) { + return -1; + } + + uart_hal_read_rxfifo(&data->hal, p_char, &inout_rd_len); + + return 0; +} + +static void lp_uart_esp32_poll_out(const struct device *dev, unsigned char c) +{ + struct lp_uart_esp32_data *data = dev->data; + int tx_len = 0; + int loop_cnt = 0; + + /* Write one byte to LP UART. Break after few iterations if we are stuck for any reason. */ + while (tx_len != 1 && loop_cnt < 1000) { + uart_hal_write_txfifo(&data->hal, (const void *)&c, 1, &tx_len); + loop_cnt++; + } +} + +#if defined(CONFIG_SOC_ESP32C6_HPCORE) + +static int lp_uart_esp32_param_config(const struct device *dev) +{ + const struct lp_uart_esp32_config *const cfg = dev->config; + struct lp_uart_esp32_data *data = dev->data; + uint32_t sclk_freq = 0; + + if ((cfg->rx_flow_ctrl_thresh > SOC_LP_UART_FIFO_LEN) || + (cfg->flow_ctrl > UART_CFG_FLOW_CTRL_RTS_CTS) || + (cfg->data_bits > UART_CFG_DATA_BITS_8)) { + return -EINVAL; + } + + /* Get LP UART source clock frequency */ + switch (clk_ll_rtc_fast_get_src()) { + case SOC_RTC_FAST_CLK_SRC_XTAL_DIV: +#if CONFIG_SOC_SERIES_ESP32 || CONFIG_SOC_SERIES_ESP32S2 /* SOC_RTC_FAST_CLK_SRC_XTAL_D4 */ + sclk_freq = clk_hal_xtal_get_freq_mhz() * MHZ(1) >> 2; +#else /* SOC_RTC_FAST_CLK_SRC_XTAL_D2 */ + sclk_freq = clk_hal_xtal_get_freq_mhz() * MHZ(1) >> 1; +#endif + break; + case SOC_RTC_FAST_CLK_SRC_RC_FAST: + sclk_freq = + esp_clk_tree_rc_fast_get_freq_hz(ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED) / + clk_ll_rc_fast_get_divider(); + break; +#if SOC_CLK_LP_FAST_SUPPORT_LP_PLL + case SOC_RTC_FAST_CLK_SRC_LP_PLL: + sclk_freq = clk_ll_lp_pll_get_freq_mhz() * MHZ(1); + break; +#endif + default: + return -EINVAL; + } + + lp_uart_ll_enable_bus_clock(0, true); + lp_uart_ll_set_source_clk(data->hal.dev, cfg->lp_uart_source_clk); + lp_uart_ll_sclk_enable(0); + + /* Initialize LP UART HAL with default parameters */ + uart_hal_init(&data->hal, LP_UART_NUM_0); + + /* Set protocol parameters from the configuration */ + lp_uart_ll_set_baudrate(data->hal.dev, cfg->baud_rate, sclk_freq); + uart_hal_set_parity(&data->hal, cfg->parity); + uart_hal_set_data_bit_num(&data->hal, cfg->data_bits); + uart_hal_set_stop_bits(&data->hal, cfg->stop_bits); + uart_hal_set_tx_idle_num(&data->hal, ESP_LP_UART_TX_IDLE_NUM_DEFAULT); + uart_hal_set_hw_flow_ctrl(&data->hal, cfg->flow_ctrl, cfg->rx_flow_ctrl_thresh); + + /* Reset Tx/Rx FIFOs */ + uart_hal_rxfifo_rst(&data->hal); + uart_hal_txfifo_rst(&data->hal); + + return 0; +} + +static void lp_uart_esp32_config_io(int pin, int direction, int func) +{ + int rtc_io_num = rtc_io_num_map[pin]; + + rtcio_hal_function_select(rtc_io_num, RTCIO_FUNC_RTC); + rtcio_hal_set_direction(rtc_io_num, direction); + rtcio_hal_iomux_func_sel(rtc_io_num, func); +} + +static void lp_uart_esp32_set_pin(const struct device *dev) +{ + const struct lp_uart_esp32_config *const cfg = dev->config; + + /* Configure Tx Pin */ + lp_uart_esp32_config_io(cfg->tx_io_num, RTC_GPIO_MODE_OUTPUT_ONLY, LP_U0TXD_MUX_FUNC); + + /* Configure Rx Pin */ + lp_uart_esp32_config_io(cfg->rx_io_num, RTC_GPIO_MODE_INPUT_ONLY, LP_U0RXD_GPIO_NUM); + + /* Configure RTS Pin */ + lp_uart_esp32_config_io(cfg->rts_io_num, RTC_GPIO_MODE_OUTPUT_ONLY, LP_U0RTS_MUX_FUNC); + + /* Configure CTS Pin */ + lp_uart_esp32_config_io(cfg->cts_io_num, RTC_GPIO_MODE_INPUT_ONLY, LP_U0CTS_MUX_FUNC); +} + +static int lp_uart_esp32_init(const struct device *dev) +{ + int ret = 0; + uint32_t reset_cause; + + hwinfo_get_reset_cause(&reset_cause); + + if (reset_cause == RESET_LOW_POWER_WAKE) { + return 0; + } + + ret = lp_uart_esp32_param_config(dev); + if (ret != 0) { + return -EINVAL; + } + + /* Configure LP UART IO pins */ + lp_uart_esp32_set_pin(dev); + return 0; +} + +#endif /* CONFIG_SOC_ESP32C6_HPCORE */ + +static DEVICE_API(uart, lp_uart_esp32_api) = { + .poll_in = lp_uart_esp32_poll_in, + .poll_out = lp_uart_esp32_poll_out, +}; + +static struct lp_uart_esp32_data lp_uart_esp32_data = { + .hal = + { + .dev = (uart_dev_t *)DT_REG_ADDR(DT_NODELABEL(lp_uart)), + }, +}; + +static const struct lp_uart_esp32_config lp_uart_esp32_cfg = { + .tx_io_num = DT_PROP(DT_NODELABEL(lp_uart), tx_pin), + .rx_io_num = DT_PROP(DT_NODELABEL(lp_uart), rx_pin), + .rts_io_num = DT_PROP(DT_NODELABEL(lp_uart), rts_pin), + .cts_io_num = DT_PROP(DT_NODELABEL(lp_uart), cts_pin), + .baud_rate = DT_PROP(DT_NODELABEL(lp_uart), current_speed), + .data_bits = DT_PROP_OR(DT_NODELABEL(lp_uart), data_bits, UART_CFG_DATA_BITS_8), + .parity = DT_ENUM_IDX(DT_NODELABEL(lp_uart), parity), + .stop_bits = DT_PROP_OR(DT_NODELABEL(lp_uart), stop_bits, UART_CFG_STOP_BITS_1), + .flow_ctrl = DT_PROP_OR(DT_NODELABEL(lp_uart), flow_ctrl, UART_CFG_FLOW_CTRL_NONE), + .rx_flow_ctrl_thresh = 0, + .lp_uart_source_clk = LP_UART_SCLK_DEFAULT, +}; + +#if defined(CONFIG_SOC_ESP32C6_HPCORE) +#define LP_UART_ESP32_INIT_FUNC lp_uart_esp32_init +#else +#define LP_UART_ESP32_INIT_FUNC NULL +#endif + +DEVICE_DT_DEFINE(DT_NODELABEL(lp_uart), LP_UART_ESP32_INIT_FUNC, NULL, &lp_uart_esp32_data, + &lp_uart_esp32_cfg, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, &lp_uart_esp32_api); diff --git a/drivers/timer/Kconfig.esp32 b/drivers/timer/Kconfig.esp32 index 304ad1271b79..ff10f017866d 100644 --- a/drivers/timer/Kconfig.esp32 +++ b/drivers/timer/Kconfig.esp32 @@ -5,7 +5,7 @@ config ESP32_SYS_TIMER bool "ESP32 sys-timer support (ESP32Cx series)" - depends on SOC_SERIES_ESP32C2 || SOC_SERIES_ESP32C3 || SOC_SERIES_ESP32C6 + depends on SOC_SERIES_ESP32C2 || SOC_SERIES_ESP32C3 || (SOC_SERIES_ESP32C6 && !SOC_ESP32C6_LPCORE) default y select TICKLESS_CAPABLE select TIMER_HAS_64BIT_CYCLE_COUNTER diff --git a/dts/bindings/gpio/espressif,esp32-lpgpio.yaml b/dts/bindings/gpio/espressif,esp32-lpgpio.yaml new file mode 100644 index 000000000000..5d7c76829606 --- /dev/null +++ b/dts/bindings/gpio/espressif,esp32-lpgpio.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2019, Yannis Damigos +# SPDX-License-Identifier: Apache-2.0 + +description: ESP32 Low Power GPIO controller for LP Core + +compatible: "espressif,esp32-lpgpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/serial/espressif,esp32-lpuart.yaml b/dts/bindings/serial/espressif,esp32-lpuart.yaml new file mode 100644 index 000000000000..a86ffce24e6a --- /dev/null +++ b/dts/bindings/serial/espressif,esp32-lpuart.yaml @@ -0,0 +1,40 @@ +description: ESP32 Low Power UART + +compatible: "espressif,esp32-lpuart" + +include: uart-controller.yaml + +properties: + reg: + required: true + + tx-pin: + type: int + default: 5 + enum: + - 5 + description: In ESP32C6, TX pin is fixed to GPIO5 + + rx-pin: + type: int + default: 4 + enum: + - 4 + description: In ESP32C6, RX pin is fixed to GPIO4 + + rts-pin: + type: int + default: 2 + enum: + - 2 + description: In ESP32C6, RTS pin is fixed to GPIO2 + + cts-pin: + type: int + default: 3 + enum: + - 3 + description: In ESP32C6, CTS pin is fixed to GPIO3 + + current-speed: + type: int diff --git a/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi b/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi index d61f0762e436..fa36d3d6ace8 100644 --- a/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi +++ b/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi @@ -76,9 +76,15 @@ }; sramlp: memory@50000000 { + #address-cells = <1>; + #size-cells = <1>; compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x50000000 DT_SIZE_K(16)>; zephyr,memory-region = "SRAMLP "; + + shmlp: memory@0 { + reg = <0x0 0x10>; + }; }; intc: interrupt-controller@60010000 { @@ -257,6 +263,13 @@ current-speed = <115200>; }; + lp_uart: uart@600b1400 { + compatible = "espressif,esp32-lpuart"; + reg = <0x600b1400 DT_SIZE_K(4)>; + status = "disabled"; + current-speed = <115200>; + }; + usb_serial: uart@6000f000 { compatible = "espressif,esp32-usb-serial"; reg = <0x6000F000 0x1000>; diff --git a/dts/riscv/espressif/esp32c6/esp32c6_lpcore.dtsi b/dts/riscv/espressif/esp32c6/esp32c6_lpcore.dtsi new file mode 100644 index 000000000000..dab0283d1365 --- /dev/null +++ b/dts/riscv/espressif/esp32c6/esp32c6_lpcore.dtsi @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "espressif,riscv"; + riscv,isa = "rv32imac_zicsr_zifencei"; + reg = <0>; + clock-source = ; + clock-frequency = ; + xtal-freq = ; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + + sramlp: memory@50000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "mmio-sram"; + reg = <0x50000000 DT_SIZE_K(16)>; + + shmlp: memory@0 { + reg = <0x0 0x10>; + }; + }; + + flash: flash-controller@60002000 { + compatible = "espressif,esp32-flash-controller"; + reg = <0x60002000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + erase-block-size = <4096>; + write-block-size = <4>; + /* Flash size is specified in SOC/SIP dtsi */ + }; + }; + + lp_uart: uart@600b1400 { + compatible = "espressif,esp32-lpuart"; + reg = <0x600b1400 DT_SIZE_K(4)>; + status = "disabled"; + }; + + lp_gpio: gpio@600b2000 { + compatible = "espressif,esp32-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x600b2000 DT_SIZE_K(4)>; + ngpios = <8>; /* 0..7 */ + }; + }; +}; diff --git a/dts/riscv/espressif/esp32c6/esp32c6_lpcore_wroom_n4.dtsi b/dts/riscv/espressif/esp32c6/esp32c6_lpcore_wroom_n4.dtsi new file mode 100644 index 000000000000..cfb4fc103dcb --- /dev/null +++ b/dts/riscv/espressif/esp32c6/esp32c6_lpcore_wroom_n4.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + + #include "esp32c6_lpcore.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/include/zephyr/dt-bindings/clock/esp32c6_clock.h b/include/zephyr/dt-bindings/clock/esp32c6_clock.h index 9aa39b2c51ed..b3264125790c 100644 --- a/include/zephyr/dt-bindings/clock/esp32c6_clock.h +++ b/include/zephyr/dt-bindings/clock/esp32c6_clock.h @@ -13,28 +13,28 @@ #define ESP32_CLK_SRC_RC_FAST 2U /* Supported CPU frequencies */ -#define ESP32_CLK_CPU_PLL_80M 80000000 -#define ESP32_CLK_CPU_PLL_160M 160000000 +#define ESP32_CLK_CPU_PLL_80M 80000000 +#define ESP32_CLK_CPU_PLL_160M 160000000 #define ESP32_CLK_CPU_RC_FAST_FREQ 17500000 /* Supported XTAL Frequencies */ -#define ESP32_CLK_XTAL_32M 32000000 -#define ESP32_CLK_XTAL_40M 40000000 +#define ESP32_CLK_XTAL_32M 32000000 +#define ESP32_CLK_XTAL_40M 40000000 /* Supported RTC fast clock sources */ #define ESP32_RTC_FAST_CLK_SRC_RC_FAST 0 #define ESP32_RTC_FAST_CLK_SRC_XTAL_D2 1 /* Supported RTC slow clock frequencies */ -#define ESP32_RTC_SLOW_CLK_SRC_RC_SLOW 0 -#define ESP32_RTC_SLOW_CLK_SRC_XTAL32K 1 -#define ESP32_RTC_SLOW_CLK_SRC_RC32K 2 -#define ESP32_RTC_SLOW_CLK_32K_EXT_OSC 9 +#define ESP32_RTC_SLOW_CLK_SRC_RC_SLOW 0 +#define ESP32_RTC_SLOW_CLK_SRC_XTAL32K 1 +#define ESP32_RTC_SLOW_CLK_SRC_RC32K 2 +#define ESP32_RTC_SLOW_CLK_32K_EXT_OSC 9 /* RTC slow clock frequencies */ -#define ESP32_RTC_SLOW_CLK_SRC_RC_SLOW_FREQ 136000 -#define ESP32_RTC_SLOW_CLK_SRC_XTAL32K_FREQ 32768 -#define ESP32_RTC_SLOW_CLK_SRC_RC32K_FREQ 32768 +#define ESP32_RTC_SLOW_CLK_SRC_RC_SLOW_FREQ 136000 +#define ESP32_RTC_SLOW_CLK_SRC_XTAL32K_FREQ 32768 +#define ESP32_RTC_SLOW_CLK_SRC_RC32K_FREQ 32768 /* Modules IDs * These IDs are actually offsets in CLK and RST Control registers. @@ -44,44 +44,49 @@ * Basic Modules * Registers: DPORT_PERIP_CLK_EN_REG, DPORT_PERIP_RST_EN_REG */ -#define ESP32_LEDC_MODULE 0 -#define ESP32_UART0_MODULE 1 -#define ESP32_UART1_MODULE 2 -#define ESP32_USB_MODULE 3 -#define ESP32_I2C0_MODULE 4 -#define ESP32_I2S1_MODULE 5 -#define ESP32_TIMG0_MODULE 6 -#define ESP32_TIMG1_MODULE 7 -#define ESP32_UHCI0_MODULE 8 -#define ESP32_RMT_MODULE 9 -#define ESP32_PCNT_MODULE 10 -#define ESP32_SPI_MODULE 11 -#define ESP32_SPI2_MODULE 12 -#define ESP32_TWAI0_MODULE 13 -#define ESP32_TWAI1_MODULE 14 -#define ESP32_RNG_MODULE 15 -#define ESP32_RSA_MODULE 16 -#define ESP32_AES_MODULE 17 -#define ESP32_SHA_MODULE 18 -#define ESP32_ECC_MODULE 19 -#define ESP32_HMAC_MODULE 20 -#define ESP32_DS_MODULE 21 -#define ESP32_SDIO_SLAVE_MODULE 22 -#define ESP32_GDMA_MODULE 23 -#define ESP32_MCPWM0_MODULE 24 -#define ESP32_ETM_MODULE 25 -#define ESP32_PARLIO_MODULE 26 -#define ESP32_SYSTIMER_MODULE 27 -#define ESP32_SARADC_MODULE 28 -#define ESP32_TEMPSENSOR_MODULE 29 -#define ESP32_REGDMA_MODULE 30 -#define ESP32_LP_I2C0_MODULE 31 +#define ESP32_LEDC_MODULE 0 +#define ESP32_UART0_MODULE 1 +#define ESP32_UART1_MODULE 2 +#define ESP32_USB_MODULE 3 +#define ESP32_I2C0_MODULE 4 +#define ESP32_I2S1_MODULE 5 +#define ESP32_TIMG0_MODULE 6 +#define ESP32_TIMG1_MODULE 7 +#define ESP32_UHCI0_MODULE 8 +#define ESP32_RMT_MODULE 9 +#define ESP32_PCNT_MODULE 10 +#define ESP32_SPI_MODULE 11 +#define ESP32_SPI2_MODULE 12 +#define ESP32_TWAI0_MODULE 13 +#define ESP32_TWAI1_MODULE 14 +#define ESP32_RNG_MODULE 15 +#define ESP32_RSA_MODULE 16 +#define ESP32_AES_MODULE 17 +#define ESP32_SHA_MODULE 18 +#define ESP32_ECC_MODULE 19 +#define ESP32_HMAC_MODULE 20 +#define ESP32_DS_MODULE 21 +#define ESP32_SDIO_SLAVE_MODULE 22 +#define ESP32_GDMA_MODULE 23 +#define ESP32_MCPWM0_MODULE 24 +#define ESP32_ETM_MODULE 25 +#define ESP32_PARLIO_MODULE 26 +#define ESP32_SYSTIMER_MODULE 27 +#define ESP32_SARADC_MODULE 28 +#define ESP32_TEMPSENSOR_MODULE 29 +#define ESP32_ASSIST_DEBUG_MODULE 30 +/* LP peripherals */ +#define ESP32_LP_I2C0_MODULE 31 +#define ESP32_LP_UART0_MODULE 32 /* Peripherals clock managed by the modem_clock driver must be listed last */ -#define ESP32_WIFI_MODULE 32 -#define ESP32_BT_MODULE 33 -#define ESP32_IEEE802154_MODULE 34 -#define ESP32_COEX_MODULE 35 -#define ESP32_PHY_MODULE 36 -#define ESP32_MODULE_MAX 37 +#define ESP32_WIFI_MODULE 33 +#define ESP32_BT_MODULE 34 +#define ESP32_IEEE802154_MODULE 35 +#define ESP32_COEX_MODULE 36 +#define ESP32_PHY_MODULE 37 +#define ESP32_ANA_I2C_MASTER_MODULE 38 +#define ESP32_MODEM_ETM_MODULE 39 +#define ESP32_MODEM_ADC_COMMON_FE_MODULE 40 +#define ESP32_MODULE_MAX 41 #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_ESP32C6_H_ */ diff --git a/samples/boards/espressif/deep_sleep/boards/esp32c6_devkitc.conf b/samples/boards/espressif/deep_sleep/boards/esp32c6_devkitc_hpcore.conf similarity index 100% rename from samples/boards/espressif/deep_sleep/boards/esp32c6_devkitc.conf rename to samples/boards/espressif/deep_sleep/boards/esp32c6_devkitc_hpcore.conf diff --git a/samples/boards/espressif/ulp/README.rst b/samples/boards/espressif/ulp/README.rst new file mode 100644 index 000000000000..89ff6980ec0c --- /dev/null +++ b/samples/boards/espressif/ulp/README.rst @@ -0,0 +1,5 @@ +.. zephyr:code-sample-category:: ulp + :name: Ultra Low Power coprocessor (ULP) + :show-listing: + + These samples demonstrate how to use the ULP in Espressif SOCs. diff --git a/samples/boards/espressif/ulp/lp_core/README.rst b/samples/boards/espressif/ulp/lp_core/README.rst new file mode 100644 index 000000000000..d06d7a11443f --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/README.rst @@ -0,0 +1,5 @@ +.. zephyr:code-sample-category:: lp-core + :name: Low-Power CPU (LP CORE) + :show-listing: + + These samples demonstrate how to use the LP Core in Espressif SOCs. diff --git a/samples/boards/espressif/ulp/lp_core/blinky_ulp/CMakeLists.txt b/samples/boards/espressif/ulp/lp_core/blinky_ulp/CMakeLists.txt new file mode 100644 index 000000000000..17fc0f8c11b4 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/blinky_ulp/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../blinky_ulp_lpcore/zephyr) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +message(STATUS "${CONFIG_BOARD_TARGET} compile as Master in this sample") +project(blinky_ulp_hpcore) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/espressif/ulp/lp_core/blinky_ulp/Kconfig.sysbuild b/samples/boards/espressif/ulp/lp_core/blinky_ulp/Kconfig.sysbuild new file mode 100644 index 000000000000..1a54b95872ba --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/blinky_ulp/Kconfig.sysbuild @@ -0,0 +1,8 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config ULP_REMOTE_BOARD + string + default "esp32c6_devkitc/esp32c6/lpcore" if $(BOARD) = "esp32c6_devkitc" diff --git a/samples/boards/espressif/ulp/lp_core/blinky_ulp/README.rst b/samples/boards/espressif/ulp/lp_core/blinky_ulp/README.rst new file mode 100644 index 000000000000..750ae31be6e3 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/blinky_ulp/README.rst @@ -0,0 +1,38 @@ +.. zephyr:code-sample:: hello-ulp + :name: + + Sample to demonstrate how to use LP UART with LP Core in ESP32C6. + +Overview +******** + +This is a simple sample that prints 'Hello World' running from LP Core using LP UART peripheral. + + +Building and Flashing +********************* + +Build the sample code as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/espressif/ulp/lp_core/hello_ulp + :board: esp32c6_devkitc/esp32c6/hpcore + :west-args: --sysbuild + :goals: build + :compact: + +Flash it to the device with the command: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/espressif/ulp/lp_core/hello_ulp + :board: esp32c6_devkitc/esp32c6/hpcore + :west-args: --sysbuild + :goals: flash + :compact: + +Sample Output +============= + +.. code-block:: console + + Hello World! esp32c6_devkitc/esp32c6/lpcore diff --git a/samples/boards/espressif/ulp/lp_core/blinky_ulp/gdbinit b/samples/boards/espressif/ulp/lp_core/blinky_ulp/gdbinit new file mode 100644 index 000000000000..ef3943512b41 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/blinky_ulp/gdbinit @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +set pagination off +target extended-remote :3333 + +mon reset halt +maintenance flush register-cache + +add-symbol build/blinky_ulp_lpcore/zephyr/zephyr.elf +thb lp_gpio_esp32_configure diff --git a/samples/boards/espressif/ulp/lp_core/blinky_ulp/prj.conf b/samples/boards/espressif/ulp/lp_core/blinky_ulp/prj.conf new file mode 100644 index 000000000000..7d425a10aa2c --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/blinky_ulp/prj.conf @@ -0,0 +1 @@ +CONFIG_ULP_COPROC_ENABLED=y diff --git a/samples/boards/espressif/ulp/lp_core/blinky_ulp/remote/CMakeLists.txt b/samples/boards/espressif/ulp/lp_core/blinky_ulp/remote/CMakeLists.txt new file mode 100644 index 000000000000..8d6eba0415cf --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/blinky_ulp/remote/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +message(STATUS "${BOARD} compiles as remote in this sample") +project(blinky_ulp_lpcore) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/espressif/ulp/lp_core/blinky_ulp/remote/app.overlay b/samples/boards/espressif/ulp/lp_core/blinky_ulp/remote/app.overlay new file mode 100644 index 000000000000..e8f7d832a848 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/blinky_ulp/remote/app.overlay @@ -0,0 +1,12 @@ +/ { + leds { + compatible = "gpio-leds"; + lp_led0: lp_led0 { + gpios = <&lp_gpio 0 0>; + }; + }; + + aliases { + led0 = &lp_led0; + }; +}; diff --git a/samples/boards/espressif/ulp/lp_core/blinky_ulp/remote/prj.conf b/samples/boards/espressif/ulp/lp_core/blinky_ulp/remote/prj.conf new file mode 100644 index 000000000000..91c3c15b37d1 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/blinky_ulp/remote/prj.conf @@ -0,0 +1 @@ +CONFIG_GPIO=y diff --git a/samples/boards/espressif/ulp/lp_core/blinky_ulp/remote/src/main.c b/samples/boards/espressif/ulp/lp_core/blinky_ulp/remote/src/main.c new file mode 100644 index 000000000000..4cab4969d94b --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/blinky_ulp/remote/src/main.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* 1000 msec = 1 sec */ +#define SLEEP_TIME_MS 1000 + +/* The devicetree node identifier for the "led0" alias. */ +#define LED0_NODE DT_ALIAS(led0) + +/* + * A build error on this line means your board is unsupported. + * See the sample documentation for information on how to fix this. + */ +static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); + +int main(void) +{ + int ret; + bool led_state = true; + + if (!gpio_is_ready_dt(&led)) { + return 0; + } + + ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); + if (ret < 0) { + return 0; + } + + while (1) { + ret = gpio_pin_toggle_dt(&led); + if (ret < 0) { + return 0; + } + + led_state = !led_state; + printf("LED state: %s\n", led_state ? "ON" : "OFF"); + k_msleep(SLEEP_TIME_MS); + } + return 0; +} diff --git a/samples/boards/espressif/ulp/lp_core/blinky_ulp/sample.yaml b/samples/boards/espressif/ulp/lp_core/blinky_ulp/sample.yaml new file mode 100644 index 000000000000..5c8a669d85a7 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/blinky_ulp/sample.yaml @@ -0,0 +1,8 @@ +sample: + name: ESP32C6 LP_CORE blinky World Sample +tests: + sample.boards.espressif.ulp.lp_core.blinky_ulp: + platform_allow: + - esp32c6_devkitc/esp32c6/hpcore + tags: + - samples diff --git a/samples/boards/espressif/ulp/lp_core/blinky_ulp/src/main.c b/samples/boards/espressif/ulp/lp_core/blinky_ulp/src/main.c new file mode 100644 index 000000000000..bfb97b8f2714 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/blinky_ulp/src/main.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +int main(void) +{ + while (1) { + k_sleep(K_MSEC(1000)); + } + + return 0; +} diff --git a/samples/boards/espressif/ulp/lp_core/blinky_ulp/sysbuild.cmake b/samples/boards/espressif/ulp/lp_core/blinky_ulp/sysbuild.cmake new file mode 100644 index 000000000000..ca51cc662c7f --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/blinky_ulp/sysbuild.cmake @@ -0,0 +1,21 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +# Add external project +ExternalZephyrProject_Add( + APPLICATION blinky_ulp_lpcore + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_ULP_REMOTE_BOARD} + ) + +# Add dependencies so that the remote sample will be built first +# This is required because some primary cores need information from the +# remote core's build, such as the output image's LMA +add_dependencies(blinky_ulp blinky_ulp_lpcore) +sysbuild_add_dependencies(CONFIGURE blinky_ulp blinky_ulp_lpcore) +sysbuild_add_dependencies(FLASH blinky_ulp_lpcore blinky_ulp) + +if(SB_CONFIG_BOOTLOADER_MCUBOOT) + # Make sure MCUboot is flashed first + sysbuild_add_dependencies(FLASH blinky_ulp mcuboot) +endif() diff --git a/samples/boards/espressif/ulp/lp_core/debug_ulp/CMakeLists.txt b/samples/boards/espressif/ulp/lp_core/debug_ulp/CMakeLists.txt new file mode 100644 index 000000000000..c12f9e3c74c7 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/debug_ulp/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../hello_ulp_lpcore/zephyr) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +message(STATUS "${CONFIG_BOARD_TARGET} compile as Master in this sample") +project(debug_ulp_hpcore) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/espressif/ulp/lp_core/debug_ulp/Kconfig.sysbuild b/samples/boards/espressif/ulp/lp_core/debug_ulp/Kconfig.sysbuild new file mode 100644 index 000000000000..1a54b95872ba --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/debug_ulp/Kconfig.sysbuild @@ -0,0 +1,8 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config ULP_REMOTE_BOARD + string + default "esp32c6_devkitc/esp32c6/lpcore" if $(BOARD) = "esp32c6_devkitc" diff --git a/samples/boards/espressif/ulp/lp_core/debug_ulp/README.rst b/samples/boards/espressif/ulp/lp_core/debug_ulp/README.rst new file mode 100644 index 000000000000..9c44c186fca0 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/debug_ulp/README.rst @@ -0,0 +1,124 @@ +.. zephyr:code-sample:: debug-ulp + :name: + :relevant-api: ipm_interface + + Sample to demonstrate how to debug the LP Core in ESP32C6. + +Overview +******** + +This example demonstrates how to build, flash and debug a simple application on the LP core. + +This sample also provides a custom ``gdbinit`` file to be loaded by GDB to set up the debugging environment. +It connects with the remote OpenOCD server, loads the symbols from the LP Core application +and sets an initial breakpoint. + +Limitations +*********** +1. Currently debugging is not supported when either HP or LP core enters any sleep mode. So this limits debugging scenarios. +2. OS support is disabled when debugging the LP core, so you won't be able to see tasks running in the system. Instead there will be two threads representing HP ('esp32c6.cpu0') and LP ('esp32c6.cpu1') cores: + +.. code-block:: console + + (gdb) info thread + Id Target Id Frame + 1 Thread 1 "esp32c6.hp.cpu0" (Name: esp32c6.hp.cpu0, state: debug-request) arch_irq_unlock (key=8) at zephyr/include/zephyr/arch/riscv/arch.h:259 + * 2 Thread 2 "esp32c6.lp.cpu" (Name: esp32c6.lp.cpu, state: breakpoint) do_things (max=1000000000) at zephyr/samples/boards/espressif/ulp/lp_core/debug_ulp/remote/src/main.c:28 + +3. When setting HW breakpoint in GDB it is set on both cores, so the number of available HW breakpoints is limited to the number of them supported by LP core (2 for ESP32-C6). + +Sysbuild +******** + +Sysbuild is in charge of building the application located in the ``remote`` folder for the LP Core target. +The build and flashing orders are as follows: + +Build: + +- MCUboot bootloader +- LP Core application +- HP Core application + +Flash: + +- MCUboot bootloader +- HP Core application +- LP Core application + +Building and Flashing +********************* + +Build the sample code as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/espressif/ulp/lp_core/debug_ulp + :board: esp32c6_devkitc/esp32c6/hpcore + :west-args: --sysbuild + :goals: build + :compact: + +Flash it to the device with the command: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/espressif/ulp/lp_core/debug_ulp + :board: esp32c6_devkitc/esp32c6/hpcore + :west-args: --sysbuild + :goals: flash + :compact: + +Debugging +********* + +Connect the USB cable to the USB port of the ESP32-C6 Devkitc board. + +The ESP32-C6 modules require patches to OpenOCD that are not upstreamed yet. +Espressif maintains their own fork of the project. +The custom OpenOCD can be obtained at `OpenOCD ESP32`_. + +In one terminal instance run the Espressif's OpenOCD: + +.. code-block:: shell + + /bin/openocd -f board/esp32c6-lpcore-builtin.cfg + +Wait for the following output to show up in the console: + +.. code-block:: console + + Info : Listening on port 3333 for gdb connections + +On another terminal instance, run the GDB: + +.. code-block:: shell + + /riscv64-zephyr-elf/bin/riscv64-zephyr-elf-gdb -x samples/boards/espressif/ulp/lp_core/debug_ulp/gdbinit build/debug_ulp/zephyr/zephyr.elf + +The following output should be displayed: + +.. code-block:: console + + [esp32c6.hp.cpu0] Reset cause (24) - (JTAG CPU reset) + add symbol table from file "build/debug_ulp_lpcore/zephyr/zephyr.elf" + Hardware assisted breakpoint 1 at 0x500000ec: file zephyr/samples/boards/espressif/ulp/lp_core/debug_ulp/remote/src/main.c, line 28. + (gdb) + +From now on you can use the GDB commands to debug the application. By using the command ``continue`` the LP Core application stop at the assigned breakpoint: + +.. code-block:: console + + (gdb) continue + Continuing. + [Switching to Thread 2] + + Thread 2 "esp32c6.lp.cpu" hit Temporary breakpoint 1, do_things (max=1000000000) at zephyr/samples/boards/espressif/ulp/lp_core/debug_ulp/remote/src/main.c:28 + 28 for (int i = 0; i < max; i++) { + (gdb) + +When the application reaches the ``abort()`` function it will automatically break. + +References +********** + +.. target-notes:: + +.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/samples/boards/espressif/ulp/lp_core/debug_ulp/gdbinit b/samples/boards/espressif/ulp/lp_core/debug_ulp/gdbinit new file mode 100644 index 000000000000..b1da390631b2 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/debug_ulp/gdbinit @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +set pagination off +target extended-remote :3333 + +mon reset halt +maintenance flush register-cache + +add-symbol build/debug_ulp_lpcore/zephyr/zephyr.elf +thb do_things diff --git a/samples/boards/espressif/ulp/lp_core/debug_ulp/prj.conf b/samples/boards/espressif/ulp/lp_core/debug_ulp/prj.conf new file mode 100644 index 000000000000..ddeb8d78974a --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/debug_ulp/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_LOG=y diff --git a/samples/boards/espressif/ulp/lp_core/debug_ulp/remote/CMakeLists.txt b/samples/boards/espressif/ulp/lp_core/debug_ulp/remote/CMakeLists.txt new file mode 100644 index 000000000000..bca02c90158f --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/debug_ulp/remote/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +message(STATUS "${BOARD} compiles as remote in this sample") +project(debug_ulp_lpcore) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/espressif/ulp/lp_core/debug_ulp/remote/prj.conf b/samples/boards/espressif/ulp/lp_core/debug_ulp/remote/prj.conf new file mode 100644 index 000000000000..7c76e06e876f --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/debug_ulp/remote/prj.conf @@ -0,0 +1,6 @@ +CONFIG_DEBUG=y +CONFIG_NO_OPTIMIZATIONS=y + +# Create a disassembly file +CONFIG_OUTPUT_DISASSEMBLY=y +CONFIG_OUTPUT_DISASSEMBLE_ALL=y diff --git a/samples/boards/espressif/ulp/lp_core/debug_ulp/remote/src/main.c b/samples/boards/espressif/ulp/lp_core/debug_ulp/remote/src/main.c new file mode 100644 index 000000000000..b8a7ffc5a253 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/debug_ulp/remote/src/main.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "ulp_lp_core_utils.h" +#include +#include "riscv/rvruntime-frames.h" + +/* Override for the ulp_lp_core_panic_handler() so it stops the debugger when abort() is called */ +void ulp_lp_core_panic_handler(RvExcFrame *frame, int exccause) +{ + esp_cpu_dbgr_break(); +} + +void do_crash(void) +{ + volatile int *p = (int *)0x0; + *p = 32; + abort(); +} + +void do_things(int max) +{ + while (1) { + for (int i = 0; i < max; i++) { + ulp_lp_core_delay_us(100000); + if (i > 0) { + do_crash(); + } + } + } +} + +int main(void) +{ + do_things(1000000000); + return 0; +} diff --git a/samples/boards/espressif/ulp/lp_core/debug_ulp/sample.yaml b/samples/boards/espressif/ulp/lp_core/debug_ulp/sample.yaml new file mode 100644 index 000000000000..ad24c11c61fc --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/debug_ulp/sample.yaml @@ -0,0 +1,8 @@ +sample: + name: ESP32C6 LP_CORE Debug Sample +tests: + sample.boards.espressif.ulp.lp_core.debug_ulp: + platform_allow: + - esp32c6_devkitc/esp32c6/hpcore + tags: + - samples diff --git a/samples/boards/espressif/ulp/lp_core/debug_ulp/src/main.c b/samples/boards/espressif/ulp/lp_core/debug_ulp/src/main.c new file mode 100644 index 000000000000..bfb97b8f2714 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/debug_ulp/src/main.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +int main(void) +{ + while (1) { + k_sleep(K_MSEC(1000)); + } + + return 0; +} diff --git a/samples/boards/espressif/ulp/lp_core/debug_ulp/sysbuild.cmake b/samples/boards/espressif/ulp/lp_core/debug_ulp/sysbuild.cmake new file mode 100644 index 000000000000..79b72a6fd8d3 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/debug_ulp/sysbuild.cmake @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2025 Espressif + +# Add external project +ExternalZephyrProject_Add( + APPLICATION debug_ulp_lpcore + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_ULP_REMOTE_BOARD} + ) + +# Add dependencies so that the remote sample will be built first +# This is required because some primary cores need information from the +# remote core's build, such as the output image's LMA +add_dependencies(debug_ulp debug_ulp_lpcore) +sysbuild_add_dependencies(CONFIGURE debug_ulp debug_ulp_lpcore) +sysbuild_add_dependencies(FLASH debug_ulp_lpcore debug_ulp) + +if(SB_CONFIG_BOOTLOADER_MCUBOOT) + # Make sure MCUboot is flashed first + sysbuild_add_dependencies(FLASH debug_ulp mcuboot) +endif() diff --git a/samples/boards/espressif/ulp/lp_core/echo_ulp/CMakeLists.txt b/samples/boards/espressif/ulp/lp_core/echo_ulp/CMakeLists.txt new file mode 100644 index 000000000000..8567bfb13c7d --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/echo_ulp/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../echo_ulp_lpcore/zephyr) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +message(STATUS "${CONFIG_BOARD_TARGET} compile as Master in this sample") +project(echo_ulp_hpcore) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/espressif/ulp/lp_core/echo_ulp/Kconfig.sysbuild b/samples/boards/espressif/ulp/lp_core/echo_ulp/Kconfig.sysbuild new file mode 100644 index 000000000000..768b878fe1d6 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/echo_ulp/Kconfig.sysbuild @@ -0,0 +1,9 @@ +# Copyright 2022 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config ULP_REMOTE_BOARD + string + default "esp32c6_devkitc/esp32c6/lpcore" if $(BOARD) = "esp32c6_devkitc" diff --git a/samples/boards/espressif/ulp/lp_core/echo_ulp/README.rst b/samples/boards/espressif/ulp/lp_core/echo_ulp/README.rst new file mode 100644 index 000000000000..9345980d22f3 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/echo_ulp/README.rst @@ -0,0 +1,39 @@ +.. zephyr:code-sample:: echo-ulp + :name: + + Sample to demonstrate how to use LP UART with LP Core in ESP32C6 using Zephyr's UART API. + +Overview +******** + +This sample application demonstrates how to use poll-based APIs from the Zephyr +UART driver subsystem. It reads characters from the LP UART using +:c:func:`uart_poll_in` and echoes them back using :c:func:`uart_poll_out`. + +Building and Flashing +********************* + +Build the sample code as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/espressif/ulp/lp_core/echo_ulp + :board: esp32c6_devkitc/esp32c6/hpcore + :west-args: --sysbuild + :goals: build + :compact: + +Flash it to the device with the command: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/espressif/ulp/lp_core/echo_ulp + :board: esp32c6_devkitc/esp32c6/hpcore + :west-args: --sysbuild + :goals: flash + :compact: + +Sample Output +============= + +.. code-block:: console + + UART echo example started. Type something... diff --git a/samples/boards/espressif/ulp/lp_core/echo_ulp/app.overlay b/samples/boards/espressif/ulp/lp_core/echo_ulp/app.overlay new file mode 100644 index 000000000000..244dc34aa973 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/echo_ulp/app.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&lp_uart { + status = "okay"; +}; diff --git a/samples/boards/espressif/ulp/lp_core/echo_ulp/prj.conf b/samples/boards/espressif/ulp/lp_core/echo_ulp/prj.conf new file mode 100644 index 000000000000..7d425a10aa2c --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/echo_ulp/prj.conf @@ -0,0 +1 @@ +CONFIG_ULP_COPROC_ENABLED=y diff --git a/samples/boards/espressif/ulp/lp_core/echo_ulp/remote/CMakeLists.txt b/samples/boards/espressif/ulp/lp_core/echo_ulp/remote/CMakeLists.txt new file mode 100644 index 000000000000..27258dcbb0d5 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/echo_ulp/remote/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +message(STATUS "${BOARD} compiles as remote in this sample") +project(echo_ulp_lpcore) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/espressif/ulp/lp_core/echo_ulp/remote/prj.conf b/samples/boards/espressif/ulp/lp_core/echo_ulp/remote/prj.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/samples/boards/espressif/ulp/lp_core/echo_ulp/remote/src/main.c b/samples/boards/espressif/ulp/lp_core/echo_ulp/remote/src/main.c new file mode 100644 index 000000000000..b9b5ab177fc2 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/echo_ulp/remote/src/main.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define UART_DEVICE_NODE DT_NODELABEL(lp_uart) + +int main(void) +{ + const struct device *uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE); + char c; + int ret = 0; + + printf("UART echo example started. Type something...\n"); + + while(1) { + ret = uart_poll_in(uart_dev, &c); + if (ret == 0) { + /* Echo character back out */ + uart_poll_out(uart_dev, c); + if(c == '\r') { + uart_poll_out(uart_dev, '\n'); + } + } + } + + return 0; +} diff --git a/samples/boards/espressif/ulp/lp_core/echo_ulp/sample.yaml b/samples/boards/espressif/ulp/lp_core/echo_ulp/sample.yaml new file mode 100644 index 000000000000..4577165150a1 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/echo_ulp/sample.yaml @@ -0,0 +1,8 @@ +sample: + name: ESP32C6 LP_CORE Echo World Sample +tests: + sample.boards.espressif.ulp.lp_core.echo_ulp: + platform_allow: + - esp32c6_devkitc/esp32c6/hpcore + tags: + - samples diff --git a/samples/boards/espressif/ulp/lp_core/echo_ulp/src/main.c b/samples/boards/espressif/ulp/lp_core/echo_ulp/src/main.c new file mode 100644 index 000000000000..bfb97b8f2714 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/echo_ulp/src/main.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +int main(void) +{ + while (1) { + k_sleep(K_MSEC(1000)); + } + + return 0; +} diff --git a/samples/boards/espressif/ulp/lp_core/echo_ulp/sysbuild.cmake b/samples/boards/espressif/ulp/lp_core/echo_ulp/sysbuild.cmake new file mode 100644 index 000000000000..5eaf61a64dac --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/echo_ulp/sysbuild.cmake @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2024 Espressif + +# Add external project +ExternalZephyrProject_Add( + APPLICATION echo_ulp_lpcore + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_ULP_REMOTE_BOARD} + ) + +# Add dependencies so that the remote sample will be built first +# This is required because some primary cores need information from the +# remote core's build, such as the output image's LMA +add_dependencies(echo_ulp echo_ulp_lpcore) +sysbuild_add_dependencies(CONFIGURE echo_ulp echo_ulp_lpcore) +sysbuild_add_dependencies(FLASH echo_ulp_lpcore echo_ulp) + +if(SB_CONFIG_BOOTLOADER_MCUBOOT) + # Make sure MCUboot is flashed first + sysbuild_add_dependencies(FLASH echo_ulp mcuboot) +endif() diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/CMakeLists.txt b/samples/boards/espressif/ulp/lp_core/hello_ulp/CMakeLists.txt new file mode 100644 index 000000000000..d64e6a39fd28 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/hello_ulp/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../hello_ulp_lpcore/zephyr) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +message(STATUS "${CONFIG_BOARD_TARGET} compile as Master in this sample") +project(hello_ulp_hpcore) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/Kconfig.sysbuild b/samples/boards/espressif/ulp/lp_core/hello_ulp/Kconfig.sysbuild new file mode 100644 index 000000000000..768b878fe1d6 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/hello_ulp/Kconfig.sysbuild @@ -0,0 +1,9 @@ +# Copyright 2022 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config ULP_REMOTE_BOARD + string + default "esp32c6_devkitc/esp32c6/lpcore" if $(BOARD) = "esp32c6_devkitc" diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/README.rst b/samples/boards/espressif/ulp/lp_core/hello_ulp/README.rst new file mode 100644 index 000000000000..750ae31be6e3 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/hello_ulp/README.rst @@ -0,0 +1,38 @@ +.. zephyr:code-sample:: hello-ulp + :name: + + Sample to demonstrate how to use LP UART with LP Core in ESP32C6. + +Overview +******** + +This is a simple sample that prints 'Hello World' running from LP Core using LP UART peripheral. + + +Building and Flashing +********************* + +Build the sample code as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/espressif/ulp/lp_core/hello_ulp + :board: esp32c6_devkitc/esp32c6/hpcore + :west-args: --sysbuild + :goals: build + :compact: + +Flash it to the device with the command: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/espressif/ulp/lp_core/hello_ulp + :board: esp32c6_devkitc/esp32c6/hpcore + :west-args: --sysbuild + :goals: flash + :compact: + +Sample Output +============= + +.. code-block:: console + + Hello World! esp32c6_devkitc/esp32c6/lpcore diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/app.overlay b/samples/boards/espressif/ulp/lp_core/hello_ulp/app.overlay new file mode 100644 index 000000000000..1cb1b78e860e --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/hello_ulp/app.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&lp_uart { + status = "okay"; +}; + +&sramlp { + reg = <0x50000000 DT_SIZE_K(8)>; +}; diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/gdbinit b/samples/boards/espressif/ulp/lp_core/hello_ulp/gdbinit new file mode 100644 index 000000000000..6cec80f00d2e --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/hello_ulp/gdbinit @@ -0,0 +1,8 @@ +set pagination off +target extended-remote :3333 + +mon reset halt +maintenance flush register-cache + +add-symbol build/hello_ulp_lpcore/zephyr/zephyr.elf +thb lp_uart_esp32_param_config diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/prj.conf b/samples/boards/espressif/ulp/lp_core/hello_ulp/prj.conf new file mode 100644 index 000000000000..229f48950988 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/hello_ulp/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_POWEROFF=y diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/remote/CMakeLists.txt b/samples/boards/espressif/ulp/lp_core/hello_ulp/remote/CMakeLists.txt new file mode 100644 index 000000000000..4f85e0a76fd5 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/hello_ulp/remote/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +message(STATUS "${BOARD} compiles as remote in this sample") +project(hello_ulp_lpcore) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/remote/app.overlay b/samples/boards/espressif/ulp/lp_core/hello_ulp/remote/app.overlay new file mode 100644 index 000000000000..dd0dd8723c64 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/hello_ulp/remote/app.overlay @@ -0,0 +1,5 @@ +#include + +&sramlp { + reg = <0x50000000 DT_SIZE_K(8)>; +}; diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/remote/prj.conf b/samples/boards/espressif/ulp/lp_core/hello_ulp/remote/prj.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/remote/src/main.c b/samples/boards/espressif/ulp/lp_core/hello_ulp/remote/src/main.c new file mode 100644 index 000000000000..dd820ad9881d --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/hello_ulp/remote/src/main.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "ulp_lp_core_utils.h" + +int main(void) +{ + printf("Hello World! %s\r\n", CONFIG_BOARD_TARGET); + while(1) { + k_msleep(2000); + printf("Waking HP Core\n"); + ulp_lp_core_wakeup_main_processor(); + } + + return 0; +} diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/sample.yaml b/samples/boards/espressif/ulp/lp_core/hello_ulp/sample.yaml new file mode 100644 index 000000000000..8b80ca021cfa --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/hello_ulp/sample.yaml @@ -0,0 +1,8 @@ +sample: + name: ESP32C6 LP_CORE Hello World Sample +tests: + sample.boards.espressif.ulp.lp_core.hello_ulp: + platform_allow: + - esp32c6_devkitc/esp32c6/hpcore + tags: + - samples diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/src/main.c b/samples/boards/espressif/ulp/lp_core/hello_ulp/src/main.c new file mode 100644 index 000000000000..031ef9a17c67 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/hello_ulp/src/main.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +int main(void) +{ + uint32_t reset_cause; + + hwinfo_get_reset_cause(&reset_cause); + + switch (reset_cause) { + case RESET_LOW_POWER_WAKE: + printf("Wake up from deep sleep\n"); + break; + default: + printf("Not a deep sleep reset\n"); + } + + esp_sleep_enable_ulp_wakeup(); + printf("Powering off\n"); + sys_poweroff(); + + return 0; +} diff --git a/samples/boards/espressif/ulp/lp_core/hello_ulp/sysbuild.cmake b/samples/boards/espressif/ulp/lp_core/hello_ulp/sysbuild.cmake new file mode 100644 index 000000000000..49da1a18409b --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/hello_ulp/sysbuild.cmake @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2024 Espressif + +# Add external project +ExternalZephyrProject_Add( + APPLICATION hello_ulp_lpcore + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_ULP_REMOTE_BOARD} + ) + +# Add dependencies so that the remote sample will be built first +# This is required because some primary cores need information from the +# remote core's build, such as the output image's LMA +add_dependencies(hello_ulp hello_ulp_lpcore) +sysbuild_add_dependencies(CONFIGURE hello_ulp hello_ulp_lpcore) +sysbuild_add_dependencies(FLASH hello_ulp_lpcore hello_ulp) + +if(SB_CONFIG_BOOTLOADER_MCUBOOT) + # Make sure MCUboot is flashed first + sysbuild_add_dependencies(FLASH hello_ulp mcuboot) +endif() diff --git a/samples/boards/espressif/ulp/lp_core/interrupt_ulp/CMakeLists.txt b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/CMakeLists.txt new file mode 100644 index 000000000000..75c46ff8911b --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../interrupt_ulp_lpcore/zephyr) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +message(STATUS "${CONFIG_BOARD_TARGET} compile as Master in this sample") +project(interrupt_ulp_hpcore) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/espressif/ulp/lp_core/interrupt_ulp/Kconfig.sysbuild b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/Kconfig.sysbuild new file mode 100644 index 000000000000..768b878fe1d6 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/Kconfig.sysbuild @@ -0,0 +1,9 @@ +# Copyright 2022 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config ULP_REMOTE_BOARD + string + default "esp32c6_devkitc/esp32c6/lpcore" if $(BOARD) = "esp32c6_devkitc" diff --git a/samples/boards/espressif/ulp/lp_core/interrupt_ulp/README.rst b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/README.rst new file mode 100644 index 000000000000..750ae31be6e3 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/README.rst @@ -0,0 +1,38 @@ +.. zephyr:code-sample:: hello-ulp + :name: + + Sample to demonstrate how to use LP UART with LP Core in ESP32C6. + +Overview +******** + +This is a simple sample that prints 'Hello World' running from LP Core using LP UART peripheral. + + +Building and Flashing +********************* + +Build the sample code as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/espressif/ulp/lp_core/hello_ulp + :board: esp32c6_devkitc/esp32c6/hpcore + :west-args: --sysbuild + :goals: build + :compact: + +Flash it to the device with the command: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/espressif/ulp/lp_core/hello_ulp + :board: esp32c6_devkitc/esp32c6/hpcore + :west-args: --sysbuild + :goals: flash + :compact: + +Sample Output +============= + +.. code-block:: console + + Hello World! esp32c6_devkitc/esp32c6/lpcore diff --git a/samples/boards/espressif/ulp/lp_core/interrupt_ulp/prj.conf b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/prj.conf new file mode 100644 index 000000000000..7d425a10aa2c --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/prj.conf @@ -0,0 +1 @@ +CONFIG_ULP_COPROC_ENABLED=y diff --git a/samples/boards/espressif/ulp/lp_core/interrupt_ulp/remote/CMakeLists.txt b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/remote/CMakeLists.txt new file mode 100644 index 000000000000..df4edfdd0e83 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/remote/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +message(STATUS "${BOARD} compiles as remote in this sample") +project(interrupt_ulp_lpcore) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/espressif/ulp/lp_core/interrupt_ulp/remote/prj.conf b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/remote/prj.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/samples/boards/espressif/ulp/lp_core/interrupt_ulp/remote/src/main.c b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/remote/src/main.c new file mode 100644 index 000000000000..babca707bd1d --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/remote/src/main.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "ulp_lp_core_utils.h" +#include "ulp_lp_core_interrupts.h" + +uint32_t lp_core_pmu_intr_count = 0; + +void ulp_lp_core_lp_pmu_intr_handler(void) +{ + ulp_lp_core_sw_intr_clear(); + lp_core_pmu_intr_count++; + printf("LP PMU interrupt received: %d\n", lp_core_pmu_intr_count); +} + +int main(void) +{ + ulp_lp_core_intr_enable(); + ulp_lp_core_sw_intr_enable(true); + + while (1) { + /* Wait forever, handling interrupts */ + asm volatile("wfi"); + } + return 0; +} diff --git a/samples/boards/espressif/ulp/lp_core/interrupt_ulp/sample.yaml b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/sample.yaml new file mode 100644 index 000000000000..4f38cb814583 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/sample.yaml @@ -0,0 +1,8 @@ +sample: + name: ESP32C6 LP_CORE interrupt World Sample +tests: + sample.boards.espressif.ulp.lp_core.interrupt_ulp: + platform_allow: + - esp32c6_devkitc/esp32c6/hpcore + tags: + - samples diff --git a/samples/boards/espressif/ulp/lp_core/interrupt_ulp/src/main.c b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/src/main.c new file mode 100644 index 000000000000..8b5ef1df0941 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/src/main.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +int main(void) +{ + while (1) { + ulp_lp_core_sw_intr_trigger(); + k_sleep(K_MSEC(1000)); + } + + return 0; +} diff --git a/samples/boards/espressif/ulp/lp_core/interrupt_ulp/sysbuild.cmake b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/sysbuild.cmake new file mode 100644 index 000000000000..ec4b67f12bd6 --- /dev/null +++ b/samples/boards/espressif/ulp/lp_core/interrupt_ulp/sysbuild.cmake @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2024 Espressif + +# Add external project +ExternalZephyrProject_Add( + APPLICATION interrupt_ulp_lpcore + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_ULP_REMOTE_BOARD} + ) + +# Add dependencies so that the remote sample will be built first +# This is required because some primary cores need information from the +# remote core's build, such as the output image's LMA +add_dependencies(interrupt_ulp interrupt_ulp_lpcore) +sysbuild_add_dependencies(CONFIGURE interrupt_ulp interrupt_ulp_lpcore) +sysbuild_add_dependencies(FLASH interrupt_ulp_lpcore interrupt_ulp) + +if(SB_CONFIG_BOOTLOADER_MCUBOOT) + # Make sure MCUboot is flashed first + sysbuild_add_dependencies(FLASH interrupt_ulp mcuboot) +endif() diff --git a/samples/cpp/hello_world/sample.yaml b/samples/cpp/hello_world/sample.yaml index 244c7b4f3453..bae5608d9a1b 100644 --- a/samples/cpp/hello_world/sample.yaml +++ b/samples/cpp/hello_world/sample.yaml @@ -22,3 +22,4 @@ tests: - intel_ish_5_4_1 - intel_ish_5_6_0 - intel_ish_5_8_0 + - esp32c6_devkitc/esp32c6/lpcore diff --git a/samples/net/wifi/shell/sample.yaml b/samples/net/wifi/shell/sample.yaml index 82be44c22cc6..d39379bd6136 100644 --- a/samples/net/wifi/shell/sample.yaml +++ b/samples/net/wifi/shell/sample.yaml @@ -90,7 +90,7 @@ tests: - esp32c3_devkitm - esp32s3_devkitm/esp32s3/procpu - esp8684_devkitm - - esp32c6_devkitc + - esp32c6_devkitc/esp32c6/hpcore sample.net.wifi.siwx91x_offloaded: extra_args: - CONFIG_WIFI_SILABS_SIWX91X_NET_STACK_OFFLOAD=y diff --git a/samples/net/wifi/shell/socs/esp32c6.conf b/samples/net/wifi/shell/socs/esp32c6_hpcore.conf similarity index 100% rename from samples/net/wifi/shell/socs/esp32c6.conf rename to samples/net/wifi/shell/socs/esp32c6_hpcore.conf diff --git a/samples/net/wifi/shell/socs/esp32c6.overlay b/samples/net/wifi/shell/socs/esp32c6_hpcore.overlay similarity index 100% rename from samples/net/wifi/shell/socs/esp32c6.overlay rename to samples/net/wifi/shell/socs/esp32c6_hpcore.overlay diff --git a/samples/subsys/settings/socs/esp32c6.conf b/samples/subsys/settings/socs/esp32c6_hpcore.conf similarity index 100% rename from samples/subsys/settings/socs/esp32c6.conf rename to samples/subsys/settings/socs/esp32c6_hpcore.conf diff --git a/samples/sysbuild/with_mcuboot/sample.yaml b/samples/sysbuild/with_mcuboot/sample.yaml index 2478fa9df345..0348b74dfe30 100644 --- a/samples/sysbuild/with_mcuboot/sample.yaml +++ b/samples/sysbuild/with_mcuboot/sample.yaml @@ -13,14 +13,14 @@ tests: - esp32s2_devkitc - esp32s3_devkitm/esp32s3/procpu - esp32c3_devkitm - - esp32c6_devkitc + - esp32c6_devkitc/esp32c6/hpcore integration_platforms: - nrf52840dk/nrf52840 - esp32_devkitc_wrover/esp32/procpu - esp32s2_devkitc - esp32s3_devkitm/esp32s3/procpu - esp32c3_devkitm - - esp32c6_devkitc + - esp32c6_devkitc/esp32c6/hpcore tags: mcuboot harness: console harness_config: diff --git a/soc/espressif/Kconfig b/soc/espressif/Kconfig index 7a3b927957c9..483ac468b67a 100644 --- a/soc/espressif/Kconfig +++ b/soc/espressif/Kconfig @@ -62,4 +62,6 @@ config RTC_CLK_CAL_CYCLES If the crystal could not start, it will be switched to internal RC. endmenu +rsource "Kconfig.ulp" + endif # SOC_FAMILY_ESPRESSIF_ESP32 diff --git a/soc/espressif/Kconfig.ulp b/soc/espressif/Kconfig.ulp new file mode 100644 index 000000000000..d45c9f2d971f --- /dev/null +++ b/soc/espressif/Kconfig.ulp @@ -0,0 +1,88 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +menu "Ultra Low Power (ULP) Coprocessor" + +config ULP_COPROC_ENABLED + bool "Ultra Low Power (ULP) Coprocessor" + default y if SOC_ESP32C6_LPCORE + select SOC_LATE_INIT_HOOK if SOC_ESP32C6_HPCORE + select HWINFO if SOC_ESP32C6_HPCORE + help + Enable this feature if you plan to use the ULP Coprocessor. + Once this option is enabled, further ULP co-processor configuration will appear in the menu. + +choice ULP_COPROC_TYPE + prompt "ULP Coprocessor type" + depends on ULP_COPROC_ENABLED + default ULP_COPROC_TYPE_LP_CORE if SOC_SERIES_ESP32C6 + help + Choose the ULP Coprocessor type: ULP FSM (Finite State Machine) or ULP RISC-V. + +config ULP_COPROC_TYPE_FSM + bool "ULP FSM (Finite State Machine)" + depends on SOC_SERIES_ESP32 || SOC_SERIES_ESP32S2 || SOC_SERIES_ESP32S3 + +config ULP_COPROC_TYPE_RISCV + bool "ULP RISC-V" + depends on SOC_SERIES_ESP32S2 || SOC_SERIES_ESP32S3 + +config ULP_COPROC_TYPE_LP_CORE + bool "LP core RISC-V" + depends on SOC_SERIES_ESP32C6 +endchoice + +menu "ULP RISC-V Settings" + depends on ULP_COPROC_TYPE_RISCV + +config ULP_RISCV_INTERRUPT_ENABLE + bool "ULP RISC-V interrupts" + help + Turn on this setting to enabled interrupts on the ULP RISC-V core. + +endmenu + +menu "ULP Debugging Options" + +config ULP_PANIC_OUTPUT_ENABLE + bool "Panic handler outputs to LP UART" + depends on ULP_COPROC_TYPE_LP_CORE + help + Set this option to enable panic handler functionality. If this option is + enabled then the LP Core will output a panic dump over LP UART, + similar to what the main core does. Output depends on LP UART already being + initialized and configured. + Disabling this option will reduce the LP core binary size by not + linking in panic handler functionality. + +config ULP_HP_UART_CONSOLE_PRINT + bool "Route lp_core_printf to the console HP-UART" + depends on ULP_COPROC_TYPE_LP_CORE + help + Set this option to route lp_core_printf to the console HP-UART. + This allows you to easily view print outputs from the LP core, without + having to connect to the LP-UART. This option comes with the following + limitations: + + 1. There is no mutual exclusion between the HP-Core and the LP-Core accessing + the HP-UART, which means that if both cores are logging heavily the output + strings might get mangled together. + 2. The HP-UART can only work while the HP-Core is running, which means that + if the HP-Core is in deep sleep, the LP-Core will not be able to print to the + console HP-UART. + + Due to these limitations it is only recommended to use this option for easy debugging. + For more serious use-cases you should use the LP-UART. + +config ULP_NORESET_UNDER_DEBUG + bool "Avoid resetting LP core when debugger is attached" + depends on ULP_COPROC_TYPE_LP_CORE + default y + help + Enable this feature to avoid resetting LP core in sleep mode when debugger is attached, + otherwise configured HW breakpoints and dcsr.ebreak* bits will be missed. + This is a workaround until it will be fixed in HW. + +endmenu + +endmenu # Ultra Low Power (ULP) Coprocessor diff --git a/soc/espressif/common/Kconfig.defconfig b/soc/espressif/common/Kconfig.defconfig index 9e33c4ff7ea3..bcc34a1a52ca 100644 --- a/soc/espressif/common/Kconfig.defconfig +++ b/soc/espressif/common/Kconfig.defconfig @@ -4,7 +4,7 @@ if SOC_SERIES_ESP32C2 || SOC_SERIES_ESP32C3 || SOC_SERIES_ESP32C6 config GEN_ISR_TABLES - default y + default y if !SOC_ESP32C6_LPCORE config GEN_SW_ISR_TABLE default y @@ -13,7 +13,7 @@ config GEN_IRQ_VECTOR_TABLE default n config DYNAMIC_INTERRUPTS - default y + default y if !SOC_ESP32C6_LPCORE config ISR_STACK_SIZE default 2048 diff --git a/soc/espressif/esp32c6/CMakeLists.txt b/soc/espressif/esp32c6/CMakeLists.txt index 6bd5b99e6ff5..68b9c20ed7d3 100644 --- a/soc/espressif/esp32c6/CMakeLists.txt +++ b/soc/espressif/esp32c6/CMakeLists.txt @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_sources( +zephyr_sources_ifdef(CONFIG_SOC_ESP32C6_HPCORE vectors.S soc_irq.S soc_irq.c @@ -8,17 +8,26 @@ zephyr_sources( ../common/loader.c ) -zephyr_include_directories(.) +zephyr_sources_ifdef(CONFIG_SOC_ESP32C6_LPCORE + vector_table_lpcore.S + vectors_lpcore.S + start_lpcore.S + soc_lpcore.c + ) -zephyr_sources_ifndef(CONFIG_BOOTLOADER_MCUBOOT hw_init.c) +zephyr_include_directories(.) -zephyr_library_sources_ifdef(CONFIG_PM power.c) -zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) +if(CONFIG_SOC_ESP32C6_HPCORE) + zephyr_sources_ifndef(CONFIG_BOOTLOADER_MCUBOOT hw_init.c) + zephyr_library_sources_ifdef(CONFIG_PM power.c) + zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) + zephyr_sources_ifdef(CONFIG_ULP_COPROC_ENABLED hpcore_init_ulp.c) +endif() # get flash size to use in esptool as string math(EXPR esptoolpy_flashsize "${CONFIG_FLASH_SIZE} / 0x100000") -if(NOT CONFIG_BOOTLOADER_MCUBOOT) +if(NOT CONFIG_BOOTLOADER_MCUBOOT AND NOT CONFIG_SOC_ESP32C6_LPCORE) if(CONFIG_BUILD_OUTPUT_BIN) # make ESP ROM loader compatible image @@ -42,18 +51,26 @@ if(NOT CONFIG_BOOTLOADER_MCUBOOT) endif() -# get code-partition slot0 address -dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") +if(CONFIG_SOC_ESP32C6_HPCORE) + # Get code-partition slot0 address + dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") +elseif(CONFIG_SOC_ESP32C6_LPCORE) + dt_nodelabel(dts_partition_path NODELABEL "slot0_lpcore_partition") +endif() dt_reg_addr(img_0_off PATH ${dts_partition_path}) # get code-partition boot address dt_nodelabel(dts_partition_path NODELABEL "boot_partition") dt_reg_addr(boot_off PATH ${dts_partition_path}) -if(CONFIG_BOOTLOADER_MCUBOOT) +if(CONFIG_SOC_ESP32C6_HPCORE) + if(CONFIG_BOOTLOADER_MCUBOOT) + board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") + else() + board_finalize_runner_args(esp32 "--esp-app-address=${boot_off}") + endif() +elseif(CONFIG_SOC_ESP32C6_LPCORE) board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") -else() - board_finalize_runner_args(esp32 "--esp-app-address=${boot_off}") endif() if(CONFIG_MCUBOOT) @@ -71,6 +88,8 @@ endif() if(CONFIG_MCUBOOT) set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/mcuboot.ld CACHE INTERNAL "") +elseif(CONFIG_SOC_ESP32C6_LPCORE) + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default_lpcore.ld CACHE INTERNAL "") else() set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default.ld CACHE INTERNAL "") endif() diff --git a/soc/espressif/esp32c6/Kconfig b/soc/espressif/esp32c6/Kconfig index 3908eb4ee1e0..a43328002758 100644 --- a/soc/espressif/esp32c6/Kconfig +++ b/soc/espressif/esp32c6/Kconfig @@ -4,14 +4,15 @@ config SOC_SERIES_ESP32C6 select RISCV select RISCV_SOC_HAS_GP_RELATIVE_ADDRESSING - select DYNAMIC_INTERRUPTS - select CLOCK_CONTROL - select PINCTRL + select DYNAMIC_INTERRUPTS if SOC_ESP32C6_HPCORE + select CLOCK_CONTROL if SOC_ESP32C6_HPCORE + select PINCTRL if SOC_ESP32C6_HPCORE select RISCV_ISA_RV32I select RISCV_ISA_EXT_A select RISCV_ISA_EXT_M select RISCV_ISA_EXT_C select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI if SOC_ESP32C6_LPCORE select HAS_ESPRESSIF_HAL select HAS_PM select HAS_POWEROFF diff --git a/soc/espressif/esp32c6/Kconfig.defconfig b/soc/espressif/esp32c6/Kconfig.defconfig index 69a04a39a37b..86fc3369d92f 100644 --- a/soc/espressif/esp32c6/Kconfig.defconfig +++ b/soc/espressif/esp32c6/Kconfig.defconfig @@ -18,3 +18,25 @@ config MAIN_STACK_SIZE default 2048 endif # SOC_SERIES_ESP32C6 + +if SOC_ESP32C6_LPCORE + +config GEN_ISR_TABLES + default n + +config SYS_CLOCK_EXISTS + default n + +config KERNEL_MEM_POOL + default n + +config COMMON_LIBC_MALLOC_ARENA_SIZE + default 0 + +config MULTITHREADING + default n + +config NUM_PREEMPT_PRIORITIES + default 0 + +endif diff --git a/soc/espressif/esp32c6/Kconfig.soc b/soc/espressif/esp32c6/Kconfig.soc index 0fe5f8faa058..285478169f6a 100644 --- a/soc/espressif/esp32c6/Kconfig.soc +++ b/soc/espressif/esp32c6/Kconfig.soc @@ -17,6 +17,16 @@ config SOC_ESP32C6 bool select SOC_SERIES_ESP32C6 +config SOC_ESP32C6_HPCORE + bool + help + This hidden configuration defines that build is targeted for HP CORE. + +config SOC_ESP32C6_LPCORE + bool + help + This hidden configuration defines that build is targeted for LP CORE. + config SOC_SERIES default "esp32c6" if SOC_SERIES_ESP32C6 diff --git a/soc/espressif/esp32c6/default.ld b/soc/espressif/esp32c6/default.ld index 74a6e13301e0..3cc5124c505d 100644 --- a/soc/espressif/esp32c6/default.ld +++ b/soc/espressif/esp32c6/default.ld @@ -66,9 +66,13 @@ MEMORY irom0_0_seg(RX): org = IROM_SEG_ORG, len = IROM_SEG_LEN drom0_0_seg(R): org = DROM_SEG_ORG, len = DROM_SEG_LEN +#if CONFIG_ULP_COPROC_ENABLED + lp_ram_seg(RW): org = LPSRAM_IRAM_START + ULP_COPROC_RESERVE_MEM, + len = LPSRAM_SIZE - ULP_COPROC_RESERVE_MEM - CONFIG_RESERVE_RTC_MEM +#else lp_ram_seg(RW): org = LPSRAM_IRAM_START, len = 0x4000 - CONFIG_RESERVE_RTC_MEM - +#endif /* We reduced the size of lp_ram_seg by CONFIG_RESERVE_RTC_MEM value. It reserves the amount of LP memory that we use for this memory segment. This segment is intended for keeping: @@ -186,7 +190,6 @@ SECTIONS #endif /* --- START OF RTC --- */ - .rtc.text : { . = ALIGN(4); diff --git a/soc/espressif/esp32c6/default_lpcore.ld b/soc/espressif/esp32c6/default_lpcore.ld new file mode 100644 index 000000000000..2730eaffbb4c --- /dev/null +++ b/soc/espressif/esp32c6/default_lpcore.ld @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +#include "memory.h" + +#define ALIGN_DOWN(SIZE, AL) (SIZE & ~(AL - 1)) +/* Ensure the end where the shared memory starts is aligned to 8 bytes + if updating this also update the same in ulp_lp_core_memory_shared.c + */ +#define ALIGNED_COPROC_MEM ALIGN_DOWN(ULP_COPROC_RESERVE_MEM, 0x8) + +#define RODATA_REGION ram +#define RAMABLE_REGION ram +#define ROMABLE_REGION ram + +/* User available memory segments */ +_aligned_coproc_mem = ALIGNED_COPROC_MEM; +_vector_table_org = LPSRAM_IRAM_START; +_vector_table_len = 0x80; +_ram_org = _vector_table_org + _vector_table_len; +_ram_len = _aligned_coproc_mem - _vector_table_len - ULP_SHARED_MEM; +_shared_mem_org = _ram_org + _ram_len; +_shared_mem_len = ULP_SHARED_MEM; + +ENTRY(reset_vector) + +MEMORY +{ + /*first 128byte for exception/interrupt vectors*/ + vector_table(RX) : ORIGIN = _vector_table_org , LENGTH = _vector_table_len + ram(RWX) : ORIGIN = _ram_org, LENGTH = _ram_len + shared_mem_ram(RW) : ORIGIN = _shared_mem_org, LENGTH = _shared_mem_len +} + +SECTIONS +{ + .vector.text : + { + __mtvec_base = .; + KEEP (*(.init.vector .init.vector.*)) + } > vector_table + + . = ORIGIN(ram); + + .text ALIGN(4): + { + *(.text.vectors) /* Default reset vector must link to offset 0x80 */ + __text_region_start = ABSOLUTE(.); + *(.text) + *(.text*) + *(.iram1) + *(.iram1.*) + __text_region_end = ABSOLUTE(.); + } >ram + + #include + + .rodata ALIGN(4): + { + __rodata_region_start = ABSOLUTE(.); + *(.rodata .srodata) + *(.rodata* .srodata*) + __rodata_region_end = .; + + } > ram + +#include + + .rodata.end ALIGN(4): + { + _rodata_reserved_end = ABSOLUTE(.); + } > ram + + .data ALIGN(4): + { + _image_ram_start = ABSOLUTE(.); + *(.data) + *(.data*) + *(.sdata) + *(.sdata*) + + } > ram + + #include + #include + #include + + .data.end ALIGN(4): + { + _image_ram_end = ABSOLUTE(.); + } > ram + + .data.noinit (NOLOAD): + { + . = ALIGN(4); + *(.noinit) + *(.noinit.*) + . = ALIGN(4); + } > ram + + .bss ALIGN(4) : + { + __bss_start = .; + *(.bss) + *(.bss*) + *(.sbss) + *(.sbss*) + PROVIDE(end = .); + __bss_end = .; + _heap_sentry = .; + } >ram + +#include + + __stack_top = ORIGIN(ram) + LENGTH(ram); + +#include + SECTION_PROLOGUE(.riscv.attributes, 0,) + { + KEEP(*(.riscv.attributes)) + KEEP(*(.gnu.attributes)) + } + + . = ORIGIN(shared_mem_ram); + .shared_mem (ALIGN(4)) : + { + KEEP(*(.shared_mem)) + } > shared_mem_ram +} diff --git a/soc/espressif/esp32c6/hpcore_init_ulp.c b/soc/espressif/esp32c6/hpcore_init_ulp.c new file mode 100644 index 000000000000..a35bc0f2f8af --- /dev/null +++ b/soc/espressif/esp32c6/hpcore_init_ulp.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "bootloader_flash_priv.h" +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); + +void IRAM_ATTR lp_core_image_init(void) +{ + const uint32_t lpcore_img_off = FIXED_PARTITION_OFFSET(slot0_lpcore_partition); + const uint32_t lpcore_img_size = DT_REG_SIZE(DT_NODELABEL(sramlp)); + int ret = 0; + + LOG_INF("Getting LPU image at %p, size %d", (void *)lpcore_img_off, lpcore_img_size); + + const uint8_t *data = (const uint8_t *)bootloader_mmap(lpcore_img_off, lpcore_img_size); + + ret = ulp_lp_core_load_binary(data, lpcore_img_size); + if (ret) { + LOG_ERR("Failed to load LP core image: %d", ret); + } + + LOG_INF("LP core image loaded"); + + /* Set LP core wakeup source as the HP CPU */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + + ret = ulp_lp_core_run(&cfg); + if (ret) { + LOG_ERR("Failed to start LP core: %d", ret); + } +} + +void soc_late_init_hook(void) +{ + uint32_t reset_cause; + hwinfo_get_reset_cause(&reset_cause); + + if (reset_cause != RESET_LOW_POWER_WAKE) { + LOG_INF("Not a ULP wakeup, initializing it!"); + lp_core_image_init(); + } +} diff --git a/soc/espressif/esp32c6/mcuboot.ld b/soc/espressif/esp32c6/mcuboot.ld index 8c76315ffe33..ea93c8e65156 100644 --- a/soc/espressif/esp32c6/mcuboot.ld +++ b/soc/espressif/esp32c6/mcuboot.ld @@ -55,6 +55,7 @@ SECTIONS *libkernel.a:kheap.*(.literal .text .literal.* .text.*) *libkernel.a:mempool.*(.literal .text .literal.* .text.*) + *libkernel.a:device.*(.literal .text .literal.* .text.*) *libzephyr.a:esp_loader.*(.literal .text .literal.* .text.*) *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) diff --git a/soc/espressif/esp32c6/memory.h b/soc/espressif/esp32c6/memory.h index 455c62aba03b..ad9e0b1b8176 100644 --- a/soc/espressif/esp32c6/memory.h +++ b/soc/espressif/esp32c6/memory.h @@ -5,15 +5,18 @@ #pragma once /* LP-SRAM (16kB) memory */ -#define LPSRAM_IRAM_START DT_REG_ADDR(DT_NODELABEL(sramlp)) -#define LPSRAM_SIZE DT_REG_SIZE(DT_NODELABEL(sramlp)) +#define LPSRAM_IRAM_START DT_REG_ADDR(DT_NODELABEL(sramlp)) +#define LPSRAM_SIZE (0x4000) +#define ULP_SHARED_MEM DT_REG_SIZE(DT_NODELABEL(shmlp)) +#define ULP_COPROC_RESERVE_MEM DT_REG_SIZE(DT_NODELABEL(sramlp)) + /* HP-SRAM (512kB) memory */ -#define HPSRAM_START DT_REG_ADDR(DT_NODELABEL(sramhp)) -#define HPSRAM_SIZE DT_REG_SIZE(DT_NODELABEL(sramhp)) -#define HPSRAM_DRAM_START HPSRAM_START -#define HPSRAM_IRAM_START HPSRAM_START +#define HPSRAM_START DT_REG_ADDR(DT_NODELABEL(sramhp)) +#define HPSRAM_SIZE DT_REG_SIZE(DT_NODELABEL(sramhp)) +#define HPSRAM_DRAM_START HPSRAM_START +#define HPSRAM_IRAM_START HPSRAM_START /* ICache size is fixed to 32KB on ESP32-C6 */ -#define ICACHE_SIZE 0x8000 +#define ICACHE_SIZE 0x8000 /** Simplified memory map for the bootloader. * Make sure the bootloader can load into main memory without overwriting itself. @@ -27,13 +30,13 @@ * buffers area (0x4087c610). */ -#define DRAM_BUFFERS_START 0x4086ad08 -#define DRAM_BUFFERS_END 0x4087c610 -#define DRAM_STACK_START DRAM_BUFFERS_END -#define DRAM_ROM_BSS_DATA_START 0x4087e610 +#define DRAM_BUFFERS_START 0x4086ad08 +#define DRAM_BUFFERS_END 0x4087c610 +#define DRAM_STACK_START DRAM_BUFFERS_END +#define DRAM_ROM_BSS_DATA_START 0x4087e610 /* Set the limit for the application runtime dynamic allocations */ -#define DRAM_RESERVED_START DRAM_BUFFERS_END +#define DRAM_RESERVED_START DRAM_BUFFERS_END /* For safety margin between bootloader data section and startup stacks */ #define BOOTLOADER_STACK_OVERHEAD 0x0 @@ -49,14 +52,14 @@ /* Start of the lower region is determined by region size and the end of the higher region */ #define BOOTLOADER_IRAM_LOADER_SEG_START (BOOTLOADER_USER_SRAM_END - BOOTLOADER_IRAM_LOADER_SEG_LEN) -#define BOOTLOADER_IRAM_SEG_START (BOOTLOADER_IRAM_LOADER_SEG_START - BOOTLOADER_IRAM_SEG_LEN) -#define BOOTLOADER_DRAM_SEG_START (BOOTLOADER_IRAM_SEG_START - BOOTLOADER_DRAM_SEG_LEN) +#define BOOTLOADER_IRAM_SEG_START (BOOTLOADER_IRAM_LOADER_SEG_START - BOOTLOADER_IRAM_SEG_LEN) +#define BOOTLOADER_DRAM_SEG_START (BOOTLOADER_IRAM_SEG_START - BOOTLOADER_DRAM_SEG_LEN) /* Flash */ #ifdef CONFIG_FLASH_SIZE -#define FLASH_SIZE CONFIG_FLASH_SIZE +#define FLASH_SIZE CONFIG_FLASH_SIZE #else -#define FLASH_SIZE 0x400000 +#define FLASH_SIZE 0x400000 #endif /* Cached memory */ diff --git a/soc/espressif/esp32c6/soc_lpcore.c b/soc/espressif/esp32c6/soc_lpcore.c new file mode 100644 index 000000000000..e2e5a5d2b53c --- /dev/null +++ b/soc/espressif/esp32c6/soc_lpcore.c @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" +#include "esp_rom_caps.h" +#include "rom/ets_sys.h" +#include "ulp_lp_core_utils.h" +#include "ulp_lp_core_lp_timer_shared.h" +#include "ulp_lp_core_memory_shared.h" +#include "ulp_lp_core_print.h" +#include +#include + +extern void main(void); + +/* Initialize lp core related system functions before calling user's main*/ +void lp_core_startup(void) +{ +#if CONFIG_ULP_HP_UART_CONSOLE_PRINT && ESP_ROM_HAS_LP_ROM + ets_install_putc1(lp_core_print_char); +#endif + + ulp_lp_core_update_wakeup_cause(); + + /* Start Zephyr */ + z_cstart(); + + CODE_UNREACHABLE; +} diff --git a/soc/espressif/esp32c6/start_lpcore.S b/soc/espressif/esp32c6/start_lpcore.S new file mode 100644 index 000000000000..deadee0add7e --- /dev/null +++ b/soc/espressif/esp32c6/start_lpcore.S @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + .section .text.vectors + .global reset_vector + +/* The reset vector, jumps to startup code */ +reset_vector: + + /* _vector_table: Only 256-byte aligned addresses are allowed */ + la t0, _vector_table + csrw mtvec, t0 + + j __start + +__start: + + /* setup the stack pointer */ + la sp, __stack_top + call lp_core_startup +loop: + j loop diff --git a/soc/espressif/esp32c6/vector_table_lpcore.S b/soc/espressif/esp32c6/vector_table_lpcore.S new file mode 100644 index 000000000000..a1309e3cf817 --- /dev/null +++ b/soc/espressif/esp32c6/vector_table_lpcore.S @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + .section .init.vector,"ax" + + .global _vector_table + .type _vector_table, @function +_vector_table: + .option push + .option norvc + + .rept 30 + j _panic_handler + .endr + j _interrupt_handler // All interrupts are routed to mtvec + 4*30, i.e. the 31st entry + j _panic_handler + + .option pop + .size _vector_table, .-_vector_table diff --git a/soc/espressif/esp32c6/vectors_lpcore.S b/soc/espressif/esp32c6/vectors_lpcore.S new file mode 100644 index 000000000000..360977cadd1b --- /dev/null +++ b/soc/espressif/esp32c6/vectors_lpcore.S @@ -0,0 +1,142 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "riscv/rvruntime-frames.h" +#include + + .equ SAVE_REGS, 32 + .equ CONTEXT_SIZE, (SAVE_REGS * 4) +/* Macro which first allocates space on the stack to save general + * purpose registers, and then save them. GP register is excluded. + * The default size allocated on the stack is CONTEXT_SIZE, but it + * can be overridden. */ +.macro save_general_regs cxt_size=CONTEXT_SIZE + addi sp, sp, -\cxt_size + sw ra, RV_STK_RA(sp) + sw tp, RV_STK_TP(sp) + sw t0, RV_STK_T0(sp) + sw t1, RV_STK_T1(sp) + sw t2, RV_STK_T2(sp) + sw s0, RV_STK_S0(sp) + sw s1, RV_STK_S1(sp) + sw a0, RV_STK_A0(sp) + sw a1, RV_STK_A1(sp) + sw a2, RV_STK_A2(sp) + sw a3, RV_STK_A3(sp) + sw a4, RV_STK_A4(sp) + sw a5, RV_STK_A5(sp) + sw a6, RV_STK_A6(sp) + sw a7, RV_STK_A7(sp) + sw s2, RV_STK_S2(sp) + sw s3, RV_STK_S3(sp) + sw s4, RV_STK_S4(sp) + sw s5, RV_STK_S5(sp) + sw s6, RV_STK_S6(sp) + sw s7, RV_STK_S7(sp) + sw s8, RV_STK_S8(sp) + sw s9, RV_STK_S9(sp) + sw s10, RV_STK_S10(sp) + sw s11, RV_STK_S11(sp) + sw t3, RV_STK_T3(sp) + sw t4, RV_STK_T4(sp) + sw t5, RV_STK_T5(sp) + sw t6, RV_STK_T6(sp) +.endm + +.macro save_mepc + csrr t0, mepc + sw t0, RV_STK_MEPC(sp) +.endm + +/* Restore the general purpose registers (excluding gp) from the context on + * the stack. The context is then deallocated. The default size is CONTEXT_SIZE + * but it can be overridden. */ +.macro restore_general_regs cxt_size=CONTEXT_SIZE + lw ra, RV_STK_RA(sp) + lw tp, RV_STK_TP(sp) + lw t0, RV_STK_T0(sp) + lw t1, RV_STK_T1(sp) + lw t2, RV_STK_T2(sp) + lw s0, RV_STK_S0(sp) + lw s1, RV_STK_S1(sp) + lw a0, RV_STK_A0(sp) + lw a1, RV_STK_A1(sp) + lw a2, RV_STK_A2(sp) + lw a3, RV_STK_A3(sp) + lw a4, RV_STK_A4(sp) + lw a5, RV_STK_A5(sp) + lw a6, RV_STK_A6(sp) + lw a7, RV_STK_A7(sp) + lw s2, RV_STK_S2(sp) + lw s3, RV_STK_S3(sp) + lw s4, RV_STK_S4(sp) + lw s5, RV_STK_S5(sp) + lw s6, RV_STK_S6(sp) + lw s7, RV_STK_S7(sp) + lw s8, RV_STK_S8(sp) + lw s9, RV_STK_S9(sp) + lw s10, RV_STK_S10(sp) + lw s11, RV_STK_S11(sp) + lw t3, RV_STK_T3(sp) + lw t4, RV_STK_T4(sp) + lw t5, RV_STK_T5(sp) + lw t6, RV_STK_T6(sp) + addi sp,sp, \cxt_size +.endm + +.macro restore_mepc + lw t0, RV_STK_MEPC(sp) + csrw mepc, t0 +.endm + + +/* _panic_handler: handle all exception */ + .section .text.handlers,"ax" + .global _panic_handler + .type _panic_handler, @function +_panic_handler: + save_general_regs RV_STK_FRMSZ + save_mepc + + addi t0, sp, RV_STK_FRMSZ /* Restore sp with the value when trap happened */ + + /* Save CSRs */ + sw t0, RV_STK_SP(sp) + csrr t0, mstatus + sw t0, RV_STK_MSTATUS(sp) + csrr t0, mcause + sw t0, RV_STK_MCAUSE(sp) + csrr t0, mtvec + sw t0, RV_STK_MTVEC(sp) + csrr t0, mhartid + sw t0, RV_STK_MHARTID(sp) + csrr t0, mtval + sw t0, RV_STK_MTVAL(sp) + + csrr a1, mcause /* Exception cause */ + + mv a0, sp /* RvExcFrame *regs */ + call ulp_lp_core_panic_handler +_end: + j _end /* loop forever */ + + +/* _interrupt_handler: handle all interrupt */ + .section .text.handlers,"ax" + .global _interrupt_handler + .type _interrupt_handler, @function +_interrupt_handler: + /* Save registers & mepc to stack */ + save_general_regs + save_mepc + + call ulp_lp_core_intr_handler + + /* Restore registers & mepc from stack */ + restore_mepc + restore_general_regs + /* Exit, this will also re-enable the interrupts */ + mret diff --git a/soc/espressif/soc.yml b/soc/espressif/soc.yml index 1ec21c88aaea..cd20df8a60b1 100644 --- a/soc/espressif/soc.yml +++ b/soc/espressif/soc.yml @@ -25,3 +25,6 @@ family: - name: esp32c6 socs: - name: esp32c6 + cpuclusters: + - name: hpcore + - name: lpcore diff --git a/tests/boards/espressif/rtc_clk/README.rst b/tests/boards/espressif/rtc_clk/README.rst index 8cd4853517e4..48db070183c2 100644 --- a/tests/boards/espressif/rtc_clk/README.rst +++ b/tests/boards/espressif/rtc_clk/README.rst @@ -14,7 +14,7 @@ Supported Boards **************** - esp32_devkitc_wrover/esp32/procpu - esp32c3_devkitm -- esp32c6_devkitc +- esp32c6_devkitc/esp32c6/hpcore - esp32s2_saola - esp32s3_devkitm/esp32s3/procpu diff --git a/tests/boards/espressif/rtc_clk/testcase.yaml b/tests/boards/espressif/rtc_clk/testcase.yaml index 5d0cb264b1c8..2a13a3728f92 100644 --- a/tests/boards/espressif/rtc_clk/testcase.yaml +++ b/tests/boards/espressif/rtc_clk/testcase.yaml @@ -1,19 +1,19 @@ common: integration_platforms: - - esp32c6_devkitc + - esp32c6_devkitc/esp32c6/hpcore tests: boards.esp32.rtc_clk: platform_allow: - esp32_devkitc_wrover/esp32/procpu - esp32c3_devkitm - - esp32c6_devkitc + - esp32c6_devkitc/esp32c6/hpcore - esp32s2_saola - esp32s3_devkitm/esp32s3/procpu boards.esp32.rtc_clk.xtal: platform_allow: - esp32_devkitc_wrover/esp32/procpu - esp32c3_devkitm - - esp32c6_devkitc + - esp32c6_devkitc/esp32c6/hpcore - esp32s2_saola - esp32s3_devkitm/esp32s3/procpu harness_config: diff --git a/tests/boards/espressif/wifi/socs/esp32c6.overlay b/tests/boards/espressif/wifi/socs/esp32c6_hpcore.overlay similarity index 100% rename from tests/boards/espressif/wifi/socs/esp32c6.overlay rename to tests/boards/espressif/wifi/socs/esp32c6_hpcore.overlay diff --git a/tests/drivers/adc/adc_api/socs/esp32c6.conf b/tests/drivers/adc/adc_api/socs/esp32c6_hpcore.conf similarity index 100% rename from tests/drivers/adc/adc_api/socs/esp32c6.conf rename to tests/drivers/adc/adc_api/socs/esp32c6_hpcore.conf diff --git a/tests/drivers/adc/adc_api/socs/esp32c6.overlay b/tests/drivers/adc/adc_api/socs/esp32c6_hpcore.overlay similarity index 100% rename from tests/drivers/adc/adc_api/socs/esp32c6.overlay rename to tests/drivers/adc/adc_api/socs/esp32c6_hpcore.overlay diff --git a/tests/drivers/counter/counter_basic_api/socs/esp32c6.overlay b/tests/drivers/counter/counter_basic_api/socs/esp32c6_hpcore.overlay similarity index 100% rename from tests/drivers/counter/counter_basic_api/socs/esp32c6.overlay rename to tests/drivers/counter/counter_basic_api/socs/esp32c6_hpcore.overlay diff --git a/tests/drivers/dma/loop_transfer/boards/esp32c6_devkitc.conf b/tests/drivers/dma/loop_transfer/boards/esp32c6_devkitc_hpcore.conf similarity index 100% rename from tests/drivers/dma/loop_transfer/boards/esp32c6_devkitc.conf rename to tests/drivers/dma/loop_transfer/boards/esp32c6_devkitc_hpcore.conf diff --git a/tests/drivers/dma/loop_transfer/boards/esp32c6_devkitc.overlay b/tests/drivers/dma/loop_transfer/boards/esp32c6_devkitc_hpcore.overlay similarity index 100% rename from tests/drivers/dma/loop_transfer/boards/esp32c6_devkitc.overlay rename to tests/drivers/dma/loop_transfer/boards/esp32c6_devkitc_hpcore.overlay diff --git a/tests/drivers/pwm/pwm_api/boards/esp32c6_devkitc.overlay b/tests/drivers/pwm/pwm_api/boards/esp32c6_devkitc_hpcore.overlay similarity index 100% rename from tests/drivers/pwm/pwm_api/boards/esp32c6_devkitc.overlay rename to tests/drivers/pwm/pwm_api/boards/esp32c6_devkitc_hpcore.overlay diff --git a/tests/drivers/pwm/pwm_gpio_loopback/socs/esp32c6.overlay b/tests/drivers/pwm/pwm_gpio_loopback/socs/esp32c6_hpcore.overlay similarity index 100% rename from tests/drivers/pwm/pwm_gpio_loopback/socs/esp32c6.overlay rename to tests/drivers/pwm/pwm_gpio_loopback/socs/esp32c6_hpcore.overlay diff --git a/tests/drivers/pwm/pwm_gpio_loopback/testcase.yaml b/tests/drivers/pwm/pwm_gpio_loopback/testcase.yaml index 1cc0dd5b7971..45c18be499eb 100644 --- a/tests/drivers/pwm/pwm_gpio_loopback/testcase.yaml +++ b/tests/drivers/pwm/pwm_gpio_loopback/testcase.yaml @@ -12,7 +12,7 @@ tests: - esp32_devkitc_wrover/esp32/procpu - esp8684_devkitm - esp32c3_devkitm - - esp32c6_devkitc + - esp32c6_devkitc/esp32c6/hpcore - esp32s2_saola - esp32s3_devkitm/esp32s3/procpu diff --git a/tests/drivers/pwm/pwm_loopback/socs/esp32c6.overlay b/tests/drivers/pwm/pwm_loopback/socs/esp32c6_hpcore.overlay similarity index 100% rename from tests/drivers/pwm/pwm_loopback/socs/esp32c6.overlay rename to tests/drivers/pwm/pwm_loopback/socs/esp32c6_hpcore.overlay diff --git a/tests/drivers/spi/spi_loopback/socs/esp32c6.conf b/tests/drivers/spi/spi_loopback/socs/esp32c6_hpcore.conf similarity index 100% rename from tests/drivers/spi/spi_loopback/socs/esp32c6.conf rename to tests/drivers/spi/spi_loopback/socs/esp32c6_hpcore.conf diff --git a/tests/drivers/spi/spi_loopback/socs/esp32c6.overlay b/tests/drivers/spi/spi_loopback/socs/esp32c6_hpcore.overlay similarity index 100% rename from tests/drivers/spi/spi_loopback/socs/esp32c6.overlay rename to tests/drivers/spi/spi_loopback/socs/esp32c6_hpcore.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/esp32c6_devkitc.conf b/tests/drivers/uart/uart_async_api/boards/esp32c6_devkitc_hpcore.conf similarity index 100% rename from tests/drivers/uart/uart_async_api/boards/esp32c6_devkitc.conf rename to tests/drivers/uart/uart_async_api/boards/esp32c6_devkitc_hpcore.conf diff --git a/tests/drivers/uart/uart_async_api/boards/esp32c6_devkitc.overlay b/tests/drivers/uart/uart_async_api/boards/esp32c6_devkitc_hpcore.overlay similarity index 100% rename from tests/drivers/uart/uart_async_api/boards/esp32c6_devkitc.overlay rename to tests/drivers/uart/uart_async_api/boards/esp32c6_devkitc_hpcore.overlay diff --git a/tests/drivers/uart/uart_elementary/socs/esp32c6.overlay b/tests/drivers/uart/uart_elementary/socs/esp32c6_hpcore.overlay similarity index 100% rename from tests/drivers/uart/uart_elementary/socs/esp32c6.overlay rename to tests/drivers/uart/uart_elementary/socs/esp32c6_hpcore.overlay diff --git a/tests/drivers/uart/uart_elementary/testcase.yaml b/tests/drivers/uart/uart_elementary/testcase.yaml index cbf0327e48ff..659f721d9f5c 100644 --- a/tests/drivers/uart/uart_elementary/testcase.yaml +++ b/tests/drivers/uart/uart_elementary/testcase.yaml @@ -19,7 +19,7 @@ tests: - esp32_devkitc_wrover/esp32/procpu - esp8684_devkitm - esp32c3_devkitm - - esp32c6_devkitc + - esp32c6_devkitc/esp32c6/hpcore - esp32s2_saola - esp32s3_devkitm/esp32s3/procpu integration_platforms: diff --git a/west.yml b/west.yml index c90f2caed76a..5a9dd6726faf 100644 --- a/west.yml +++ b/west.yml @@ -162,7 +162,7 @@ manifest: groups: - hal - name: hal_espressif - revision: fbbe8f22f34cadc43b69f9eb3fca10e301874e36 + revision: pull/417/head path: modules/hal/espressif west-commands: west/west-commands.yml groups: