Merge branch 'feature/mailbox' into 'master'

feat(mailbox): define and implement a mailbox API for the ESP32-P4

See merge request espressif/esp-idf!39925
This commit is contained in:
Omar Chebib
2025-09-26 16:34:41 +08:00
43 changed files with 2385 additions and 291 deletions

View File

@@ -57,6 +57,9 @@ if(NOT non_os_build)
if(CONFIG_SOC_MODEM_SUPPORT_ETM)
list(APPEND srcs "modem/modem_etm.c")
endif()
if(CONFIG_SOC_PMU_SUPPORTED)
list(APPEND srcs "pmu_share_hw.c")
endif()
if(CONFIG_SOC_LIGHT_SLEEP_SUPPORTED)
list(APPEND srcs "sleep_modem.c"
"sleep_modes.c"

View File

@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Acquire PMU lock
*
* @note If any of the locks are taken, this API will wait until the lock is successfully acquired.
*/
void pmu_lock_acquire(void);
/**
* @brief Release PMU lock
*/
void pmu_lock_release(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* PMU is currently only used by the software mailbox, but it could be used by multiple components
*/
#include <esp_types.h>
#include "sdkconfig.h"
#include "esp_private/critical_section.h"
#include "esp_private/pmu_share_hw.h"
DEFINE_CRIT_SECTION_LOCK_STATIC(s_pmu_lock);
void pmu_lock_acquire(void)
{
esp_os_enter_critical(&s_pmu_lock);
}
void pmu_lock_release(void)
{
esp_os_exit_critical(&s_pmu_lock);
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -522,6 +522,11 @@ FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_intr_status(pmu_dev_t *hw)
hw->hp_ext.int_clr.reject = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_enable_sw_intr(pmu_dev_t *hw, bool enable)
{
hw->hp_ext.int_ena.sw = enable;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_wakeup_cause(pmu_dev_t *hw)
{
return hw->wakeup.status0;
@@ -703,6 +708,16 @@ FORCE_INLINE_ATTR void pmu_ll_lp_clear_intsts_mask(pmu_dev_t *hw, uint32_t mask)
hw->lp_ext.int_clr.val = mask;
}
FORCE_INLINE_ATTR void pmu_ll_lp_trigger_sw_intr(pmu_dev_t *hw)
{
hw->hp_lp_cpu_comm.lp_trigger_hp = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_trigger_sw_intr(pmu_dev_t *hw)
{
hw->hp_lp_cpu_comm.hp_trigger_lp = 1;
}
FORCE_INLINE_ATTR void pmu_ll_lp_clear_sw_intr_status(pmu_dev_t *hw)
{
hw->lp_ext.int_clr.sw_trigger = 1;

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -522,6 +522,11 @@ FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_intr_status(pmu_dev_t *hw)
hw->hp_ext.int_clr.reject = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_enable_sw_intr(pmu_dev_t *hw, bool enable)
{
hw->hp_ext.int_ena.sw = enable;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_wakeup_cause(pmu_dev_t *hw)
{
return hw->wakeup.status0;
@@ -542,6 +547,16 @@ FORCE_INLINE_ATTR void pmu_ll_lp_clear_intsts_mask(pmu_dev_t *hw, uint32_t mask)
hw->lp_ext.int_clr.val = mask;
}
FORCE_INLINE_ATTR void pmu_ll_lp_trigger_sw_intr(pmu_dev_t *hw)
{
hw->hp_lp_cpu_comm.lp_trigger_hp = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_trigger_sw_intr(pmu_dev_t *hw)
{
hw->hp_lp_cpu_comm.hp_trigger_lp = 1;
}
FORCE_INLINE_ATTR void pmu_ll_lp_clear_sw_intr_status(pmu_dev_t *hw)
{
hw->lp_ext.int_clr.sw_trigger = 1;

View File

@@ -0,0 +1,188 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The LL layer for ESP32-P4 LP Mailbox register operations
#pragma once
#include <stdlib.h>
#include <stdbool.h>
#include "soc/soc.h"
#include "soc/lp_mailbox_struct.h"
#include "soc/lp_mailbox_reg.h"
#include "hal/misc.h"
#include "esp_attr.h"
#define LP_MAILBOX_LL_MSG_COUNT 16U
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Get a message (32-bit value) from the LP mailbox.
*
* @param dev Pointer to the LP mailbox device structure.
* @param index Index of the message to retrieve (must be less than LP_MAILBOX_LL_MSG_COUNT).
*
* @return The 32-bit message value at the specified index, or 0 if the index is out of range.
*/
FORCE_INLINE_ATTR uint32_t lp_mailbox_ll_get_message(lp_mb_dev_t *dev, int index)
{
if (index < LP_MAILBOX_LL_MSG_COUNT) {
return (&dev->message_0.val)[index];
}
return 0;
}
/**
* @brief Set a message in the LP mailbox.
*
* @note Writing a message in the mailbox will set the corresponding message's intr_raw bit for
* both the LP and HP registers, regardless of the writer!
*
* @param dev Pointer to the LP mailbox device structure.
* @param index Index of the message to set (must be less than LP_MAILBOX_LL_MSG_COUNT).
* @param val Message (32-bit value) to write to the specified message index.
*/
FORCE_INLINE_ATTR void lp_mailbox_ll_set_message(lp_mb_dev_t *dev, int index, uint32_t val)
{
if (index < LP_MAILBOX_LL_MSG_COUNT) {
(&dev->message_0.val)[index] = val;
}
}
/**
* @brief Get the raw status of the LP core interrupt register.
*
* @param dev Pointer to the LP mailbox device structure.
*
* @return Raw interrupt status value.
*/
FORCE_INLINE_ATTR uint32_t lp_mailbox_ll_get_lp_intr_raw(lp_mb_dev_t *dev)
{
return dev->lp_int_raw.val;
}
/**
* @brief Clear LP core interrupt register bits.
*
* @param dev Pointer to the LP mailbox device structure.
* @param mask Bitmask of interrupts to clear, bit `i` represents message `i`.
*/
FORCE_INLINE_ATTR void lp_mailbox_ll_lp_intr_clear(lp_mb_dev_t *dev, uint32_t mask)
{
dev->lp_int_clr.val = mask;
}
/**
* @brief Get the LP core interrupt register status.
*
* @param dev Pointer to the LP mailbox device structure.
*
* @return Interrupt status value.
*/
FORCE_INLINE_ATTR uint32_t lp_mailbox_ll_lp_intr_status(lp_mb_dev_t *dev)
{
return dev->lp_int_st.val;
}
/**
* @brief Enable mailbox interrupts by mask for the LP core.
*
* @param dev Pointer to the LP mailbox device structure.
* @param mask Bitmask of interrupts to enable, bit `i` represents message `i`.
*
* @return Updated interrupt enable register value.
*/
FORCE_INLINE_ATTR uint32_t lp_mailbox_ll_lp_intr_enable_mask(lp_mb_dev_t *dev, uint32_t mask)
{
dev->lp_int_ena.val |= mask;
return dev->lp_int_ena.val;
}
/**
* @brief Disable LP core mailbox interrupts by mask.
*
* @param dev Pointer to the LP mailbox device structure.
* @param mask Bitmask of interrupts to disable, bit `i` represents message `i`.
*
* @return Updated interrupt enable register value.
*/
FORCE_INLINE_ATTR uint32_t lp_mailbox_ll_lp_intr_disable_mask(lp_mb_dev_t *dev, uint32_t mask)
{
dev->lp_int_ena.val &= ~mask;
return dev->lp_int_ena.val;
}
/**
* @brief Get the raw status of the HP core interrupt register.
*
* @param dev Pointer to the LP mailbox device structure.
*
* @return Raw interrupt status value.
*/
FORCE_INLINE_ATTR uint32_t lp_mailbox_ll_get_hp_intr_raw(lp_mb_dev_t *dev)
{
return dev->hp_int_raw.val;
}
/**
* @brief Clear HP core interrupt register bits.
*
* @param dev Pointer to the LP mailbox device structure.
* @param mask Bitmask of interrupts to clear, bit `i` represents message `i`.
*/
FORCE_INLINE_ATTR void lp_mailbox_ll_hp_intr_clear(lp_mb_dev_t *dev, uint32_t mask)
{
dev->hp_int_clr.val = mask;
}
/**
* @brief Get the HP core interrupt register status.
*
* @param dev Pointer to the LP mailbox device structure.
*
* @return Interrupt status value.
*/
FORCE_INLINE_ATTR uint32_t lp_mailbox_ll_hp_intr_status(lp_mb_dev_t *dev)
{
return dev->hp_int_st.val;
}
/**
* @brief Enable mailbox interrupts by mask for the HP core.
*
* @param dev Pointer to the LP mailbox device structure.
* @param mask Bitmask of interrupts to enable, bit `i` represents message `i`.
*
* @return Updated interrupt enable register value.
*/
FORCE_INLINE_ATTR uint32_t lp_mailbox_ll_hp_intr_enable_mask(lp_mb_dev_t *dev, uint32_t mask)
{
dev->hp_int_ena.val |= mask;
return dev->hp_int_ena.val;
}
/**
* @brief Disable HP core mailbox interrupts by mask.
*
* @param dev Pointer to the LP mailbox device structure.
* @param mask Bitmask of interrupts to disable, bit `i` represents message `i`.
*
* @return Updated interrupt enable register value.
*/
FORCE_INLINE_ATTR uint32_t lp_mailbox_ll_hp_intr_disable_mask(lp_mb_dev_t *dev, uint32_t mask)
{
dev->hp_int_ena.val &= ~mask;
return dev->hp_int_ena.val;
}
#ifdef __cplusplus
}
#endif

View File

@@ -493,6 +493,11 @@ FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_cause(pmu_dev_t *hw)
hw->wakeup.cntl4.slp_reject_cause_clr = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_enable_sw_intr(pmu_dev_t *hw, bool enable)
{
hw->hp_ext.int_ena.sw = enable;
}
FORCE_INLINE_ATTR bool pmu_ll_hp_is_sleep_wakeup(pmu_dev_t *hw)
{
return (hw->hp_ext.int_raw.wakeup == 1);
@@ -503,6 +508,16 @@ FORCE_INLINE_ATTR bool pmu_ll_hp_is_sleep_reject(pmu_dev_t *hw)
return (hw->hp_ext.int_raw.reject == 1);
}
FORCE_INLINE_ATTR void pmu_ll_lp_trigger_sw_intr(pmu_dev_t *hw)
{
hw->hp_lp_cpu_comm.lp_trigger_hp = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_trigger_sw_intr(pmu_dev_t *hw)
{
hw->hp_lp_cpu_comm.hp_trigger_lp = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_clear_sw_intr_status(pmu_dev_t *hw)
{
hw->hp_ext.int_clr.sw = 1;

View File

@@ -283,6 +283,10 @@ config SOC_LP_VAD_SUPPORTED
bool
default y
config SOC_LP_MAILBOX_SUPPORTED
bool
default y
config SOC_SPIRAM_SUPPORTED
bool
default y

View File

@@ -93,6 +93,7 @@
#define SOC_LP_SPI_SUPPORTED 1
#define SOC_LP_ADC_SUPPORTED 1
#define SOC_LP_VAD_SUPPORTED 1
#define SOC_LP_MAILBOX_SUPPORTED 1
#define SOC_SPIRAM_SUPPORTED 1
#define SOC_PSRAM_DMA_CAPABLE 1
#define SOC_SDMMC_HOST_SUPPORTED 1

View File

@@ -76,6 +76,7 @@ PROVIDE ( LP_AON_CLKRST = 0x50111000 );
PROVIDE ( EFUSE = 0x5012D000 );
PROVIDE ( LPPERI = 0x50120000 );
PROVIDE ( LP_TIMER = 0x50112000 );
PROVIDE ( LP_MAILBOX = 0x50118000 );
PROVIDE ( LP_UART = 0x50121000 );
PROVIDE ( LP_I2C = 0x50122000 );
PROVIDE ( LP_SPI = 0x50123000 );

View File

@@ -1,5 +1,5 @@
/**
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -11,197 +11,197 @@
extern "C" {
#endif
/** MB_MASSEGE_0_REG register
/** MB_MESSAGE_0_REG register
* need_des
*/
#define MB_MASSEGE_0_REG (DR_REG_MB_BASE + 0x0)
/** MB_MASSEGE_0 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_0_REG (DR_REG_MB_BASE + 0x0)
/** MB_MESSAGE_0 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_0 0xFFFFFFFFU
#define MB_MASSEGE_0_M (MB_MASSEGE_0_V << MB_MASSEGE_0_S)
#define MB_MASSEGE_0_V 0xFFFFFFFFU
#define MB_MASSEGE_0_S 0
#define MB_MESSAGE_0 0xFFFFFFFFU
#define MB_MESSAGE_0_M (MB_MESSAGE_0_V << MB_MESSAGE_0_S)
#define MB_MESSAGE_0_V 0xFFFFFFFFU
#define MB_MESSAGE_0_S 0
/** MB_MASSEGE_1_REG register
/** MB_MESSAGE_1_REG register
* need_des
*/
#define MB_MASSEGE_1_REG (DR_REG_MB_BASE + 0x4)
/** MB_MASSEGE_1 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_1_REG (DR_REG_MB_BASE + 0x4)
/** MB_MESSAGE_1 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_1 0xFFFFFFFFU
#define MB_MASSEGE_1_M (MB_MASSEGE_1_V << MB_MASSEGE_1_S)
#define MB_MASSEGE_1_V 0xFFFFFFFFU
#define MB_MASSEGE_1_S 0
#define MB_MESSAGE_1 0xFFFFFFFFU
#define MB_MESSAGE_1_M (MB_MESSAGE_1_V << MB_MESSAGE_1_S)
#define MB_MESSAGE_1_V 0xFFFFFFFFU
#define MB_MESSAGE_1_S 0
/** MB_MASSEGE_2_REG register
/** MB_MESSAGE_2_REG register
* need_des
*/
#define MB_MASSEGE_2_REG (DR_REG_MB_BASE + 0x8)
/** MB_MASSEGE_2 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_2_REG (DR_REG_MB_BASE + 0x8)
/** MB_MESSAGE_2 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_2 0xFFFFFFFFU
#define MB_MASSEGE_2_M (MB_MASSEGE_2_V << MB_MASSEGE_2_S)
#define MB_MASSEGE_2_V 0xFFFFFFFFU
#define MB_MASSEGE_2_S 0
#define MB_MESSAGE_2 0xFFFFFFFFU
#define MB_MESSAGE_2_M (MB_MESSAGE_2_V << MB_MESSAGE_2_S)
#define MB_MESSAGE_2_V 0xFFFFFFFFU
#define MB_MESSAGE_2_S 0
/** MB_MASSEGE_3_REG register
/** MB_MESSAGE_3_REG register
* need_des
*/
#define MB_MASSEGE_3_REG (DR_REG_MB_BASE + 0xc)
/** MB_MASSEGE_3 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_3_REG (DR_REG_MB_BASE + 0xc)
/** MB_MESSAGE_3 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_3 0xFFFFFFFFU
#define MB_MASSEGE_3_M (MB_MASSEGE_3_V << MB_MASSEGE_3_S)
#define MB_MASSEGE_3_V 0xFFFFFFFFU
#define MB_MASSEGE_3_S 0
#define MB_MESSAGE_3 0xFFFFFFFFU
#define MB_MESSAGE_3_M (MB_MESSAGE_3_V << MB_MESSAGE_3_S)
#define MB_MESSAGE_3_V 0xFFFFFFFFU
#define MB_MESSAGE_3_S 0
/** MB_MASSEGE_4_REG register
/** MB_MESSAGE_4_REG register
* need_des
*/
#define MB_MASSEGE_4_REG (DR_REG_MB_BASE + 0x10)
/** MB_MASSEGE_4 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_4_REG (DR_REG_MB_BASE + 0x10)
/** MB_MESSAGE_4 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_4 0xFFFFFFFFU
#define MB_MASSEGE_4_M (MB_MASSEGE_4_V << MB_MASSEGE_4_S)
#define MB_MASSEGE_4_V 0xFFFFFFFFU
#define MB_MASSEGE_4_S 0
#define MB_MESSAGE_4 0xFFFFFFFFU
#define MB_MESSAGE_4_M (MB_MESSAGE_4_V << MB_MESSAGE_4_S)
#define MB_MESSAGE_4_V 0xFFFFFFFFU
#define MB_MESSAGE_4_S 0
/** MB_MASSEGE_5_REG register
/** MB_MESSAGE_5_REG register
* need_des
*/
#define MB_MASSEGE_5_REG (DR_REG_MB_BASE + 0x14)
/** MB_MASSEGE_5 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_5_REG (DR_REG_MB_BASE + 0x14)
/** MB_MESSAGE_5 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_5 0xFFFFFFFFU
#define MB_MASSEGE_5_M (MB_MASSEGE_5_V << MB_MASSEGE_5_S)
#define MB_MASSEGE_5_V 0xFFFFFFFFU
#define MB_MASSEGE_5_S 0
#define MB_MESSAGE_5 0xFFFFFFFFU
#define MB_MESSAGE_5_M (MB_MESSAGE_5_V << MB_MESSAGE_5_S)
#define MB_MESSAGE_5_V 0xFFFFFFFFU
#define MB_MESSAGE_5_S 0
/** MB_MASSEGE_6_REG register
/** MB_MESSAGE_6_REG register
* need_des
*/
#define MB_MASSEGE_6_REG (DR_REG_MB_BASE + 0x18)
/** MB_MASSEGE_6 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_6_REG (DR_REG_MB_BASE + 0x18)
/** MB_MESSAGE_6 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_6 0xFFFFFFFFU
#define MB_MASSEGE_6_M (MB_MASSEGE_6_V << MB_MASSEGE_6_S)
#define MB_MASSEGE_6_V 0xFFFFFFFFU
#define MB_MASSEGE_6_S 0
#define MB_MESSAGE_6 0xFFFFFFFFU
#define MB_MESSAGE_6_M (MB_MESSAGE_6_V << MB_MESSAGE_6_S)
#define MB_MESSAGE_6_V 0xFFFFFFFFU
#define MB_MESSAGE_6_S 0
/** MB_MASSEGE_7_REG register
/** MB_MESSAGE_7_REG register
* need_des
*/
#define MB_MASSEGE_7_REG (DR_REG_MB_BASE + 0x1c)
/** MB_MASSEGE_7 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_7_REG (DR_REG_MB_BASE + 0x1c)
/** MB_MESSAGE_7 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_7 0xFFFFFFFFU
#define MB_MASSEGE_7_M (MB_MASSEGE_7_V << MB_MASSEGE_7_S)
#define MB_MASSEGE_7_V 0xFFFFFFFFU
#define MB_MASSEGE_7_S 0
#define MB_MESSAGE_7 0xFFFFFFFFU
#define MB_MESSAGE_7_M (MB_MESSAGE_7_V << MB_MESSAGE_7_S)
#define MB_MESSAGE_7_V 0xFFFFFFFFU
#define MB_MESSAGE_7_S 0
/** MB_MASSEGE_8_REG register
/** MB_MESSAGE_8_REG register
* need_des
*/
#define MB_MASSEGE_8_REG (DR_REG_MB_BASE + 0x20)
/** MB_MASSEGE_8 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_8_REG (DR_REG_MB_BASE + 0x20)
/** MB_MESSAGE_8 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_8 0xFFFFFFFFU
#define MB_MASSEGE_8_M (MB_MASSEGE_8_V << MB_MASSEGE_8_S)
#define MB_MASSEGE_8_V 0xFFFFFFFFU
#define MB_MASSEGE_8_S 0
#define MB_MESSAGE_8 0xFFFFFFFFU
#define MB_MESSAGE_8_M (MB_MESSAGE_8_V << MB_MESSAGE_8_S)
#define MB_MESSAGE_8_V 0xFFFFFFFFU
#define MB_MESSAGE_8_S 0
/** MB_MASSEGE_9_REG register
/** MB_MESSAGE_9_REG register
* need_des
*/
#define MB_MASSEGE_9_REG (DR_REG_MB_BASE + 0x24)
/** MB_MASSEGE_9 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_9_REG (DR_REG_MB_BASE + 0x24)
/** MB_MESSAGE_9 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_9 0xFFFFFFFFU
#define MB_MASSEGE_9_M (MB_MASSEGE_9_V << MB_MASSEGE_9_S)
#define MB_MASSEGE_9_V 0xFFFFFFFFU
#define MB_MASSEGE_9_S 0
#define MB_MESSAGE_9 0xFFFFFFFFU
#define MB_MESSAGE_9_M (MB_MESSAGE_9_V << MB_MESSAGE_9_S)
#define MB_MESSAGE_9_V 0xFFFFFFFFU
#define MB_MESSAGE_9_S 0
/** MB_MASSEGE_10_REG register
/** MB_MESSAGE_10_REG register
* need_des
*/
#define MB_MASSEGE_10_REG (DR_REG_MB_BASE + 0x28)
/** MB_MASSEGE_10 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_10_REG (DR_REG_MB_BASE + 0x28)
/** MB_MESSAGE_10 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_10 0xFFFFFFFFU
#define MB_MASSEGE_10_M (MB_MASSEGE_10_V << MB_MASSEGE_10_S)
#define MB_MASSEGE_10_V 0xFFFFFFFFU
#define MB_MASSEGE_10_S 0
#define MB_MESSAGE_10 0xFFFFFFFFU
#define MB_MESSAGE_10_M (MB_MESSAGE_10_V << MB_MESSAGE_10_S)
#define MB_MESSAGE_10_V 0xFFFFFFFFU
#define MB_MESSAGE_10_S 0
/** MB_MASSEGE_11_REG register
/** MB_MESSAGE_11_REG register
* need_des
*/
#define MB_MASSEGE_11_REG (DR_REG_MB_BASE + 0x2c)
/** MB_MASSEGE_11 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_11_REG (DR_REG_MB_BASE + 0x2c)
/** MB_MESSAGE_11 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_11 0xFFFFFFFFU
#define MB_MASSEGE_11_M (MB_MASSEGE_11_V << MB_MASSEGE_11_S)
#define MB_MASSEGE_11_V 0xFFFFFFFFU
#define MB_MASSEGE_11_S 0
#define MB_MESSAGE_11 0xFFFFFFFFU
#define MB_MESSAGE_11_M (MB_MESSAGE_11_V << MB_MESSAGE_11_S)
#define MB_MESSAGE_11_V 0xFFFFFFFFU
#define MB_MESSAGE_11_S 0
/** MB_MASSEGE_12_REG register
/** MB_MESSAGE_12_REG register
* need_des
*/
#define MB_MASSEGE_12_REG (DR_REG_MB_BASE + 0x30)
/** MB_MASSEGE_12 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_12_REG (DR_REG_MB_BASE + 0x30)
/** MB_MESSAGE_12 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_12 0xFFFFFFFFU
#define MB_MASSEGE_12_M (MB_MASSEGE_12_V << MB_MASSEGE_12_S)
#define MB_MASSEGE_12_V 0xFFFFFFFFU
#define MB_MASSEGE_12_S 0
#define MB_MESSAGE_12 0xFFFFFFFFU
#define MB_MESSAGE_12_M (MB_MESSAGE_12_V << MB_MESSAGE_12_S)
#define MB_MESSAGE_12_V 0xFFFFFFFFU
#define MB_MESSAGE_12_S 0
/** MB_MASSEGE_13_REG register
/** MB_MESSAGE_13_REG register
* need_des
*/
#define MB_MASSEGE_13_REG (DR_REG_MB_BASE + 0x34)
/** MB_MASSEGE_13 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_13_REG (DR_REG_MB_BASE + 0x34)
/** MB_MESSAGE_13 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_13 0xFFFFFFFFU
#define MB_MASSEGE_13_M (MB_MASSEGE_13_V << MB_MASSEGE_13_S)
#define MB_MASSEGE_13_V 0xFFFFFFFFU
#define MB_MASSEGE_13_S 0
#define MB_MESSAGE_13 0xFFFFFFFFU
#define MB_MESSAGE_13_M (MB_MESSAGE_13_V << MB_MESSAGE_13_S)
#define MB_MESSAGE_13_V 0xFFFFFFFFU
#define MB_MESSAGE_13_S 0
/** MB_MASSEGE_14_REG register
/** MB_MESSAGE_14_REG register
* need_des
*/
#define MB_MASSEGE_14_REG (DR_REG_MB_BASE + 0x38)
/** MB_MASSEGE_14 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_14_REG (DR_REG_MB_BASE + 0x38)
/** MB_MESSAGE_14 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_14 0xFFFFFFFFU
#define MB_MASSEGE_14_M (MB_MASSEGE_14_V << MB_MASSEGE_14_S)
#define MB_MASSEGE_14_V 0xFFFFFFFFU
#define MB_MASSEGE_14_S 0
#define MB_MESSAGE_14 0xFFFFFFFFU
#define MB_MESSAGE_14_M (MB_MESSAGE_14_V << MB_MESSAGE_14_S)
#define MB_MESSAGE_14_V 0xFFFFFFFFU
#define MB_MESSAGE_14_S 0
/** MB_MASSEGE_15_REG register
/** MB_MESSAGE_15_REG register
* need_des
*/
#define MB_MASSEGE_15_REG (DR_REG_MB_BASE + 0x3c)
/** MB_MASSEGE_15 : R/W; bitpos: [31:0]; default: 0;
#define MB_MESSAGE_15_REG (DR_REG_MB_BASE + 0x3c)
/** MB_MESSAGE_15 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
#define MB_MASSEGE_15 0xFFFFFFFFU
#define MB_MASSEGE_15_M (MB_MASSEGE_15_V << MB_MASSEGE_15_S)
#define MB_MASSEGE_15_V 0xFFFFFFFFU
#define MB_MASSEGE_15_S 0
#define MB_MESSAGE_15 0xFFFFFFFFU
#define MB_MESSAGE_15_M (MB_MESSAGE_15_V << MB_MESSAGE_15_S)
#define MB_MESSAGE_15_V 0xFFFFFFFFU
#define MB_MESSAGE_15_S 0
/** MB_LP_INT_RAW_REG register
* need_des

View File

@@ -1,5 +1,5 @@
/**
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -11,213 +11,213 @@ extern "C" {
#endif
/** Group: configure_register */
/** Type of massege_0 register
/** Type of message_0 register
* need_des
*/
typedef union {
struct {
/** massege_0 : R/W; bitpos: [31:0]; default: 0;
/** message_0 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_0:32;
uint32_t message_0:32;
};
uint32_t val;
} mb_massege_0_reg_t;
} mb_message_0_reg_t;
/** Type of massege_1 register
/** Type of message_1 register
* need_des
*/
typedef union {
struct {
/** massege_1 : R/W; bitpos: [31:0]; default: 0;
/** message_1 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_1:32;
uint32_t message_1:32;
};
uint32_t val;
} mb_massege_1_reg_t;
} mb_message_1_reg_t;
/** Type of massege_2 register
/** Type of message_2 register
* need_des
*/
typedef union {
struct {
/** massege_2 : R/W; bitpos: [31:0]; default: 0;
/** message_2 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_2:32;
uint32_t message_2:32;
};
uint32_t val;
} mb_massege_2_reg_t;
} mb_message_2_reg_t;
/** Type of massege_3 register
/** Type of message_3 register
* need_des
*/
typedef union {
struct {
/** massege_3 : R/W; bitpos: [31:0]; default: 0;
/** message_3 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_3:32;
uint32_t message_3:32;
};
uint32_t val;
} mb_massege_3_reg_t;
} mb_message_3_reg_t;
/** Type of massege_4 register
/** Type of message_4 register
* need_des
*/
typedef union {
struct {
/** massege_4 : R/W; bitpos: [31:0]; default: 0;
/** message_4 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_4:32;
uint32_t message_4:32;
};
uint32_t val;
} mb_massege_4_reg_t;
} mb_message_4_reg_t;
/** Type of massege_5 register
/** Type of message_5 register
* need_des
*/
typedef union {
struct {
/** massege_5 : R/W; bitpos: [31:0]; default: 0;
/** message_5 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_5:32;
uint32_t message_5:32;
};
uint32_t val;
} mb_massege_5_reg_t;
} mb_message_5_reg_t;
/** Type of massege_6 register
/** Type of message_6 register
* need_des
*/
typedef union {
struct {
/** massege_6 : R/W; bitpos: [31:0]; default: 0;
/** message_6 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_6:32;
uint32_t message_6:32;
};
uint32_t val;
} mb_massege_6_reg_t;
} mb_message_6_reg_t;
/** Type of massege_7 register
/** Type of message_7 register
* need_des
*/
typedef union {
struct {
/** massege_7 : R/W; bitpos: [31:0]; default: 0;
/** message_7 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_7:32;
uint32_t message_7:32;
};
uint32_t val;
} mb_massege_7_reg_t;
} mb_message_7_reg_t;
/** Type of massege_8 register
/** Type of message_8 register
* need_des
*/
typedef union {
struct {
/** massege_8 : R/W; bitpos: [31:0]; default: 0;
/** message_8 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_8:32;
uint32_t message_8:32;
};
uint32_t val;
} mb_massege_8_reg_t;
} mb_message_8_reg_t;
/** Type of massege_9 register
/** Type of message_9 register
* need_des
*/
typedef union {
struct {
/** massege_9 : R/W; bitpos: [31:0]; default: 0;
/** message_9 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_9:32;
uint32_t message_9:32;
};
uint32_t val;
} mb_massege_9_reg_t;
} mb_message_9_reg_t;
/** Type of massege_10 register
/** Type of message_10 register
* need_des
*/
typedef union {
struct {
/** massege_10 : R/W; bitpos: [31:0]; default: 0;
/** message_10 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_10:32;
uint32_t message_10:32;
};
uint32_t val;
} mb_massege_10_reg_t;
} mb_message_10_reg_t;
/** Type of massege_11 register
/** Type of message_11 register
* need_des
*/
typedef union {
struct {
/** massege_11 : R/W; bitpos: [31:0]; default: 0;
/** message_11 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_11:32;
uint32_t message_11:32;
};
uint32_t val;
} mb_massege_11_reg_t;
} mb_message_11_reg_t;
/** Type of massege_12 register
/** Type of message_12 register
* need_des
*/
typedef union {
struct {
/** massege_12 : R/W; bitpos: [31:0]; default: 0;
/** message_12 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_12:32;
uint32_t message_12:32;
};
uint32_t val;
} mb_massege_12_reg_t;
} mb_message_12_reg_t;
/** Type of massege_13 register
/** Type of message_13 register
* need_des
*/
typedef union {
struct {
/** massege_13 : R/W; bitpos: [31:0]; default: 0;
/** message_13 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_13:32;
uint32_t message_13:32;
};
uint32_t val;
} mb_massege_13_reg_t;
} mb_message_13_reg_t;
/** Type of massege_14 register
/** Type of message_14 register
* need_des
*/
typedef union {
struct {
/** massege_14 : R/W; bitpos: [31:0]; default: 0;
/** message_14 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_14:32;
uint32_t message_14:32;
};
uint32_t val;
} mb_massege_14_reg_t;
} mb_message_14_reg_t;
/** Type of massege_15 register
/** Type of message_15 register
* need_des
*/
typedef union {
struct {
/** massege_15 : R/W; bitpos: [31:0]; default: 0;
/** message_15 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_15:32;
uint32_t message_15:32;
};
uint32_t val;
} mb_massege_15_reg_t;
} mb_message_15_reg_t;
/** Type of reg_clk_en register
* need_des
@@ -829,22 +829,22 @@ typedef union {
typedef struct {
volatile mb_massege_0_reg_t massege_0;
volatile mb_massege_1_reg_t massege_1;
volatile mb_massege_2_reg_t massege_2;
volatile mb_massege_3_reg_t massege_3;
volatile mb_massege_4_reg_t massege_4;
volatile mb_massege_5_reg_t massege_5;
volatile mb_massege_6_reg_t massege_6;
volatile mb_massege_7_reg_t massege_7;
volatile mb_massege_8_reg_t massege_8;
volatile mb_massege_9_reg_t massege_9;
volatile mb_massege_10_reg_t massege_10;
volatile mb_massege_11_reg_t massege_11;
volatile mb_massege_12_reg_t massege_12;
volatile mb_massege_13_reg_t massege_13;
volatile mb_massege_14_reg_t massege_14;
volatile mb_massege_15_reg_t massege_15;
volatile mb_message_0_reg_t message_0;
volatile mb_message_1_reg_t message_1;
volatile mb_message_2_reg_t message_2;
volatile mb_message_3_reg_t message_3;
volatile mb_message_4_reg_t message_4;
volatile mb_message_5_reg_t message_5;
volatile mb_message_6_reg_t message_6;
volatile mb_message_7_reg_t message_7;
volatile mb_message_8_reg_t message_8;
volatile mb_message_9_reg_t message_9;
volatile mb_message_10_reg_t message_10;
volatile mb_message_11_reg_t message_11;
volatile mb_message_12_reg_t message_12;
volatile mb_message_13_reg_t message_13;
volatile mb_message_14_reg_t message_14;
volatile mb_message_15_reg_t message_15;
volatile mb_lp_int_raw_reg_t lp_int_raw;
volatile mb_lp_int_st_reg_t lp_int_st;
volatile mb_lp_int_ena_reg_t lp_int_ena;
@@ -854,11 +854,12 @@ typedef struct {
volatile mb_hp_int_ena_reg_t hp_int_ena;
volatile mb_hp_int_clr_reg_t hp_int_clr;
volatile mb_reg_clk_en_reg_t reg_clk_en;
} mb_dev_t;
} lp_mb_dev_t;
extern lp_mb_dev_t LP_MAILBOX;
#ifndef __cplusplus
_Static_assert(sizeof(mb_dev_t) == 0x64, "Invalid size of mb_dev_t structure");
_Static_assert(sizeof(lp_mb_dev_t) == 0x64, "Invalid size of lp_mb_dev_t structure");
#endif
#ifdef __cplusplus

View File

@@ -11,213 +11,213 @@ extern "C" {
#endif
/** Group: configure_register */
/** Type of massege_0 register
/** Type of message_0 register
* need_des
*/
typedef union {
struct {
/** massege_0 : R/W; bitpos: [31:0]; default: 0;
/** message_0 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_0:32;
uint32_t message_0:32;
};
uint32_t val;
} mb_massege_0_reg_t;
} mb_message_0_reg_t;
/** Type of massege_1 register
/** Type of message_1 register
* need_des
*/
typedef union {
struct {
/** massege_1 : R/W; bitpos: [31:0]; default: 0;
/** message_1 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_1:32;
uint32_t message_1:32;
};
uint32_t val;
} mb_massege_1_reg_t;
} mb_message_1_reg_t;
/** Type of massege_2 register
/** Type of message_2 register
* need_des
*/
typedef union {
struct {
/** massege_2 : R/W; bitpos: [31:0]; default: 0;
/** message_2 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_2:32;
uint32_t message_2:32;
};
uint32_t val;
} mb_massege_2_reg_t;
} mb_message_2_reg_t;
/** Type of massege_3 register
/** Type of message_3 register
* need_des
*/
typedef union {
struct {
/** massege_3 : R/W; bitpos: [31:0]; default: 0;
/** message_3 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_3:32;
uint32_t message_3:32;
};
uint32_t val;
} mb_massege_3_reg_t;
} mb_message_3_reg_t;
/** Type of massege_4 register
/** Type of message_4 register
* need_des
*/
typedef union {
struct {
/** massege_4 : R/W; bitpos: [31:0]; default: 0;
/** message_4 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_4:32;
uint32_t message_4:32;
};
uint32_t val;
} mb_massege_4_reg_t;
} mb_message_4_reg_t;
/** Type of massege_5 register
/** Type of message_5 register
* need_des
*/
typedef union {
struct {
/** massege_5 : R/W; bitpos: [31:0]; default: 0;
/** message_5 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_5:32;
uint32_t message_5:32;
};
uint32_t val;
} mb_massege_5_reg_t;
} mb_message_5_reg_t;
/** Type of massege_6 register
/** Type of message_6 register
* need_des
*/
typedef union {
struct {
/** massege_6 : R/W; bitpos: [31:0]; default: 0;
/** message_6 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_6:32;
uint32_t message_6:32;
};
uint32_t val;
} mb_massege_6_reg_t;
} mb_message_6_reg_t;
/** Type of massege_7 register
/** Type of message_7 register
* need_des
*/
typedef union {
struct {
/** massege_7 : R/W; bitpos: [31:0]; default: 0;
/** message_7 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_7:32;
uint32_t message_7:32;
};
uint32_t val;
} mb_massege_7_reg_t;
} mb_message_7_reg_t;
/** Type of massege_8 register
/** Type of message_8 register
* need_des
*/
typedef union {
struct {
/** massege_8 : R/W; bitpos: [31:0]; default: 0;
/** message_8 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_8:32;
uint32_t message_8:32;
};
uint32_t val;
} mb_massege_8_reg_t;
} mb_message_8_reg_t;
/** Type of massege_9 register
/** Type of message_9 register
* need_des
*/
typedef union {
struct {
/** massege_9 : R/W; bitpos: [31:0]; default: 0;
/** message_9 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_9:32;
uint32_t message_9:32;
};
uint32_t val;
} mb_massege_9_reg_t;
} mb_message_9_reg_t;
/** Type of massege_10 register
/** Type of message_10 register
* need_des
*/
typedef union {
struct {
/** massege_10 : R/W; bitpos: [31:0]; default: 0;
/** message_10 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_10:32;
uint32_t message_10:32;
};
uint32_t val;
} mb_massege_10_reg_t;
} mb_message_10_reg_t;
/** Type of massege_11 register
/** Type of message_11 register
* need_des
*/
typedef union {
struct {
/** massege_11 : R/W; bitpos: [31:0]; default: 0;
/** message_11 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_11:32;
uint32_t message_11:32;
};
uint32_t val;
} mb_massege_11_reg_t;
} mb_message_11_reg_t;
/** Type of massege_12 register
/** Type of message_12 register
* need_des
*/
typedef union {
struct {
/** massege_12 : R/W; bitpos: [31:0]; default: 0;
/** message_12 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_12:32;
uint32_t message_12:32;
};
uint32_t val;
} mb_massege_12_reg_t;
} mb_message_12_reg_t;
/** Type of massege_13 register
/** Type of message_13 register
* need_des
*/
typedef union {
struct {
/** massege_13 : R/W; bitpos: [31:0]; default: 0;
/** message_13 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_13:32;
uint32_t message_13:32;
};
uint32_t val;
} mb_massege_13_reg_t;
} mb_message_13_reg_t;
/** Type of massege_14 register
/** Type of message_14 register
* need_des
*/
typedef union {
struct {
/** massege_14 : R/W; bitpos: [31:0]; default: 0;
/** message_14 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_14:32;
uint32_t message_14:32;
};
uint32_t val;
} mb_massege_14_reg_t;
} mb_message_14_reg_t;
/** Type of massege_15 register
/** Type of message_15 register
* need_des
*/
typedef union {
struct {
/** massege_15 : R/W; bitpos: [31:0]; default: 0;
/** message_15 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t massege_15:32;
uint32_t message_15:32;
};
uint32_t val;
} mb_massege_15_reg_t;
} mb_message_15_reg_t;
/** Type of reg_clk_en register
* need_des
@@ -829,22 +829,22 @@ typedef union {
typedef struct {
volatile mb_massege_0_reg_t massege_0;
volatile mb_massege_1_reg_t massege_1;
volatile mb_massege_2_reg_t massege_2;
volatile mb_massege_3_reg_t massege_3;
volatile mb_massege_4_reg_t massege_4;
volatile mb_massege_5_reg_t massege_5;
volatile mb_massege_6_reg_t massege_6;
volatile mb_massege_7_reg_t massege_7;
volatile mb_massege_8_reg_t massege_8;
volatile mb_massege_9_reg_t massege_9;
volatile mb_massege_10_reg_t massege_10;
volatile mb_massege_11_reg_t massege_11;
volatile mb_massege_12_reg_t massege_12;
volatile mb_massege_13_reg_t massege_13;
volatile mb_massege_14_reg_t massege_14;
volatile mb_massege_15_reg_t massege_15;
volatile mb_message_0_reg_t message_0;
volatile mb_message_1_reg_t message_1;
volatile mb_message_2_reg_t message_2;
volatile mb_message_3_reg_t message_3;
volatile mb_message_4_reg_t message_4;
volatile mb_message_5_reg_t message_5;
volatile mb_message_6_reg_t message_6;
volatile mb_message_7_reg_t message_7;
volatile mb_message_8_reg_t message_8;
volatile mb_message_9_reg_t message_9;
volatile mb_message_10_reg_t message_10;
volatile mb_message_11_reg_t message_11;
volatile mb_message_12_reg_t message_12;
volatile mb_message_13_reg_t message_13;
volatile mb_message_14_reg_t message_14;
volatile mb_message_15_reg_t message_15;
volatile mb_lp_int_raw_reg_t lp_int_raw;
volatile mb_lp_int_st_reg_t lp_int_st;
volatile mb_lp_int_ena_reg_t lp_int_ena;
@@ -854,12 +854,12 @@ typedef struct {
volatile mb_hp_int_ena_reg_t hp_int_ena;
volatile mb_hp_int_clr_reg_t hp_int_clr;
volatile mb_reg_clk_en_reg_t reg_clk_en;
} mb_dev_t;
} lp_mb_dev_t;
extern mb_dev_t LP_MAILBOX;
extern lp_mb_dev_t LP_MAILBOX;
#ifndef __cplusplus
_Static_assert(sizeof(mb_dev_t) == 0x64, "Invalid size of mb_dev_t structure");
_Static_assert(sizeof(lp_mb_dev_t) == 0x64, "Invalid size of lp_mb_dev_t structure");
#endif
#ifdef __cplusplus

View File

@@ -84,6 +84,14 @@ if(CONFIG_ULP_COPROC_TYPE_LP_CORE)
if(CONFIG_SOC_LP_VAD_SUPPORTED)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_vad_shared.c")
endif()
list(APPEND srcs "lp_core/lp_core_mailbox.c")
if(CONFIG_SOC_LP_MAILBOX_SUPPORTED)
list(APPEND srcs "lp_core/lp_core_mailbox_impl_hw.c")
else()
list(APPEND srcs "lp_core/lp_core_mailbox_impl_sw.c")
endif()
endif()
idf_component_register(SRCS ${srcs}

View File

@@ -128,10 +128,19 @@ function(ulp_apply_default_sources ulp_app_name)
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_spi.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_ubsan.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_mailbox.c"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_adc_shared.c"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_vad_shared.c"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_critical_section_shared.c")
if(CONFIG_SOC_LP_MAILBOX_SUPPORTED)
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/lp_core/port/lp_core_mailbox_impl_hw.c")
else()
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/lp_core/port/lp_core_mailbox_impl_sw.c")
endif()
if(CONFIG_SOC_TOUCH_SENSOR_SUPPORTED)
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_touch.c")

View File

@@ -0,0 +1,144 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "freertos/FreeRTOS.h" // for TickType_t
#include "esp_err.h"
typedef intptr_t lp_message_t;
/**
* @typedef lp_core_mailbox_callback_t
* @brief Represents a callback function type triggered when a message is received in asynchronous mode.
*
* Note: There is no guarantee regarding the order in which messages are processed between synchronous
* and asynchronous modes.
*
* @param msg The received message, represented as an `lp_message_t` object.
*/
typedef void (*lp_core_mailbox_callback_t)(lp_message_t msg);
/**
* @brief Mailbox structure.
*/
typedef struct lp_mailbox_t* lp_mailbox_t;
/**
* @brief Configuration structure for the mailbox
*/
typedef struct {
uint32_t dummy; /*!< Placeholder for future field, ignored for now */
} lp_mailbox_config_t;
/**
* @brief Initialize a mailbox.
*
* @note Depending on the target, the implementation may use either the hardware mailbox controller
* or a software implementation. In the latter case, the PMU software interrupt will be used for
* sending and receiving notifications between the HP and LP cores.
*
* @note For the software implementation, this function must be called first by the LP core before
* being called by the HP core.
*
* @param mailbox Pointer to the mailbox instance to initialize.
* @param config Configuration structure, can be NULL to use default values.
*
* @return ESP_OK on success,
* ESP_ERR_INVALID_STATE if `mailbox` parameter is NULL,
* if the mailbox has already been initialized on the HP core,
* or if the LP core has not yet initialized its mailbox (software implementation)
* ESP_ERR_NO_MEM if no more memory is available in the system.
*/
esp_err_t lp_core_mailbox_init(lp_mailbox_t *mailbox, lp_mailbox_config_t *config);
/**
* @brief Deinitialize a mailbox.
*
* @param mailbox Pointer to the mailbox instance to deinitialize.
*
*/
void lp_core_mailbox_deinit(lp_mailbox_t mailbox);
/**
* @brief Send a message through the mailbox.
*
* @note This function will put a message in the mailbox and wait for a receiver to get it.
*
* @param mailbox Pointer to the mailbox instance.
* @param msg Message to be sent.
* @param ticks_to_wait Maximum ticks to wait before issuing a timeout.
*
* @return ESP_OK on success.
* ESP_INVALID_ARGUMENT if `mailbox` is NULL.
* ESP_TIMEOUT if timeout was reached and no receiver took the message.
*/
esp_err_t lp_core_mailbox_send(lp_mailbox_t mailbox, lp_message_t msg, TickType_t ticks_to_wait);
/**
* @brief Send a message through the mailbox asynchronously.
*
* @note Unlike the synchronous send function, this function does not wait for a receiver to acknowledge
* the message.
*
* @param mailbox Pointer to the mailbox instance.
* @param msg Message to be sent.
*
* @return ESP_OK on success.
* ESP_INVALID_ARGUMENT if `mailbox` is NULL.
*/
esp_err_t lp_core_mailbox_send_async(lp_mailbox_t mailbox, lp_message_t msg);
/**
* @brief Receive a message from the mailbox.
*
* @note This function waits for a message to be sent by a sender.
*
* @param mailbox Pointer to the mailbox instance.
* @param msg Pointer to store the received message.
* @param ticks_to_wait Maximum ticks to wait before issuing a timeout.
*
* @return ESP_OK on success.
* ESP_INVALID_ARGUMENT if `mailbox` is NULL.
* ESP_TIMEOUT if the timeout expires without receiving a message.
*/
esp_err_t lp_core_mailbox_receive(lp_mailbox_t mailbox, lp_message_t* msg, TickType_t ticks_to_wait);
/**
* @brief Receive a message from the mailbox.
*
* @param mailbox Pointer to the mailbox instance.
* @param count Number of messages to receive asynchronously. To terminate it at anytime,
* use lp_core_mailbox_receive_async_cancel() to terminate it.
* @param cb Callback invoked as soon as a message is received. Please note that this function
* will be invoked from an ISR context.
*
* @return ESP_OK on success.
* ESP_INVALID_ARGUMENT if `mailbox` or `cb` is NULL.
*/
esp_err_t lp_core_mailbox_receive_async(lp_mailbox_t mailbox, uint32_t count, lp_core_mailbox_callback_t cb);
/**
* @brief Cancel an ongoing asynchronous mailbox receive.
*
* This stops any pending lp_core_mailbox_receive_async().
*
* @param mailbox Pointer to the mailbox instance.
* @param remaining Optional pointer to store the number of messages left to receive.
*
* @return ESP_OK on success, ESP_ERR_INVALID_STATE if no async receive was active.
*/
esp_err_t lp_core_mailbox_receive_async_cancel(lp_mailbox_t mailbox, uint32_t* remaining);
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -65,12 +65,44 @@ esp_err_t ulp_lp_core_load_binary(const uint8_t* program_binary, size_t program_
void ulp_lp_core_stop(void);
/**
* @brief Trigger a SW interrupt to the LP CPU from the PMU
* @brief Enable or disable the software interrupts requested by the LP CPU via the PMU
*/
void ulp_lp_core_sw_intr_from_lp_enable(bool enable);
/**
* @brief Clear the software interrupt requested by the LP CPU via the PMU
*/
void ulp_lp_core_sw_intr_from_lp_clear(void);
/**
* @brief Trigger a software interrupt to the LP CPU from the PMU
*
* @note This is the same SW trigger that is used to wake up the LP CPU
*
*/
void ulp_lp_core_sw_intr_trigger(void);
void ulp_lp_core_sw_intr_to_lp_trigger(void);
/**
* @brief Trigger a software interrupt to the LP CPU from the PMU
*
* @note This function is an alias for `ulp_lp_core_sw_intr_to_lp_trigger`
*
*/
static inline void ulp_lp_core_sw_intr_trigger(void)
{
ulp_lp_core_sw_intr_to_lp_trigger();
}
/**
* @brief Trigger a software interrupt on the HP core from the PMU
*
* @note This function generates the same software interrupt that the LP core would normally
* use to notify the HP core. It can be called directly by the HP core itself in order
* to simulate or re-issue such a notification. This is particularly useful if the HP
* core missed a previous interrupt from the LP core and needs to retrigger the
* notification sequence.
*/
void ulp_lp_core_sw_intr_trigger_self(void);
#ifdef __cplusplus
}

View File

@@ -13,11 +13,13 @@
#include "soc/pmu_reg.h"
#include "hal/misc.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/pmu_share_hw.h"
#include "ulp_common.h"
#include "ulp_lp_core.h"
#include "ulp_lp_core_memory_shared.h"
#include "ulp_lp_core_lp_timer_shared.h"
#include "hal/lp_core_ll.h"
#include "hal/pmu_ll.h"
#if CONFIG_IDF_TARGET_ESP32P4
#include "esp32p4/rom/rtc.h"
@@ -189,7 +191,28 @@ void ulp_lp_core_stop(void)
lp_core_ll_request_sleep();
}
void ulp_lp_core_sw_intr_trigger(void)
void ulp_lp_core_sw_intr_to_lp_trigger(void)
{
/* Write-only register, no need to protect it */
lp_core_ll_hp_wake_lp();
}
void ulp_lp_core_sw_intr_trigger_self(void)
{
/* Write-only register, no need to protect it */
pmu_ll_lp_trigger_sw_intr(&PMU);
}
void ulp_lp_core_sw_intr_from_lp_enable(bool enable)
{
/* Interrupt enable register must be protected since it is a R/W one */
pmu_lock_acquire();
pmu_ll_hp_enable_sw_intr(&PMU, enable);
pmu_lock_release();
}
void ulp_lp_core_sw_intr_from_lp_clear(void)
{
/* Write-only register, no need to protect it */
pmu_ll_hp_clear_sw_intr_status(&PMU);
}

View File

@@ -0,0 +1,132 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
typedef intptr_t lp_message_t;
/**
* @typedef lp_core_mailbox_callback_t
* @brief Represents a callback function type triggered when a message is received in asynchronous mode.
*
* Note: There is no guarantee regarding the order in which messages are processed between synchronous
* and asynchronous modes.
*
* @param msg The received message, represented as an `lp_message_t` object.
*/
typedef void (*lp_core_mailbox_callback_t)(lp_message_t msg);
/**
* @brief Mailbox structure.
*/
typedef struct lp_mailbox_t* lp_mailbox_t;
/**
* @brief Configuration structure for the mailbox
*/
typedef struct {
uint32_t dummy; /*!< Placeholder for future field, ignored for now */
} lp_mailbox_config_t;
/**
* @brief Initialize a mailbox.
*
* @param mailbox Pointer to the mailbox instance to initialize.
* @param config Pointer to the configuration structure, can be NULL to use default values.
*
* @return ESP_OK on success
*/
esp_err_t lp_core_mailbox_init(lp_mailbox_t *mailbox, lp_mailbox_config_t *config);
/**
* @brief Deinitialize a mailbox.
*
* @param mailbox Pointer to the mailbox instance to deinitialize.
*
*/
void lp_core_mailbox_deinit(lp_mailbox_t mailbox);
/**
* @brief Send a message through the mailbox.
*
* @note This function will put a message in the mailbox and wait for a receiver to get it.
*
* @param mailbox Pointer to the mailbox instance.
* @param msg Message to be sent.
* @param timeout Operation timeout in CPU cycles. Set to -1 to wait forever.
*
* @return ESP_OK on success.
* ESP_INVALID_ARGUMENT if `mailbox` is NULL.
* ESP_TIMEOUT if timeout was reached and no receiver took the message.
*/
esp_err_t lp_core_mailbox_send(lp_mailbox_t mailbox, lp_message_t msg, int32_t timeout);
/**
* @brief Send a message through the mailbox asynchronously.
*
* @note Unlike the synchronous send function, this function does not wait for a receiver to acknowledge
* the message.
*
* @param mailbox Pointer to the mailbox instance.
* @param msg Message to be sent.
*
* @return ESP_OK on success.
* ESP_INVALID_ARGUMENT if `mailbox` is NULL.
*/
esp_err_t lp_core_mailbox_send_async(lp_mailbox_t mailbox, lp_message_t msg);
/**
* @brief Receive a message from the mailbox.
*
* @note This function waits for a message to be sent by a sender.
*
* @param mailbox Pointer to the mailbox instance.
* @param msg Pointer to store the received message.
* @param timeout Timeout for the operation in CPU cycles. Use -1 to wait indefinitely.
*
* @return ESP_OK on success.
* ESP_INVALID_ARGUMENT if `mailbox` is NULL.
* ESP_TIMEOUT if the timeout expires without receiving a message.
*/
esp_err_t lp_core_mailbox_receive(lp_mailbox_t mailbox, lp_message_t* msg, int32_t timeout);
/**
* @brief Receive a message from the mailbox.
*
* @param mailbox Pointer to the mailbox instance.
* @param count Number of messages to receive asynchronously. To terminate it at anytime,
* use lp_core_mailbox_receive_async_cancel() to terminate it.
* @param cb Callback invoked as soon as a message is received. Please note that this function
* will be invoked from an ISR context.
*
* @return ESP_OK on success.
* ESP_INVALID_ARGUMENT if `mailbox` or `cb` is NULL.
*/
esp_err_t lp_core_mailbox_receive_async(lp_mailbox_t mailbox, uint32_t count, lp_core_mailbox_callback_t cb);
/**
* @brief Cancel an ongoing asynchronous mailbox receive.
*
* This stops any pending lp_core_mailbox_receive_async().
*
* @param mailbox Pointer to the mailbox instance.
* @param remaining Optional pointer to store the number of messages left to receive.
*
* @return ESP_OK on success, ESP_ERR_INVALID_STATE if no async receive was active.
*/
esp_err_t lp_core_mailbox_receive_async_cancel(lp_mailbox_t mailbox, uint32_t* remaining);
#ifdef __cplusplus
}
#endif

View File

@@ -13,6 +13,7 @@ extern "C" {
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include "riscv/csr.h"
#include "soc/soc_caps.h"
/**
@@ -41,6 +42,16 @@ uint32_t ulp_lp_core_get_wakeup_cause(void);
*/
void ulp_lp_core_wakeup_main_processor(void);
/**
* @brief Retrieves the current number of CPU cycles.
*
* @return The current CPU cycle count.
*/
static inline uint32_t ulp_lp_core_get_cpu_cycles(void)
{
return RV_READ_CSR(mcycle);
}
/**
* @brief Makes the co-processor busy wait for a certain number of microseconds
*
@@ -88,6 +99,11 @@ __attribute__((__noreturn__)) void ulp_lp_core_stop_lp_core(void);
*/
void __attribute__((noreturn)) ulp_lp_core_abort(void);
/**
* @brief Trigger a software interrupt on the HP core
*/
void ulp_lp_core_sw_intr_to_hp_trigger(void);
/**
* @brief Enable the SW triggered interrupt from the PMU
*
@@ -96,13 +112,34 @@ void __attribute__((noreturn)) ulp_lp_core_abort(void);
* @param enable true to enable, false to disable
*
*/
void ulp_lp_core_sw_intr_enable(bool enable);
void ulp_lp_core_sw_intr_from_hp_enable(bool enable);
/**
* @brief Enable the SW triggered interrupt from the PMU
*
* @note Alias for the `ulp_lp_core_sw_intr_from_hp_enable` function, for backward compatibility.
*
* @param enable true to enable, false to disable
*/
static inline void ulp_lp_core_sw_intr_enable(bool enable)
{
return ulp_lp_core_sw_intr_from_hp_enable(enable);
}
/**
* @brief Clear the interrupt status for the SW triggered interrupt from the PMU
*/
void ulp_lp_core_sw_intr_from_hp_clear(void);
/**
* @brief Clear the interrupt status for the SW triggered interrupt from the PMU
*
* @note Alias for the `ulp_lp_core_sw_intr_from_hp_clear` function, for backward compatibility.
*/
void ulp_lp_core_sw_intr_clear(void);
static inline void ulp_lp_core_sw_intr_clear(void)
{
return ulp_lp_core_sw_intr_from_hp_clear();
}
#if SOC_LP_TIMER_SUPPORTED
/**

View File

@@ -5,6 +5,7 @@
*/
#include "sdkconfig.h"
#include <sys/param.h> /* For MIN macro */
#include "soc/soc_caps.h"
#include "ulp_lp_core_i2c.h"
#include "ulp_lp_core_utils.h"
@@ -20,8 +21,6 @@
#define LP_I2C_ACK I2C_MASTER_ACK
#define LP_I2C_NACK I2C_MASTER_NACK
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
/* I2C LL context */
i2c_dev_t *dev = I2C_LL_GET_HW(LP_I2C_NUM_0);

View File

@@ -0,0 +1,296 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "esp_err.h"
#include "hal/misc.h"
#include "ulp_lp_core_mailbox.h"
#include "ulp_lp_core_mailbox_impl_shared.h"
#include "ulp_lp_core_utils.h"
#include "ulp_lp_core_interrupts.h"
#include "ulp_lp_core_print.h"
#ifndef BIT
#define BIT(i) (1U << (i))
#endif
/**
* @brief Number of messages allocated for LP -> HP communication
*/
#define LP_MAILBOX_TX_MSG_COUNT (LP_MAILBOX_MSG_COUNT / 2)
/**
* @brief Starting index of the LP -> HP messages
*/
#define LP_MAILBOX_TX_MSG_IDX 0U
/**
* @brief Starting index of the HP -> LP messages
*/
#define LP_MAILBOX_RX_MSG_IDX (LP_MAILBOX_TX_MSG_COUNT)
/**
* @brief Number of messages allocated for HP -> LP communication
*/
#define LP_MAILBOX_RX_MSG_COUNT (LP_MAILBOX_MSG_COUNT - LP_MAILBOX_RX_MSG_IDX)
/**
* @brief Mask for the HP -> LP messages
*/
#define LP_MAILBOX_RX_MSG_MASK (((1U << LP_MAILBOX_RX_MSG_COUNT) - 1U) << LP_MAILBOX_RX_MSG_IDX)
#define LP_MAILBOX_ACK ((lp_message_t) 0xe5U)
struct lp_mailbox_t {
lp_core_mailbox_ctx_t mb_ctx;
lp_core_mailbox_callback_t rcv_callback;
uint32_t rcv_remaining;
int tx_idx;
};
static struct lp_mailbox_t s_mailbox;
/* In the current implementation, it should always be pointing to `s_mailbox`, but keep it for now in case
* we need to have something more modular */
static lp_mailbox_t s_isr_arg;
/******************************************************************************
* STATIC HELPERS *
******************************************************************************/
static inline int lp_core_next_msg_idx(int idx)
{
return (idx + 1) % LP_MAILBOX_TX_MSG_COUNT;
}
static inline bool mb_msg_status(lp_mailbox_t mailbox, int msg_idx)
{
return lp_core_mailbox_impl_intr_raw(mailbox->mb_ctx) & BIT(msg_idx);
}
static inline bool mb_msg_search_read(lp_mailbox_t mailbox, int* msg_idx, lp_message_t* msg)
{
for (int i = LP_MAILBOX_RX_MSG_IDX; i < (LP_MAILBOX_RX_MSG_IDX + LP_MAILBOX_RX_MSG_COUNT); i += 2) {
if (mb_msg_status(mailbox, i)) {
*msg_idx = i;
*msg = lp_core_mailbox_impl_get_message(mailbox->mb_ctx, i);
return true;
}
}
return false;
}
static inline bool mb_async_mode(lp_mailbox_t mailbox)
{
return mailbox->rcv_callback != NULL;
}
static inline bool lp_core_mailbox_check_timeout(uint32_t start_cycle, int32_t timeout)
{
return timeout != -1 && (ulp_lp_core_get_cpu_cycles() - start_cycle) >= (uint32_t) timeout;
}
static void ulp_lp_core_mailbox_intr_handler(void)
{
lp_message_t received[LP_MAILBOX_RX_MSG_COUNT];
int received_count = 0;
/* `s_isr_arg` cannot be NULL but let's be safe and test it */
if (s_isr_arg == NULL || s_isr_arg->mb_ctx == NULL) {
return;
}
/* Acknowledge all the received message as fast as possible */
const uint32_t status = lp_core_mailbox_impl_intr_status(s_isr_arg->mb_ctx);
/* Mask of all the processed messages */
uint32_t clr_mask = 0;
for (int i = 0; i < LP_MAILBOX_RX_MSG_COUNT; i += 2) {
const uint32_t mask = BIT(i);
if (status & mask) {
clr_mask |= mask;
received[received_count] = lp_core_mailbox_impl_get_message(s_isr_arg->mb_ctx, LP_MAILBOX_RX_MSG_IDX + i);
/* Acknowledge reception */
const int ack_msg_idx = LP_MAILBOX_RX_MSG_IDX + lp_core_next_msg_idx(i);
lp_core_mailbox_impl_set_message(s_isr_arg->mb_ctx, ack_msg_idx, LP_MAILBOX_ACK);
lp_core_mailbox_impl_intr_clear(s_isr_arg->mb_ctx, ack_msg_idx);
received_count++;
/* We must not acknowledge more messages than what the caller needs */
s_isr_arg->rcv_remaining--;
if (s_isr_arg->rcv_remaining == 0) {
break;
}
}
}
/* Clear the interrupt status */
lp_core_mailbox_impl_intr_clear(s_isr_arg->mb_ctx, clr_mask);
/* Call the callback for all the message received */
for (int i = 0; i < received_count; i++) {
s_isr_arg->rcv_callback(received[i]);
}
/* Disable interrupts if no more messages are expected */
if (s_isr_arg->rcv_remaining == 0) {
lp_core_mailbox_impl_intr_disable(s_isr_arg->mb_ctx, LP_MAILBOX_RX_MSG_MASK);
s_isr_arg->rcv_callback = NULL;
}
}
/******************************************************************************
* PUBLIC API *
******************************************************************************/
esp_err_t lp_core_mailbox_init(lp_mailbox_t *mailbox, lp_mailbox_config_t *config)
{
/* Configuration is unused for now */
(void) config;
if (mailbox == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (s_mailbox.mb_ctx != NULL) {
/* Mailbox has already been initialized! */
return ESP_ERR_INVALID_STATE;
}
hal_memset(&s_mailbox, 0, sizeof(s_mailbox));
s_mailbox.mb_ctx = lp_core_mailbox_impl_get_context();
if (s_mailbox.mb_ctx == NULL) {
return ESP_ERR_INVALID_STATE;
}
/* Clear the status and the interrupts for the messages */
lp_core_mailbox_impl_intr_disable(s_mailbox.mb_ctx, ~0);
lp_core_mailbox_impl_intr_clear(s_mailbox.mb_ctx, ~0);
lp_core_mailbox_impl_set_intr_handler(s_mailbox.mb_ctx, ulp_lp_core_mailbox_intr_handler);
s_mailbox.tx_idx = 0;
*mailbox = &s_mailbox;
return ESP_OK;
}
void lp_core_mailbox_deinit(lp_mailbox_t mailbox)
{
if (mailbox != NULL) {
lp_core_mailbox_impl_intr_disable(s_mailbox.mb_ctx, ~0);
lp_core_mailbox_impl_intr_clear(s_mailbox.mb_ctx, ~0);
s_mailbox.mb_ctx = NULL;
}
}
esp_err_t lp_core_mailbox_send(lp_mailbox_t mailbox, lp_message_t msg, int32_t timeout)
{
if (mailbox == NULL || timeout < -1) {
return ESP_ERR_INVALID_ARG;
}
if (mb_async_mode(mailbox)) {
return ESP_ERR_INVALID_STATE;
}
/* Get the address of the next free message */
const int msg_idx = LP_MAILBOX_TX_MSG_IDX + mailbox->tx_idx;
/* The message right after will be used for acknowledgement since writing to one message
* sets the "ready" signal for both LP and HP status registers */
const int next_idx = lp_core_next_msg_idx(mailbox->tx_idx);
const int msg_ack_idx = LP_MAILBOX_TX_MSG_IDX + next_idx;
/* The message after will be the next free message */
mailbox->tx_idx = lp_core_next_msg_idx(next_idx);
/* Make sure both messages have cleared status */
lp_core_mailbox_impl_intr_clear(mailbox->mb_ctx, BIT(msg_idx) | BIT(msg_ack_idx));
/* Send the message and wait for an acknowledgement */
lp_core_mailbox_impl_set_message(mailbox->mb_ctx, msg_idx, msg);
/* Wait for a response from the HP core, on the same message */
const uint32_t start_cycle = ulp_lp_core_get_cpu_cycles();
while (1) {
if (mb_msg_status(mailbox, msg_ack_idx)) {
/* Clear the status */
lp_core_mailbox_impl_intr_clear(mailbox->mb_ctx, BIT(msg_idx) | BIT(msg_ack_idx));
break;
}
if (lp_core_mailbox_check_timeout(start_cycle, timeout)) {
return ESP_ERR_TIMEOUT;
}
}
return ESP_OK;
}
esp_err_t lp_core_mailbox_send_async(lp_mailbox_t mailbox, lp_message_t msg)
{
if (mailbox == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (mb_async_mode(mailbox)) {
return ESP_ERR_INVALID_STATE;
}
/* Get the address of the next free message */
const int msg_idx = LP_MAILBOX_TX_MSG_IDX + mailbox->tx_idx;
mailbox->tx_idx = (mailbox->tx_idx + 1) % LP_MAILBOX_TX_MSG_COUNT;
lp_core_mailbox_impl_set_message(mailbox->mb_ctx, msg_idx, msg);
return ESP_OK;
}
esp_err_t lp_core_mailbox_receive(lp_mailbox_t mailbox, lp_message_t* msg, int32_t timeout)
{
int msg_idx = 0;
if (mailbox == NULL || timeout < -1) {
return ESP_ERR_INVALID_ARG;
}
if (mb_async_mode(mailbox)) {
return ESP_ERR_INVALID_STATE;
}
/* Wait for a message from the HP core */
const uint32_t start_cycle = ulp_lp_core_get_cpu_cycles();
while (1) {
/* Get the address of the next free message */
if (mb_msg_search_read(mailbox, &msg_idx, msg)) {
lp_core_mailbox_impl_intr_clear(mailbox->mb_ctx, BIT(msg_idx));
break;
}
if (lp_core_mailbox_check_timeout(start_cycle, timeout)) {
return ESP_ERR_TIMEOUT;
}
}
/* Acknowledge the message by writing any value to the next one (guaranteed no overflow) */
const int ack_idx = msg_idx + 1;
lp_core_mailbox_impl_set_message(mailbox->mb_ctx, ack_idx, LP_MAILBOX_ACK);
/* Clear ACK messages status */
lp_core_mailbox_impl_intr_clear(mailbox->mb_ctx, BIT(ack_idx));
return ESP_OK;
}
esp_err_t lp_core_mailbox_receive_async(lp_mailbox_t mailbox, uint32_t count, lp_core_mailbox_callback_t cb)
{
/* Make sure another asynchronous transaction is not on-going */
if (mailbox == NULL || count == 0 || cb == NULL || mb_async_mode(mailbox)) {
return ESP_ERR_INVALID_ARG;
}
mailbox->rcv_callback = cb;
mailbox->rcv_remaining = count;
/* Enable interrupts for receive */
s_isr_arg = mailbox;
lp_core_mailbox_impl_intr_enable(mailbox->mb_ctx, LP_MAILBOX_RX_MSG_MASK);
return ESP_OK;
}
esp_err_t lp_core_mailbox_receive_async_cancel(lp_mailbox_t mailbox, uint32_t* remaining)
{
if (mailbox == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (!mb_async_mode(mailbox)) {
return ESP_ERR_INVALID_STATE;
}
lp_core_mailbox_impl_intr_disable(mailbox->mb_ctx, LP_MAILBOX_RX_MSG_MASK);
mailbox->rcv_callback = NULL;
if (remaining) {
*remaining = mailbox->rcv_remaining;
}
s_isr_arg = NULL;
ulp_lp_core_intr_enable();
return ESP_OK;
}

View File

@@ -181,12 +181,17 @@ void __attribute__((noreturn)) ulp_lp_core_abort(void)
while (1);
}
void ulp_lp_core_sw_intr_enable(bool enable)
void ulp_lp_core_sw_intr_to_hp_trigger(void)
{
pmu_ll_lp_trigger_sw_intr(&PMU);
}
void ulp_lp_core_sw_intr_from_hp_enable(bool enable)
{
pmu_ll_lp_enable_sw_intr(&PMU, enable);
}
void ulp_lp_core_sw_intr_clear(void)
void ulp_lp_core_sw_intr_from_hp_clear(void)
{
pmu_ll_lp_clear_sw_intr_status(&PMU);
}

View File

@@ -0,0 +1,68 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file Implementation of the mailbox port layer, using the hardware controller
*/
#include "ulp_lp_core_mailbox_impl_shared.h"
#include "hal/lp_mailbox_ll.h"
#include "soc/lp_mailbox_struct.h"
#include "ulp_lp_core_interrupts.h"
/* Implementation agnostic interrupt handler */
static void (*s_intr_handler)(void);
static void LP_CORE_ISR_ATTR ulp_lp_core_mailbox_intr_handler(void)
{
s_intr_handler();
}
lp_core_mailbox_ctx_t lp_core_mailbox_impl_get_context(void)
{
return (lp_core_mailbox_ctx_t) &LP_MAILBOX;
}
uint32_t lp_core_mailbox_impl_intr_raw(lp_core_mailbox_ctx_t ctx)
{
return lp_mailbox_ll_get_lp_intr_raw((lp_mb_dev_t*) ctx);
}
uint32_t lp_core_mailbox_impl_intr_status(lp_core_mailbox_ctx_t ctx)
{
return lp_mailbox_ll_lp_intr_status((lp_mb_dev_t*) ctx);
}
void lp_core_mailbox_impl_set_intr_handler(lp_core_mailbox_ctx_t ctx, void (*handler)(void))
{
(void) ctx;
s_intr_handler = handler;
}
void lp_core_mailbox_impl_intr_enable(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask)
{
lp_mailbox_ll_lp_intr_enable_mask((lp_mb_dev_t*) ctx, msg_mask);
}
void lp_core_mailbox_impl_intr_disable(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask)
{
lp_mailbox_ll_lp_intr_disable_mask((lp_mb_dev_t*) ctx, msg_mask);
}
void lp_core_mailbox_impl_intr_clear(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask)
{
lp_mailbox_ll_lp_intr_clear((lp_mb_dev_t*) ctx, msg_mask);
}
void lp_core_mailbox_impl_set_message(lp_core_mailbox_ctx_t ctx, int index, lp_message_t value)
{
lp_mailbox_ll_set_message((lp_mb_dev_t*) ctx, index, value);
}
lp_message_t lp_core_mailbox_impl_get_message(lp_core_mailbox_ctx_t ctx, int index)
{
return lp_mailbox_ll_get_message((lp_mb_dev_t*) ctx, index);
}

View File

@@ -0,0 +1,111 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file Implementation of the mailbox port layer, using software
*/
#include <string.h>
#include "ulp_lp_core_critical_section_shared.h"
#include "ulp_lp_core_mailbox_impl_shared.h"
#include "ulp_lp_core_utils.h"
#include "ulp_lp_core_interrupts.h"
#include "ulp_lp_core_print.h"
typedef struct {
volatile lp_message_t msg[LP_MAILBOX_MSG_COUNT];
/* Message mask to the HP core */
volatile uint32_t to_hp_msg_raw;
/* Message mask to the LP core */
volatile uint32_t to_lp_msg_raw;
/* Lock for all the "raw" values, array is guaranteed to be split between LP/HP */
ulp_lp_core_spinlock_t lock;
} lp_core_mailbox_impl_sw_t;
lp_core_mailbox_impl_sw_t g_lp_core_mailbox_impl_sw_ctx;
/* Implementation agnostic interrupt handler */
static void (*s_intr_handler)(void);
static void LP_CORE_ISR_ATTR ulp_lp_core_sw_intr_handler(void)
{
if (s_intr_handler) {
s_intr_handler();
}
}
lp_core_mailbox_ctx_t lp_core_mailbox_impl_get_context(void)
{
/* This structure must be initialized by the LP core */
memset(&g_lp_core_mailbox_impl_sw_ctx, 0, sizeof(g_lp_core_mailbox_impl_sw_ctx));
ulp_lp_core_spinlock_init(&g_lp_core_mailbox_impl_sw_ctx.lock);
ulp_lp_core_sw_intr_from_hp_enable(false);
return (lp_core_mailbox_ctx_t) &g_lp_core_mailbox_impl_sw_ctx;
}
uint32_t lp_core_mailbox_impl_intr_raw(lp_core_mailbox_ctx_t ctx)
{
lp_core_mailbox_impl_sw_t* sw_ctx = (lp_core_mailbox_impl_sw_t*) ctx;
return sw_ctx->to_lp_msg_raw;
}
uint32_t lp_core_mailbox_impl_intr_status(lp_core_mailbox_ctx_t ctx)
{
lp_core_mailbox_impl_sw_t* sw_ctx = (lp_core_mailbox_impl_sw_t*) ctx;
return sw_ctx->to_lp_msg_raw;
}
void lp_core_mailbox_impl_set_intr_handler(lp_core_mailbox_ctx_t ctx, void (*handler)(void))
{
(void) ctx;
s_intr_handler = handler;
}
void lp_core_mailbox_impl_intr_enable(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask)
{
/* This function is called when asynchronous received is used.
* In the case of the software implementation, we don't really care about the mask, it should
* be able to receive any RX message. */
ulp_lp_core_sw_intr_from_hp_enable(true);
}
void lp_core_mailbox_impl_intr_disable(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask)
{
/* Similarly to the `enable` function, this is used for receiving messages.
* Since we cannot only disable software interrupts, set the flags we defined above. */
(void) ctx;
(void) msg_mask;
ulp_lp_core_sw_intr_from_hp_enable(false);
}
void lp_core_mailbox_impl_intr_clear(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask)
{
lp_core_mailbox_impl_sw_t* sw_ctx = (lp_core_mailbox_impl_sw_t*) ctx;
/* Clear the flag */
ulp_lp_core_enter_critical(&sw_ctx->lock);
sw_ctx->to_lp_msg_raw &= ~msg_mask;
if (sw_ctx->to_lp_msg_raw == 0) {
/* All interrupts were handled */
ulp_lp_core_sw_intr_from_hp_clear();
}
ulp_lp_core_exit_critical(&sw_ctx->lock);
}
void lp_core_mailbox_impl_set_message(lp_core_mailbox_ctx_t ctx, int index, lp_message_t value)
{
lp_core_mailbox_impl_sw_t* sw_ctx = (lp_core_mailbox_impl_sw_t*) ctx;
sw_ctx->msg[index] = value;
ulp_lp_core_enter_critical(&sw_ctx->lock);
sw_ctx->to_hp_msg_raw |= 1 << index;
ulp_lp_core_exit_critical(&sw_ctx->lock);
/* Trigger a software interrupt */
ulp_lp_core_sw_intr_to_hp_trigger();
}
lp_message_t lp_core_mailbox_impl_get_message(lp_core_mailbox_ctx_t ctx, int index)
{
return ((lp_core_mailbox_impl_sw_t*) ctx)->msg[index];
}

View File

@@ -0,0 +1,367 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "esp_err.h"
#include "esp_types.h"
#include "esp_attr.h"
#include "esp_intr_alloc.h"
#include "soc/soc_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "hal/misc.h"
#include "lp_core_mailbox.h"
#include "ulp_lp_core_mailbox_impl_shared.h"
#include "riscv/rv_utils.h"
#include "soc/interrupts.h"
#ifndef BIT
#define BIT(i) (1U << (i))
#endif
/**
* @brief Starting index of the LP -> HP messages
*/
#define LP_MAILBOX_RX_MSG_IDX (0U)
/**
* @brief Number of messages allocated for LP -> HP communication
*/
#define LP_MAILBOX_RX_MSG_COUNT (LP_MAILBOX_MSG_COUNT / 2)
/**
* @brief Mask for the HP -> LP messages
*/
#define LP_MAILBOX_RX_MSG_MASK (((1U << LP_MAILBOX_RX_MSG_COUNT) - 1U) << LP_MAILBOX_RX_MSG_IDX)
/**
* @brief Number of messages allocated for HP -> LP communication
*/
#define LP_MAILBOX_TX_MSG_COUNT (LP_MAILBOX_MSG_COUNT / 2)
/**
* @brief Starting index of the HP -> LP messages
*/
#define LP_MAILBOX_TX_MSG_IDX (8U)
#define LP_MAILBOX_ACK ((lp_message_t) 0xe5U)
struct lp_mailbox_t {
lp_core_mailbox_ctx_t mb_ctx;
SemaphoreHandle_t mtx;
SemaphoreHandle_t received_sem;
intr_handle_t intr_handle;
lp_core_mailbox_callback_t rcv_callback;
uint32_t rcv_remaining;
int tx_idx;
};
static struct lp_mailbox_t s_mailbox = { 0 };
/******************************************************************************
* STATIC HELPERS *
******************************************************************************/
static inline int lp_core_next_msg_idx(int idx)
{
return (idx + 1) % LP_MAILBOX_TX_MSG_COUNT;
}
static inline bool mb_msg_status(lp_mailbox_t mailbox, int msg_idx)
{
return lp_core_mailbox_impl_intr_raw(mailbox->mb_ctx) & BIT(msg_idx);
}
static inline bool mb_msg_search_read(lp_mailbox_t mailbox, int* msg_idx, lp_message_t* msg)
{
for (int i = LP_MAILBOX_RX_MSG_IDX; i < (LP_MAILBOX_RX_MSG_IDX + LP_MAILBOX_RX_MSG_COUNT); i += 2) {
if (mb_msg_status(mailbox, i)) {
*msg_idx = i;
*msg = lp_core_mailbox_impl_get_message(mailbox->mb_ctx, i);
return true;
}
}
return false;
}
static inline bool mb_async_mode(lp_mailbox_t mailbox)
{
return mailbox->rcv_callback != NULL;
}
static void lp_core_mailbox_intr_handler(void* arg)
{
lp_mailbox_t mailbox = (lp_mailbox_t) arg;
BaseType_t task_awoken = pdFALSE;
/* If we are not in asynchronous mode, simply notify the task that an interrupt arrived */
if (!mb_async_mode(mailbox)) {
/* Disable the interrupts for all the messages (do NOT clear them) */
lp_core_mailbox_impl_intr_disable(mailbox->mb_ctx, ~0);
xSemaphoreGiveFromISR(mailbox->received_sem, &task_awoken);
if (task_awoken != pdFALSE) {
portYIELD_FROM_ISR();
}
} else {
lp_message_t received[LP_MAILBOX_RX_MSG_COUNT];
int received_count = 0;
/* Acknowledge all the received message as fast as possible */
const uint32_t status = lp_core_mailbox_impl_intr_status(mailbox->mb_ctx);
/* Mask of all the processed messages */
uint32_t clr_mask = 0;
/* Skip one message out of two since one is used for acknowledgement */
for (int i = 0; i < LP_MAILBOX_RX_MSG_COUNT; i += 2) {
const uint32_t mask = BIT(i);
if (status & mask) {
clr_mask |= mask;
received[received_count] = lp_core_mailbox_impl_get_message(mailbox->mb_ctx, LP_MAILBOX_RX_MSG_IDX + i);
/* Acknowledge reception by writing to the next message */
const int ack_msg_idx = LP_MAILBOX_RX_MSG_IDX + lp_core_next_msg_idx(i);
lp_core_mailbox_impl_set_message(mailbox->mb_ctx, ack_msg_idx, LP_MAILBOX_ACK);
lp_core_mailbox_impl_intr_clear(mailbox->mb_ctx, ack_msg_idx);
received_count++;
mailbox->rcv_remaining--;
if (mailbox->rcv_remaining == 0) {
break;
}
}
}
/* Clear the interrupt status */
lp_core_mailbox_impl_intr_clear(mailbox->mb_ctx, clr_mask);
/* Call the callback for all the message received */
for (int i = 0; i < received_count; i++) {
mailbox->rcv_callback(received[i]);
}
/* Disable interrupts if no more messages are expected */
if (mailbox->rcv_remaining == 0) {
lp_core_mailbox_impl_intr_disable(mailbox->mb_ctx, LP_MAILBOX_RX_MSG_MASK);
mailbox->rcv_callback = NULL;
}
}
}
/******************************************************************************
* PUBLIC API *
******************************************************************************/
esp_err_t lp_core_mailbox_init(lp_mailbox_t *mailbox, lp_mailbox_config_t *config)
{
esp_err_t ret;
/* Configuration is unused for now */
(void) config;
if (mailbox == NULL) {
return ESP_ERR_INVALID_ARG;
}
lp_core_mailbox_ctx_t context = lp_core_mailbox_impl_get_context();
if (context == NULL) {
/* Invalid state! LP core didn't initialize the spinlock? (SW backend) */
return ESP_ERR_INVALID_STATE;
}
if (!rv_utils_compare_and_set((volatile uint32_t *) &s_mailbox.mb_ctx, 0, (uint32_t) context)) {
/* Mailbox has already been initialized! */
return ESP_ERR_INVALID_STATE;
}
s_mailbox.received_sem = xSemaphoreCreateBinary();
if (s_mailbox.received_sem == NULL) {
ret = ESP_ERR_NO_MEM;
goto err_free_dev;
}
s_mailbox.mtx = xSemaphoreCreateMutex();
if (s_mailbox.mtx == NULL) {
ret = ESP_ERR_NO_MEM;
goto err_free_sem;
}
/* Allocate an interrupt for the mailbox */
#if SOC_LP_MAILBOX_SUPPORTED
ret = esp_intr_alloc(ETS_MB_HP_INTR_SOURCE, MALLOC_CAP_DEFAULT,
lp_core_mailbox_intr_handler, &s_mailbox,
&s_mailbox.intr_handle);
#else
ret = esp_intr_alloc(ETS_PMU_INTR_SOURCE, MALLOC_CAP_DEFAULT,
lp_core_mailbox_intr_handler, &s_mailbox,
&s_mailbox.intr_handle);
#endif // SOC_LP_MAILBOX_SUPPORTED
if (ret != ESP_OK) {
goto err_free_all;
}
/* Disable interrupts but do not clear them, if the LP core sent a message before HP core
* had time to initialize its mailbox, the interrupt signal would be lost. */
lp_core_mailbox_impl_intr_disable(s_mailbox.mb_ctx, ~0);
/* Enable the global HP mailbox interrupt (control interrupts via mailbox intr register) */
ret = esp_intr_enable(s_mailbox.intr_handle);
if (ret != ESP_OK) {
goto err_free_all;
}
s_mailbox.tx_idx = 0;
*mailbox = &s_mailbox;
return ESP_OK;
err_free_all:
vSemaphoreDelete(s_mailbox.mtx);
err_free_sem:
vSemaphoreDelete(s_mailbox.received_sem);
err_free_dev:
s_mailbox.mb_ctx = NULL;
return ret;
}
void lp_core_mailbox_deinit(lp_mailbox_t mailbox)
{
if (mailbox != NULL) {
lp_core_mailbox_impl_intr_disable(mailbox->mb_ctx, ~0);
lp_core_mailbox_impl_intr_clear(mailbox->mb_ctx, ~0);
vSemaphoreDelete(mailbox->mtx);
vSemaphoreDelete(mailbox->received_sem);
esp_intr_free(mailbox->intr_handle);
/* Mark the structure as deinitialized */
s_mailbox.mb_ctx = NULL;
}
}
esp_err_t lp_core_mailbox_send(lp_mailbox_t mailbox, lp_message_t msg, TickType_t ticks_to_wait)
{
if (mailbox == NULL) {
return ESP_ERR_INVALID_ARG;
}
xSemaphoreTake(mailbox->mtx, portMAX_DELAY);
/* Make sure there isn't already an asynchronous transaction going on */
if (mb_async_mode(mailbox)) {
xSemaphoreGive(mailbox->mtx);
return ESP_ERR_INVALID_STATE;
}
/* Get the address of the next free message */
const int msg_idx = LP_MAILBOX_TX_MSG_IDX + mailbox->tx_idx;
/* The message right after will be used for acknowledgement since writing to one message
* sets the "ready" signal for both LP and HP status registers */
const int next_idx = lp_core_next_msg_idx(mailbox->tx_idx);
const int msg_ack_idx = LP_MAILBOX_TX_MSG_IDX + next_idx;
/* The message after will be the next free message */
mailbox->tx_idx = lp_core_next_msg_idx(next_idx);
/* Make sure the next message status is cleared, to receive acknowledgement */
lp_core_mailbox_impl_intr_clear(mailbox->mb_ctx, BIT(msg_ack_idx));
/* Enable interrupt for the next message (ACK) */
lp_core_mailbox_impl_intr_enable(mailbox->mb_ctx, BIT(msg_ack_idx));
lp_core_mailbox_impl_set_message(mailbox->mb_ctx, msg_idx, msg);
BaseType_t res = xSemaphoreTake(mailbox->received_sem, ticks_to_wait);
if (res == pdFALSE) {
/* Timeout, disable interrupts */
lp_core_mailbox_impl_intr_disable(mailbox->mb_ctx, BIT(msg_ack_idx) | BIT(msg_idx));
xSemaphoreGive(mailbox->mtx);
return ESP_ERR_TIMEOUT;
}
if (mb_msg_status(mailbox, msg_ack_idx)) {
/* Clear the status */
lp_core_mailbox_impl_intr_clear(mailbox->mb_ctx, BIT(msg_ack_idx) | BIT(msg_idx));
}
xSemaphoreGive(mailbox->mtx);
return ESP_OK;
}
esp_err_t lp_core_mailbox_send_async(lp_mailbox_t mailbox, lp_message_t msg)
{
if (mailbox == NULL) {
return ESP_ERR_INVALID_ARG;
}
xSemaphoreTake(mailbox->mtx, portMAX_DELAY);
if (mb_async_mode(mailbox)) {
xSemaphoreGive(mailbox->mtx);
return ESP_ERR_INVALID_STATE;
}
/* Get the address of the next free message */
const int msg_idx = LP_MAILBOX_TX_MSG_IDX + mailbox->tx_idx;
mailbox->tx_idx = (mailbox->tx_idx + 1) % LP_MAILBOX_TX_MSG_COUNT;
lp_core_mailbox_impl_set_message(mailbox->mb_ctx, msg_idx, msg);
xSemaphoreGive(mailbox->mtx);
return ESP_OK;
}
esp_err_t lp_core_mailbox_receive(lp_mailbox_t mailbox, lp_message_t* msg, TickType_t ticks_to_wait)
{
if (mailbox == NULL) {
return ESP_ERR_INVALID_ARG;
}
xSemaphoreTake(mailbox->mtx, portMAX_DELAY);
/* Make sure we are not in asynchronous receive mode */
if (mb_async_mode(mailbox)) {
xSemaphoreGive(mailbox->mtx);
return ESP_ERR_INVALID_STATE;
}
int msg_idx = -1;
while (1) {
/* Check if we received any message */
if (mb_msg_search_read(mailbox, &msg_idx, msg)) {
lp_core_mailbox_impl_intr_clear(mailbox->mb_ctx, BIT(msg_idx));
break;
}
/* No received message yet, enable interrupts (again) */
lp_core_mailbox_impl_intr_enable(mailbox->mb_ctx, LP_MAILBOX_RX_MSG_MASK);
BaseType_t res = xSemaphoreTake(mailbox->received_sem, ticks_to_wait);
if (res == pdFALSE) {
/* Timeout, disable interrupts */
lp_core_mailbox_impl_intr_disable(mailbox->mb_ctx, LP_MAILBOX_RX_MSG_MASK);
xSemaphoreGive(mailbox->mtx);
return ESP_ERR_TIMEOUT;
}
}
/* Acknowledge the message by writing any value to the next one (guaranteed no overflow) */
const int ack_idx = msg_idx + 1;
lp_core_mailbox_impl_set_message(mailbox->mb_ctx, ack_idx, LP_MAILBOX_ACK);
/* Clear ACK messages status */
lp_core_mailbox_impl_intr_clear(mailbox->mb_ctx, BIT(ack_idx));
xSemaphoreGive(mailbox->mtx);
return ESP_OK;
}
esp_err_t lp_core_mailbox_receive_async(lp_mailbox_t mailbox, uint32_t count, lp_core_mailbox_callback_t cb)
{
/* Make sure another asynchronous transaction is not on-going */
if (mailbox == NULL || count == 0 || cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
xSemaphoreTake(mailbox->mtx, portMAX_DELAY);
/* Make sure there isn't already an asynchronous transaction going on */
if (mb_async_mode(mailbox)) {
xSemaphoreGive(mailbox->mtx);
return ESP_ERR_INVALID_STATE;
}
mailbox->rcv_callback = cb;
mailbox->rcv_remaining = count;
/* Enable interrupts for receive */
lp_core_mailbox_impl_intr_enable(mailbox->mb_ctx, LP_MAILBOX_RX_MSG_MASK);
xSemaphoreGive(mailbox->mtx);
return ESP_OK;
}
esp_err_t lp_core_mailbox_receive_async_cancel(lp_mailbox_t mailbox, uint32_t* remaining)
{
if (mailbox == NULL) {
return ESP_ERR_INVALID_ARG;
}
xSemaphoreTake(mailbox->mtx, portMAX_DELAY);
if (!mb_async_mode(mailbox)) {
xSemaphoreGive(mailbox->mtx);
return ESP_ERR_INVALID_STATE;
}
lp_core_mailbox_impl_intr_disable(mailbox->mb_ctx, LP_MAILBOX_RX_MSG_MASK);
mailbox->rcv_callback = NULL;
if (remaining) {
*remaining = mailbox->rcv_remaining;
}
xSemaphoreGive(mailbox->mtx);
return ESP_OK;
}

View File

@@ -0,0 +1,60 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file Implementation of the mailbox port layer, using the hardware controller
*/
#include "ulp_lp_core_mailbox_impl_shared.h"
#include "hal/lp_mailbox_ll.h"
/* Mailbox hardware controller, used as a context */
lp_core_mailbox_ctx_t lp_core_mailbox_impl_get_context(void)
{
return (lp_core_mailbox_ctx_t) &LP_MAILBOX;
}
uint32_t lp_core_mailbox_impl_intr_raw(lp_core_mailbox_ctx_t ctx)
{
return lp_mailbox_ll_get_hp_intr_raw((lp_mb_dev_t*) ctx);
}
uint32_t lp_core_mailbox_impl_intr_status(lp_core_mailbox_ctx_t ctx)
{
return lp_mailbox_ll_hp_intr_status((lp_mb_dev_t*) ctx);
}
void lp_core_mailbox_impl_set_intr_handler(lp_core_mailbox_ctx_t ctx, void (*handler)(void))
{
/* Unused on the HP core */
(void) ctx;
(void) handler;
}
void lp_core_mailbox_impl_intr_enable(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask)
{
lp_mailbox_ll_hp_intr_enable_mask((lp_mb_dev_t*) ctx, msg_mask);
}
void lp_core_mailbox_impl_intr_disable(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask)
{
lp_mailbox_ll_hp_intr_disable_mask((lp_mb_dev_t*) ctx, msg_mask);
}
void lp_core_mailbox_impl_intr_clear(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask)
{
lp_mailbox_ll_hp_intr_clear((lp_mb_dev_t*) ctx, msg_mask);
}
void lp_core_mailbox_impl_set_message(lp_core_mailbox_ctx_t ctx, int index, lp_message_t value)
{
lp_mailbox_ll_set_message((lp_mb_dev_t*) ctx, index, value);
}
lp_message_t lp_core_mailbox_impl_get_message(lp_core_mailbox_ctx_t ctx, int index)
{
return lp_mailbox_ll_get_message((lp_mb_dev_t*) ctx, index);
}

View File

@@ -0,0 +1,112 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file Implementation of the mailbox port layer, using software
*/
#include <string.h>
#include "ulp_lp_core.h"
#include "ulp_lp_core_critical_section_shared.h"
#include "ulp_lp_core_mailbox_impl_shared.h"
typedef struct {
volatile lp_message_t msg[LP_MAILBOX_MSG_COUNT];
/* Message mask to the HP core */
volatile uint32_t to_hp_msg_raw;
/* Message mask to the LP core */
volatile uint32_t to_lp_msg_raw;
/* Lock for all the "raw" values, array is guaranteed to be split between LP/HP */
ulp_lp_core_spinlock_t lock;
} lp_core_mailbox_impl_sw_t;
/* The structure above is defined by the ULP */
extern lp_core_mailbox_impl_sw_t ulp_g_lp_core_mailbox_impl_sw_ctx;
lp_core_mailbox_ctx_t lp_core_mailbox_impl_get_context(void)
{
/* Make sure the LP core initialized the spinlock */
if (ulp_g_lp_core_mailbox_impl_sw_ctx.lock.level[0] != -1) {
return NULL;
}
return (lp_core_mailbox_ctx_t) &ulp_g_lp_core_mailbox_impl_sw_ctx;
}
uint32_t lp_core_mailbox_impl_intr_raw(lp_core_mailbox_ctx_t ctx)
{
lp_core_mailbox_impl_sw_t* sw_ctx = (lp_core_mailbox_impl_sw_t*) ctx;
return sw_ctx->to_hp_msg_raw;
}
uint32_t lp_core_mailbox_impl_intr_status(lp_core_mailbox_ctx_t ctx)
{
lp_core_mailbox_impl_sw_t* sw_ctx = (lp_core_mailbox_impl_sw_t*) ctx;
return sw_ctx->to_hp_msg_raw;
}
void lp_core_mailbox_impl_set_intr_handler(lp_core_mailbox_ctx_t ctx, void (*handler)(void))
{
/* Unused on the HP core */
(void) ctx;
(void) handler;
}
void lp_core_mailbox_impl_intr_enable(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask)
{
lp_core_mailbox_impl_sw_t* sw_ctx = (lp_core_mailbox_impl_sw_t*) ctx;
/* This function is called when asynchronous received is used.
* In the case of the software implementation, we don't really care about the mask, it should
* be able to receive any RX message. */
ulp_lp_core_enter_critical(&sw_ctx->lock);
ulp_lp_core_sw_intr_from_lp_enable(true);
/* On the real mailbox hardware, when enabling the interrupts, if any message case in before that,
* an interrupt will be triggered, so let's simulate the same behavior here */
if (sw_ctx->to_hp_msg_raw) {
/* Simulate a software interrupt to ourselves */
ulp_lp_core_sw_intr_trigger_self();
}
ulp_lp_core_exit_critical(&sw_ctx->lock);
(void) ctx;
(void) msg_mask;
}
void lp_core_mailbox_impl_intr_disable(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask)
{
/* Similarly to the `enable` function, this is used for receiving messages.
* Since we cannot only disable software interrupts, set the flags we defined above. */
ulp_lp_core_sw_intr_from_lp_enable(false);
(void) ctx;
(void) msg_mask;
}
void lp_core_mailbox_impl_intr_clear(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask)
{
lp_core_mailbox_impl_sw_t* sw_ctx = (lp_core_mailbox_impl_sw_t*) ctx;
/* Clear the flag */
ulp_lp_core_enter_critical(&sw_ctx->lock);
sw_ctx->to_hp_msg_raw &= ~msg_mask;
if (sw_ctx->to_hp_msg_raw == 0) {
/* All interrupts were handled */
ulp_lp_core_sw_intr_from_lp_clear();
}
ulp_lp_core_exit_critical(&sw_ctx->lock);
}
void lp_core_mailbox_impl_set_message(lp_core_mailbox_ctx_t ctx, int index, lp_message_t value)
{
lp_core_mailbox_impl_sw_t* sw_ctx = (lp_core_mailbox_impl_sw_t*) ctx;
sw_ctx->msg[index] = value;
ulp_lp_core_enter_critical(&sw_ctx->lock);
sw_ctx->to_lp_msg_raw |= 1 << index;
ulp_lp_core_exit_critical(&sw_ctx->lock);
/* Trigger a software interrupt */
ulp_lp_core_sw_intr_to_lp_trigger();
}
lp_message_t lp_core_mailbox_impl_get_message(lp_core_mailbox_ctx_t ctx, int index)
{
return ((lp_core_mailbox_impl_sw_t*) ctx)->msg[index];
}

View File

@@ -0,0 +1,81 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
#if SOC_LP_MAILBOX_SUPPORTED
#include "hal/lp_mailbox_ll.h"
/**
* @brief Total number of message we have in the hardware
*/
#define LP_MAILBOX_MSG_COUNT (LP_MAILBOX_LL_MSG_COUNT)
#else // !SOC_LP_MAILBOX_SUPPORTED
#define LP_MAILBOX_MSG_COUNT (16)
#endif // SOC_LP_MAILBOX_SUPPORTED
typedef intptr_t lp_message_t;
/**
* @brief Abstract context for the mailbox implementation
*/
typedef void* lp_core_mailbox_ctx_t;
/**
* @brief Get the mailbox context for the current implementation
*/
lp_core_mailbox_ctx_t lp_core_mailbox_impl_get_context(void);
/**
* @brief Set the interrupt handler to call when the a mailbox-related interrupt occurs.
*/
void lp_core_mailbox_impl_set_intr_handler(lp_core_mailbox_ctx_t ctx, void (*handler)(void));
/**
* @brief Raw status of the messages
*/
uint32_t lp_core_mailbox_impl_intr_raw(lp_core_mailbox_ctx_t ctx);
/**
* @brief Status of the messages, returns a bitmap where bit `i` is `1` if message `i` was just received.
*/
uint32_t lp_core_mailbox_impl_intr_status(lp_core_mailbox_ctx_t ctx);
/**
* @brief Enable the interrupts for the messages pointed by the mask
*/
void lp_core_mailbox_impl_intr_enable(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask);
/**
* @brief Disable the interrupts for the messages pointed by the mask
*/
void lp_core_mailbox_impl_intr_disable(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask);
/**
* @brief Clear the interrupts for the messages pointed by the mask
*/
void lp_core_mailbox_impl_intr_clear(lp_core_mailbox_ctx_t ctx, uint32_t msg_mask);
/**
* @brief Set the message and notify the receiver of this new entry
*/
void lp_core_mailbox_impl_set_message(lp_core_mailbox_ctx_t ctx, int index, lp_message_t value);
/**
* @brief Get the message content, regardless of it status
*/
lp_message_t lp_core_mailbox_impl_get_message(lp_core_mailbox_ctx_t ctx, int index);
#ifdef __cplusplus
}
#endif

View File

@@ -89,6 +89,16 @@ void ulp_riscv_timer_resume(void);
#endif
#define ULP_RISCV_CYCLES_PER_MS ULP_RISCV_CYCLES_PER_US*1000
/**
* @brief Retrieves the current number of CPU cycles.
*
* @return The current CPU cycle count.
*/
static inline uint32_t ulp_riscv_get_cpu_cycles(void)
{
return ULP_RISCV_GET_CCOUNT();
}
/**
* @brief Makes the co-processor busy wait for a certain number of cycles
*

View File

@@ -8,6 +8,7 @@ components/ulp/lp_core/lp_core/include/ulp_lp_core_uart.h
components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h
components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h
components/ulp/lp_core/lp_core/include/ulp_lp_core_spi.h
components/ulp/lp_core/lp_core/include/ulp_lp_core_mailbox.h
# ESP-TEE header files
components/esp_tee/subproject/components/tee_sec_storage/include/esp_tee_sec_storage.h
components/esp_tee/subproject/components/tee_attestation/esp_tee_attestation.h

View File

@@ -12,6 +12,7 @@ INPUT += \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_uart.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_mailbox.h \
$(PROJECT_PATH)/components/ulp/ulp_common/include/ulp_common.h \
$(PROJECT_PATH)/components/ulp/lp_core/shared/include/ulp_lp_core_lp_uart_shared.h \
$(PROJECT_PATH)/components/bt/include/esp32c5/include/esp_bt.h \

View File

@@ -9,6 +9,7 @@ INPUT += \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_uart.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_mailbox.h \
$(PROJECT_PATH)/components/bt/include/esp32c6/include/esp_bt.h \
$(PROJECT_PATH)/components/bt/include/$(IDF_TARGET)/include/esp_bt_vs.h \
$(PROJECT_PATH)/components/esp_phy/include/esp_phy_init.h \

View File

@@ -10,6 +10,7 @@ INPUT += \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_uart.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_mailbox.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_spi.h \
$(PROJECT_PATH)/components/ulp/lp_core/shared/include/ulp_lp_core_lp_vad_shared.h \
$(PROJECT_PATH)/components/ulp/ulp_common/include/ulp_common.h \

View File

@@ -237,6 +237,7 @@ To enhance the capabilities of the ULP LP core coprocessor, it has access to per
* LP I2C
* LP UART
:SOC_LP_SPI_SUPPORTED: * LP SPI
:SOC_LP_MAILBOX_SUPPORTED: * LP Mailbox
.. only:: CONFIG_ESP_ROM_HAS_LP_ROM
@@ -391,6 +392,7 @@ Application Examples
- :example:`system/ulp/lp_core/lp_uart/lp_uart_echo` reads data written to a serial console and echoes it back. This example demonstrates the usage of the LP UART driver running on the LP core.
- :example:`system/ulp/lp_core/lp_uart/lp_uart_print` shows how to print various statements from a program running on the LP core.
- :example:`system/ulp/lp_core/lp_uart/lp_uart_char_seq_wakeup` shows how to trigger a wakeup using the LP UART specific character sequence wakeup mode.
- :example:`system/ulp/lp_core/lp_mailbox` shows how to use the mailbox for both synchronous and asynchronous communication between the HP and LP cores. Depending on the target, the implementation may use the hardware mailbox controller (if available) or a pure software implementation based on software interrupts.
- :example:`system/ulp/lp_core/interrupt` shows how to register an interrupt handler on the LP core to receive an interrupt triggered by the main CPU.
- :example:`system/ulp/lp_core/gpio_intr_pulse_counter` shows how to use GPIO interrupts to count pulses while the main CPU is in Deep-sleep mode.
- :example:`system/ulp/lp_core/build_system/` demonstrates how to include custom ``CMakeLists.txt`` file for the ULP app.
@@ -423,6 +425,7 @@ LP Core API Reference
.. include-build-file:: inc/ulp_lp_core_gpio.inc
.. include-build-file:: inc/ulp_lp_core_i2c.inc
.. include-build-file:: inc/ulp_lp_core_uart.inc
.. include-build-file:: inc/ulp_lp_core_mailbox.inc
.. include-build-file:: inc/ulp_lp_core_print.inc
.. include-build-file:: inc/ulp_lp_core_interrupts.inc

View File

@@ -335,6 +335,12 @@ examples/system/ulp/lp_core/lp_i2c:
depends_components:
- ulp
examples/system/ulp/lp_core/lp_mailbox:
enable:
- if: SOC_LP_CORE_SUPPORTED == 1
depends_components:
- ulp
examples/system/ulp/lp_core/lp_spi:
enable:
- if: SOC_LP_SPI_SUPPORTED == 1 and SOC_DEEP_SLEEP_SUPPORTED == 1

View File

@@ -0,0 +1,9 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
list(APPEND SDKCONFIG_DEFAULTS "sdkconfig.defaults")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
idf_build_set_property(MINIMAL_BUILD ON)
project(lp_mailbox)

View File

@@ -0,0 +1,78 @@
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-P4 |
| ----------------- | -------- | -------- | -------- |
# LP Mailbox Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
## Overview
This example demonstrates how to use the mailbox for communication between the LP core and the HP core.
Unlike a classic ring buffer, the mailbox allows transmitting data between the two cores with or without acknowledgment and without requiring a particular order.
This makes it useful for sending sensor data or other streaming values that the LP core may measure.
## How to use example
### Hardware Required
To run this example, you should have an ESP based development board that integrates an LP core.
### Build and Flash
Enter `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
Upon execution, the example should print the following:
```
LP Mailbox initialized successfully
Final sum: 2957
```
## Timing diagram
The following diagram shows what a typical synchronous and asynchronous transaction looks like between the HP core and the LP core.
In the synchronous case, the sender waits for an acknowledgment before proceeding, ensuring that the message is fully processed.
In the asynchronous case, the receiver handles messages through asynchronous callbacks, which can also be canceled if needed at any time.
```mermaid
sequenceDiagram
participant HP as HP core
participant LP as LP core
alt Synchronous
HP->>HP: receive()
activate HP
LP->>LP: send()
activate LP
LP->>HP: write message i
HP-->>LP: ACK: write message i+1
deactivate LP
HP->>HP: return OK
deactivate HP
else Asynchronous
LP->>LP: receive_async()
HP->>HP: send()
activate HP
HP->>LP: write message j
activate LP
LP-->>HP: ACK: write message j+1
deactivate LP
HP->>HP: return OK
deactivate HP
LP->>LP: receive_async_cancel()
end
```
## Troubleshooting
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)

View File

@@ -0,0 +1,25 @@
# Register the component
idf_component_register(SRCS "lp_mailbox_main.c"
INCLUDE_DIRS ""
REQUIRES ulp)
#
# ULP support additions to component CMakeLists.txt.
#
# 1. The LP Core app name must be unique (if multiple components use LP Core).
set(ulp_app_name lp_core_${COMPONENT_NAME})
#
# 2. Specify all C files.
# Files should be placed into a separate directory (in this case, lp_core/),
# which should not be added to COMPONENT_SRCS.
set(ulp_lp_core_sources "lp_core/main.c")
#
# 3. List all the component source files which include automatically
# generated LP Core export file, ${ulp_app_name}.h:
set(ulp_exp_dep_srcs "lp_mailbox_main.c")
#
# 4. Call function to build ULP binary and embed in project using the argument
# values above.
ulp_embed_binary(${ulp_app_name} "${ulp_lp_core_sources}" "${ulp_exp_dep_srcs}")

View File

@@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "ulp_lp_core_print.h"
#include "ulp_lp_core_utils.h"
#include "ulp_lp_core_mailbox.h"
static lp_mailbox_t mailbox;
#define VALUES_COUNT 10
int main (void)
{
uint32_t sum = 0;
/* No configuration for now */
lp_core_mailbox_init(&mailbox, NULL);
lp_message_t messages[VALUES_COUNT] = {
2, 5, 7, 9, 11, 13, 17, 23, 27, 31,
};
/* Send the integers we want the HP core to calculate */
for (int i = 0; i < VALUES_COUNT; i++) {
esp_err_t ret = lp_core_mailbox_send(mailbox, messages[i], -1);
if (ret != ESP_OK) {
lp_core_printf("Error sending message\n");
break;
}
}
/* Receive the squared of each value, calculate the sum and send it to HP */
for (int i = 0; i < VALUES_COUNT; i++) {
esp_err_t ret = lp_core_mailbox_receive(mailbox, &messages[i], -1);
if (ret != ESP_OK) {
lp_core_printf("Error receiving message\n");
break;
}
sum += messages[i];
}
/* Wait a few milliseconds and send the sum asynchronously, so we are not sure if anyone will receive it */
ulp_lp_core_delay_us(10000);
lp_core_mailbox_send_async(mailbox, sum);
while(1) {
}
return 0;
}

View File

@@ -0,0 +1,107 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "esp_sleep.h"
#include "esp_err.h"
#include "lp_core_main.h"
#include "ulp_lp_core.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "lp_core_mailbox.h"
#define VALUES_COUNT 10
extern const uint8_t lp_core_main_bin_start[] asm("_binary_lp_core_main_bin_start");
extern const uint8_t lp_core_main_bin_end[] asm("_binary_lp_core_main_bin_end");
static lp_mailbox_t s_mailbox;
static lp_message_t s_values[VALUES_COUNT];
static volatile SemaphoreHandle_t ready;
static volatile int idx = 0;
static void lp_core_init(void)
{
/* Set LP core wakeup source as the HP CPU */
ulp_lp_core_cfg_t cfg = {
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU,
};
/* Load LP core firmware */
ESP_ERROR_CHECK(ulp_lp_core_load_binary(lp_core_main_bin_start, (lp_core_main_bin_end - lp_core_main_bin_start)));
/* Run LP core */
ESP_ERROR_CHECK(ulp_lp_core_run(&cfg));
// printf("LP core loaded with firmware and running successfully\n");
}
static void rcv_callback(lp_message_t msg)
{
BaseType_t task_awoken = pdFALSE;
/* Add the new message to the array */
s_values[idx++] = msg;
if (idx == VALUES_COUNT) {
xSemaphoreGiveFromISR(ready, &task_awoken);
if (task_awoken != pdFALSE) {
portYIELD_FROM_ISR();
}
}
}
void app_main(void)
{
lp_message_t sum = 0;
esp_err_t err = ESP_OK;
ready = xSemaphoreCreateBinary();
assert(ready != NULL);
/* Load LP Core binary and start the coprocessor */
lp_core_init();
/* Give the LP core some time to initialize the LP mailbox. This is not strictly required
* for targets that have a hardware mailbox but in it is required for the software implementation
* of the mailbox since shared data will be used to communicate between HP and LP cores. */
vTaskDelay(100 / portTICK_PERIOD_MS);
if ((err = lp_core_mailbox_init(&s_mailbox, NULL)) != ESP_OK) {
printf("Could not initialize mailbox: %x\n", err);
return;
}
printf("LP Mailbox initialized successfully\n");
/* Receive the values from the LP core asynchronously */
err = lp_core_mailbox_receive_async(s_mailbox, VALUES_COUNT, rcv_callback);
assert(err == ESP_OK);
/* In practice, we can do something else while we receive the messages, in this example let's just wait */
BaseType_t success = xSemaphoreTake(ready, portMAX_DELAY);
if (!success) {
printf("Error %d taking the semaphore\n", err);
return;
}
/* Received all the value, calculate the squares and send them back */
for (int i = 0; i < VALUES_COUNT; i++) {
const int val = s_values[i];
const int snd = val * val;
err = lp_core_mailbox_send(s_mailbox, snd, portMAX_DELAY);
if (err != ESP_OK) {
printf("Error receiving data from LP core\n");
break;
}
}
/* Try to receive a message synchronously, corresponding to the sum of them all */
err = lp_core_mailbox_receive(s_mailbox, &sum, portMAX_DELAY);
if (err != ESP_OK) {
printf("Error receiving the sum from LP core\n");
} else {
printf("Final sum: %d\n", sum);
}
vSemaphoreDelete(ready);
}

View File

@@ -0,0 +1,13 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.generic
@idf_parametrize('target', ['supported_targets'], indirect=['target'])
def test_lp_mailbox(dut: Dut) -> None:
# Wait for LP core to be loaded and running
dut.expect_exact('LP Mailbox initialized successfully')
dut.expect_exact('Final sum: 2957')

View File

@@ -0,0 +1,4 @@
# Enable LP Core
CONFIG_ULP_COPROC_ENABLED=y
CONFIG_ULP_COPROC_TYPE_LP_CORE=y
CONFIG_ULP_COPROC_RESERVE_MEM=8192