test(spi_flash): Add framework to test driver can work under flash auto-suspend

This commit is contained in:
C.S.M
2025-02-10 13:51:11 +08:00
parent 2458734108
commit 3e79641afa
16 changed files with 956 additions and 14 deletions

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -717,6 +717,80 @@ static inline void spimem_flash_ll_set_common_command_register_info(spi_mem_dev_
dev->user2.val = user2_reg;
}
// For flash test utils
#define SPIMEM_FLASH_LL_SUSPEND_END_INTR SPI_MEM_PES_END_INT_ENA_M
#define SPIMEM_FLASH_LL_INTERRUPT_SOURCE ETS_SPI1_INTR_SOURCE
/**
* @brief Get the address of the interrupt status register.
*
* This function returns a pointer to the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @return volatile void* Pointer to the interrupt status register.
*/
static inline volatile void *spimem_flash_ll_get_interrupt_status_reg(spi_mem_dev_t *dev)
{
return &dev->int_st;
}
/**
* @brief Clear specific interrupt status bits.
*
* This function clears the specified interrupt bits in the interrupt clear register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to clear.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_clear_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_clr.val = mask;
}
/**
* @brief Enable specific interrupt bits.
*
* This function enables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to enable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_enable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val |= mask;
}
/**
* @brief Disable specific interrupt bits.
*
* This function disables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to disable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_disable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val &= (~mask);
}
/**
* @brief Get the current interrupt status.
*
* This function retrieves the current interrupt status from the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[out] intr_status Pointer to a variable where the interrupt status will be stored.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_get_intr_mask(spi_mem_dev_t *dev, uint32_t *intr_status)
{
*intr_status = dev->int_st.val;
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -732,6 +732,80 @@ static inline void spimem_flash_ll_set_common_command_register_info(spi_mem_dev_
dev->user2.val = user2_reg;
}
// For flash test utils
#define SPIMEM_FLASH_LL_SUSPEND_END_INTR SPI_MEM_PES_END_INT_ENA_M
#define SPIMEM_FLASH_LL_INTERRUPT_SOURCE ETS_SPI1_INTR_SOURCE
/**
* @brief Get the address of the interrupt status register.
*
* This function returns a pointer to the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @return volatile void* Pointer to the interrupt status register.
*/
static inline volatile void *spimem_flash_ll_get_interrupt_status_reg(spi_mem_dev_t *dev)
{
return &dev->int_st;
}
/**
* @brief Clear specific interrupt status bits.
*
* This function clears the specified interrupt bits in the interrupt clear register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to clear.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_clear_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_clr.val = mask;
}
/**
* @brief Enable specific interrupt bits.
*
* This function enables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to enable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_enable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val |= mask;
}
/**
* @brief Disable specific interrupt bits.
*
* This function disables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to disable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_disable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val &= (~mask);
}
/**
* @brief Get the current interrupt status.
*
* This function retrieves the current interrupt status from the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[out] intr_status Pointer to a variable where the interrupt status will be stored.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_get_intr_mask(spi_mem_dev_t *dev, uint32_t *intr_status)
{
*intr_status = dev->int_st.val;
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -763,6 +763,80 @@ static inline void spimem_flash_ll_set_common_command_register_info(spi_mem_dev_
dev->user2.val = user2_reg;
}
// For flash test utils
#define SPIMEM_FLASH_LL_SUSPEND_END_INTR SPI_MEM_PES_END_INT_ENA_M
#define SPIMEM_FLASH_LL_INTERRUPT_SOURCE ETS_MSPI_INTR_SOURCE
/**
* @brief Get the address of the interrupt status register.
*
* This function returns a pointer to the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @return volatile void* Pointer to the interrupt status register.
*/
static inline volatile void *spimem_flash_ll_get_interrupt_status_reg(spi_mem_dev_t *dev)
{
return &dev->int_st;
}
/**
* @brief Clear specific interrupt status bits.
*
* This function clears the specified interrupt bits in the interrupt clear register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to clear.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_clear_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_clr.val = mask;
}
/**
* @brief Enable specific interrupt bits.
*
* This function enables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to enable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_enable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val |= mask;
}
/**
* @brief Disable specific interrupt bits.
*
* This function disables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to disable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_disable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val &= (~mask);
}
/**
* @brief Get the current interrupt status.
*
* This function retrieves the current interrupt status from the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[out] intr_status Pointer to a variable where the interrupt status will be stored.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_get_intr_mask(spi_mem_dev_t *dev, uint32_t *intr_status)
{
*intr_status = dev->int_st.val;
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -751,6 +751,80 @@ static inline void spimem_flash_ll_set_common_command_register_info(spi_mem_dev_
dev->user2.val = user2_reg;
}
// For flash test utils
#define SPIMEM_FLASH_LL_SUSPEND_END_INTR SPI_MEM_PES_END_INT_ENA_M
#define SPIMEM_FLASH_LL_INTERRUPT_SOURCE ETS_MSPI_INTR_SOURCE
/**
* @brief Get the address of the interrupt status register.
*
* This function returns a pointer to the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @return volatile void* Pointer to the interrupt status register.
*/
static inline volatile void *spimem_flash_ll_get_interrupt_status_reg(spi_mem_dev_t *dev)
{
return &dev->int_st;
}
/**
* @brief Clear specific interrupt status bits.
*
* This function clears the specified interrupt bits in the interrupt clear register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to clear.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_clear_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_clr.val = mask;
}
/**
* @brief Enable specific interrupt bits.
*
* This function enables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to enable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_enable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val |= mask;
}
/**
* @brief Disable specific interrupt bits.
*
* This function disables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to disable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_disable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val &= (~mask);
}
/**
* @brief Get the current interrupt status.
*
* This function retrieves the current interrupt status from the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[out] intr_status Pointer to a variable where the interrupt status will be stored.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_get_intr_mask(spi_mem_dev_t *dev, uint32_t *intr_status)
{
*intr_status = dev->int_st.val;
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -732,6 +732,80 @@ static inline void spimem_flash_ll_set_common_command_register_info(spi_mem_dev_
dev->user2.val = user2_reg;
}
// For flash test utils
#define SPIMEM_FLASH_LL_SUSPEND_END_INTR SPI_MEM_PES_END_INT_ENA_M
#define SPIMEM_FLASH_LL_INTERRUPT_SOURCE ETS_MSPI_INTR_SOURCE
/**
* @brief Get the address of the interrupt status register.
*
* This function returns a pointer to the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @return volatile void* Pointer to the interrupt status register.
*/
static inline volatile void *spimem_flash_ll_get_interrupt_status_reg(spi_mem_dev_t *dev)
{
return &dev->int_st;
}
/**
* @brief Clear specific interrupt status bits.
*
* This function clears the specified interrupt bits in the interrupt clear register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to clear.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_clear_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_clr.val = mask;
}
/**
* @brief Enable specific interrupt bits.
*
* This function enables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to enable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_enable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val |= mask;
}
/**
* @brief Disable specific interrupt bits.
*
* This function disables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to disable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_disable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val &= (~mask);
}
/**
* @brief Get the current interrupt status.
*
* This function retrieves the current interrupt status from the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[out] intr_status Pointer to a variable where the interrupt status will be stored.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_get_intr_mask(spi_mem_dev_t *dev, uint32_t *intr_status)
{
*intr_status = dev->int_st.val;
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -732,6 +732,80 @@ static inline void spimem_flash_ll_set_common_command_register_info(spi_mem_dev_
dev->user2.val = user2_reg;
}
// For flash test utils
#define SPIMEM_FLASH_LL_SUSPEND_END_INTR SPI_MEM_PES_END_INT_ENA_M
#define SPIMEM_FLASH_LL_INTERRUPT_SOURCE ETS_MSPI_INTR_SOURCE
/**
* @brief Get the address of the interrupt status register.
*
* This function returns a pointer to the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @return volatile void* Pointer to the interrupt status register.
*/
static inline volatile void *spimem_flash_ll_get_interrupt_status_reg(spi_mem_dev_t *dev)
{
return &dev->int_st;
}
/**
* @brief Clear specific interrupt status bits.
*
* This function clears the specified interrupt bits in the interrupt clear register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to clear.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_clear_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_clr.val = mask;
}
/**
* @brief Enable specific interrupt bits.
*
* This function enables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to enable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_enable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val |= mask;
}
/**
* @brief Disable specific interrupt bits.
*
* This function disables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to disable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_disable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val &= (~mask);
}
/**
* @brief Get the current interrupt status.
*
* This function retrieves the current interrupt status from the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[out] intr_status Pointer to a variable where the interrupt status will be stored.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_get_intr_mask(spi_mem_dev_t *dev, uint32_t *intr_status)
{
*intr_status = dev->int_st.val;
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -794,6 +794,80 @@ static inline void spimem_flash_ll_set_common_command_register_info(spi_mem_dev_
dev->user2.val = user2_reg;
}
// For flash test utils
#define SPIMEM_FLASH_LL_SUSPEND_END_INTR SPI1_MEM_C_PES_END_INT_ENA_M
#define SPIMEM_FLASH_LL_INTERRUPT_SOURCE ETS_MSPI_INTR_SOURCE
/**
* @brief Get the address of the interrupt status register.
*
* This function returns a pointer to the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @return volatile void* Pointer to the interrupt status register.
*/
static inline volatile void *spimem_flash_ll_get_interrupt_status_reg(spi_mem_dev_t *dev)
{
return &dev->int_st;
}
/**
* @brief Clear specific interrupt status bits.
*
* This function clears the specified interrupt bits in the interrupt clear register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to clear.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_clear_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_clr.val = mask;
}
/**
* @brief Enable specific interrupt bits.
*
* This function enables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to enable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_enable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val |= mask;
}
/**
* @brief Disable specific interrupt bits.
*
* This function disables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to disable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_disable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val &= (~mask);
}
/**
* @brief Get the current interrupt status.
*
* This function retrieves the current interrupt status from the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[out] intr_status Pointer to a variable where the interrupt status will be stored.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_get_intr_mask(spi_mem_dev_t *dev, uint32_t *intr_status)
{
*intr_status = dev->int_st.val;
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -759,6 +759,80 @@ static inline void spimem_flash_ll_set_common_command_register_info(spi_mem_dev_
dev->user2.val = user2_reg;
}
// For flash test utils
#define SPIMEM_FLASH_LL_SUSPEND_END_INTR SPI_MEM_PES_END_INT_ENA_M
#define SPIMEM_FLASH_LL_INTERRUPT_SOURCE ETS_SPI1_INTR_SOURCE
/**
* @brief Get the address of the interrupt status register.
*
* This function returns a pointer to the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @return volatile void* Pointer to the interrupt status register.
*/
static inline volatile void *spimem_flash_ll_get_interrupt_status_reg(spi_mem_dev_t *dev)
{
return &dev->int_st;
}
/**
* @brief Clear specific interrupt status bits.
*
* This function clears the specified interrupt bits in the interrupt clear register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to clear.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_clear_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_clr.val = mask;
}
/**
* @brief Enable specific interrupt bits.
*
* This function enables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to enable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_enable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val |= mask;
}
/**
* @brief Disable specific interrupt bits.
*
* This function disables the specified interrupts in the interrupt enable register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[in] mask Bitmask specifying which interrupt bits to disable.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_disable_intr_mask(spi_mem_dev_t *dev, uint32_t mask)
{
dev->int_ena.val &= (~mask);
}
/**
* @brief Get the current interrupt status.
*
* This function retrieves the current interrupt status from the interrupt status register of the SPI memory device.
*
* @param[in] dev Pointer to the SPI memory device structure.
* @param[out] intr_status Pointer to a variable where the interrupt status will be stored.
*/
__attribute__((always_inline))
static inline void spimem_flash_ll_get_intr_mask(spi_mem_dev_t *dev, uint32_t *intr_status)
{
*intr_status = dev->int_st.val;
}
#ifdef __cplusplus
}
#endif

View File

@@ -2,4 +2,4 @@ set(srcs "test_flash_utils.c")
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS include
REQUIRES esp_partition)
REQUIRES esp_partition spi_flash)

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
*/
@@ -8,12 +8,22 @@
#include <esp_types.h>
#include "esp_partition.h"
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <freertos/task.h>
#include <stdio.h>
#include "esp_intr_alloc.h"
#include "esp_rom_sys.h"
#include "esp_partition.h"
#include "soc/soc_caps.h"
#if SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
#include "hal/spimem_flash_ll.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* Return the 'flash_test' custom data partition
* defined in the custom partition table.
@@ -22,6 +32,68 @@ extern "C" {
*/
const esp_partition_t *get_test_flash_partition(void);
#if SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
// Forward declaration of the flash test handle structure
typedef struct flash_test_handle_s flash_test_handle_t;
// Event data structure for flash test (currently empty, can be expanded as needed)
typedef struct {
} flash_test_event_data_t;
// Callback type definition for handling flash test events
typedef bool (*flash_test_callback_t)(flash_test_handle_t *handle, const flash_test_event_data_t *event_data, void *arg);
// Structure to hold event callbacks for flash test
typedef struct {
flash_test_callback_t auto_suspend_done; // Callback triggered when auto suspend is complete
} flash_test_event_callbacks_t;
// Definition of the flash test handle structure
struct flash_test_handle_s {
spi_mem_dev_t *dev;
flash_test_callback_t auto_suspend_done; // Callback for auto suspend event
uint32_t suspend_times; // Counter for the number of suspend operations
intr_handle_t intr_handle; // Handle for the interrupt associated with flash test
uint32_t operation_address; // flash operation address.
uint32_t operation_size; // flash operation size.
};
/**
* @brief Initialize the flash test system.
*
* This function sets up the flash test handle and necessary resources.
*
* @param[out] test_handle Pointer to the pointer that will hold the initialized handle.
* @return esp_err_t ESP_OK on success, or an appropriate error code on failure.
*/
esp_err_t spi_flash_suspend_test_init(flash_test_handle_t **test_handle);
/**
* @brief Deinitialize the flash test system.
*
* This function releases the resources associated with the flash test handle.
*
* @param[in] handle Pointer to the flash test handle to deinitialize.
* @return esp_err_t ESP_OK on success, or an appropriate error code on failure.
*/
esp_err_t spi_flash_suspend_test_deinit(flash_test_handle_t *handle);
/**
* @brief Finds the last partition in the flash memory.
*
* This function retrieves the last partition available for testing purposes.
*
* @return const esp_partition_t* Pointer to the last partition, or NULL if none found.
*/
const esp_partition_t *spi_flash_suspend_test_find_last_partition(void);
/**
* @brief Invalidates the flash cache.
*/
void spi_flash_suspend_test_invalidate_cache(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -1,11 +1,21 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdio.h>
#include "test_flash_utils.h"
#include "hal/cache_ll.h"
#include "esp_intr_alloc.h"
#include "esp_flash.h"
#include "esp_rom_sys.h"
#include "esp_partition.h"
#include "esp_log.h"
#include "esp_check.h"
#define ALIGN_UP_TO_64KB(x) (((x) + 0xFFFF) & ~0xFFFF)
const esp_partition_t *get_test_flash_partition(void)
{
@@ -15,3 +25,119 @@ const esp_partition_t *get_test_flash_partition(void)
assert(result != NULL); /* means partition table set wrong */
return result;
}
#if SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
#include "hal/spimem_flash_ll.h"
static const char TAG[] = "test-flash";
IRAM_ATTR static bool flash_auto_suspend_done(flash_test_handle_t *handle, const flash_test_event_data_t *event_data, void *arg)
{
handle->suspend_times++;
return false;
}
IRAM_ATTR static void flash_suspend_isr_handler(void *arg)
{
flash_test_handle_t *flash_test = (flash_test_handle_t *)arg;
uint32_t val;
spimem_flash_ll_get_intr_mask(flash_test->dev, &val);
spimem_flash_ll_clear_intr_mask(flash_test->dev, val);
if (val & SPIMEM_FLASH_LL_SUSPEND_END_INTR) {
if (flash_test->auto_suspend_done) {
flash_test->auto_suspend_done(flash_test, NULL, flash_test);
}
}
}
esp_err_t spi_flash_suspend_test_init(flash_test_handle_t **test_handle)
{
esp_err_t ret = ESP_OK;
flash_test_handle_t *handle = heap_caps_calloc(1, sizeof(flash_test_handle_t), MALLOC_CAP_DEFAULT);
ESP_RETURN_ON_FALSE(handle, ESP_ERR_NO_MEM, TAG, "no memory for flash test handle");
handle->dev = spimem_flash_ll_get_hw(SPI1_HOST);
handle->auto_suspend_done = flash_auto_suspend_done;
spimem_flash_ll_enable_intr_mask(handle->dev, SPIMEM_FLASH_LL_SUSPEND_END_INTR);
ret = esp_intr_alloc_intrstatus(SPIMEM_FLASH_LL_INTERRUPT_SOURCE, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LOWMED, (uint32_t)spimem_flash_ll_get_interrupt_status_reg(handle->dev), SPIMEM_FLASH_LL_SUSPEND_END_INTR, flash_suspend_isr_handler, handle, &handle->intr_handle);
ESP_GOTO_ON_ERROR(ret, err, TAG, "interrupt allocate for spi flash failed");
const esp_partition_t *last_partition = NULL;
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
// find the last valid partition
while (it != NULL) {
const esp_partition_t *current_partition = esp_partition_get(it);
if (last_partition == NULL || current_partition->address > last_partition->address) {
last_partition = current_partition;
}
it = esp_partition_next(it);
}
esp_partition_iterator_release(it);
uint32_t flash_size;
esp_flash_get_size(last_partition->flash_chip, &flash_size);
handle->operation_address = ALIGN_UP_TO_64KB(last_partition->address + last_partition->size);
handle->operation_size = flash_size - (last_partition->address + last_partition->size);
if (handle->operation_size < 64 * 1024) {
ESP_GOTO_ON_ERROR(ret, err, TAG, "reset memory is so small");
}
*test_handle = handle;
return ESP_OK;
err:
if (handle) {
free(handle);
}
return ret;
}
const esp_partition_t * spi_flash_suspend_test_find_last_partition(void) {
const esp_partition_t *last_partition = NULL;
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
if (it == NULL) {
ESP_LOGE(TAG, "No partitions found!");
return NULL;
}
// find the last valid partition
while (it != NULL) {
const esp_partition_t *current_partition = esp_partition_get(it);
if (last_partition == NULL || current_partition->address > last_partition->address) {
last_partition = current_partition;
}
it = esp_partition_next(it);
}
esp_partition_iterator_release(it);
return last_partition;
}
esp_err_t spi_flash_suspend_test_deinit(flash_test_handle_t *handle)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "no memory for flash test handle");
if (handle->intr_handle) {
ESP_RETURN_ON_ERROR(esp_intr_free(handle->intr_handle), TAG, "delete interrupt service failed");
}
free(handle);
return ESP_OK;
}
void spi_flash_suspend_test_invalidate_cache(void)
{
cache_ll_invalidate_all(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL);
}
#endif // SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND

View File

@@ -1,8 +1,14 @@
set(srcs "test_app_main.c"
"test_flash_suspend.c")
if(NOT CONFIG_I2C_MASTER_ISR_HANDLER_IN_IRAM)
list(APPEND srcs "test_i2c_flash_text.c")
endif()
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES unity test_utils spi_flash driver esp_partition
PRIV_REQUIRES unity test_utils spi_flash driver esp_partition esp_driver_i2c
WHOLE_ARCHIVE)

View File

@@ -0,0 +1,3 @@
dependencies:
test_flash_utils:
path: ${IDF_PATH}/components/spi_flash/test_apps/components/test_flash_utils

View File

@@ -0,0 +1,142 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_flash.h"
#include "test_flash_utils.h"
#include "esp_err.h"
#include "soc/soc_caps.h"
#include "esp_private/periph_ctrl.h"
#include "driver/i2c_master.h"
#include "esp_log.h"
#include "test_utils.h"
#include "driver/gptimer.h"
#if SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
#include "hal/spimem_flash_ll.h"
#define TIMER_RESOLUTION_HZ (1 * 1000 * 1000) // 1MHz resolution
typedef struct {
flash_test_handle_t *flash_handle;
SemaphoreHandle_t sem;
} spi_flash_test_context_t;
void spi_flash_suspend_test_task(void *arg)
{
spi_flash_test_context_t *context = (spi_flash_test_context_t *)arg;
uint32_t cnt = 200;
while (cnt--) {
if (context->flash_handle->suspend_times != 0) {
break;
}
esp_err_t ret = esp_flash_erase_region(NULL, context->flash_handle->operation_address, context->flash_handle->operation_size);
if (ret != ESP_OK) {
abort();
}
}
// Give Semaphore and delete task.
xSemaphoreGive(context->sem);
vTaskDelete(NULL);
}
static bool IRAM_ATTR gptimer_alarm_suspend_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
{
i2c_master_dev_handle_t dev_handle = (i2c_master_dev_handle_t) user_ctx;
spi_flash_suspend_test_invalidate_cache();
uint8_t buf[6] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
i2c_master_transmit(dev_handle, buf, 6, 200);
return false;
}
TEST_CASE("Flash suspend support on i2c", "[i2c]")
{
// Init context.
spi_flash_test_context_t *context = heap_caps_calloc(1, sizeof(spi_flash_test_context_t), MALLOC_CAP_DEFAULT);
assert(context != NULL);
context->sem = xSemaphoreCreateBinary();
assert(context->sem != NULL);
spi_flash_suspend_test_init(&context->flash_handle);
i2c_master_bus_config_t i2c_bus_config = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = 0,
.scl_io_num = 6,
.sda_io_num = 7,
.glitch_ignore_cnt = 7,
.trans_queue_depth = 37,
.flags.enable_internal_pullup = true,
};
i2c_master_bus_handle_t bus_handle;
TEST_ESP_OK(i2c_new_master_bus(&i2c_bus_config, &bus_handle));
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = 0x58,
.scl_speed_hz = 400000,
.flags.disable_ack_check = true,
};
i2c_master_dev_handle_t dev_handle;
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
gptimer_handle_t gptimer = NULL;
gptimer_config_t timer_config = {
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
.direction = GPTIMER_COUNT_UP,
.resolution_hz = TIMER_RESOLUTION_HZ,
};
TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimer));
gptimer_alarm_config_t alarm_config = {
.reload_count = 0,
.alarm_count = 1000,
.flags.auto_reload_on_alarm = true,
};
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
gptimer_event_callbacks_t cbs = {
.on_alarm = gptimer_alarm_suspend_cb,
};
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, dev_handle));
TEST_ESP_OK(gptimer_enable(gptimer));
TEST_ESP_OK(gptimer_start(gptimer));
// Then use gptimer for trigger testing function every time.
// Quit when suspend is triggered.
xTaskCreatePinnedToCore(spi_flash_suspend_test_task, "flash_task", 4096, context, 2, NULL, 0);
xSemaphoreTake(context->sem, pdMS_TO_TICKS(5000)); // We don't always wait the semaphore
printf("test finishes, suspend for %ld times\n", context->flash_handle->suspend_times);
TEST_ASSERT_NOT_EQUAL(0, context->flash_handle->suspend_times);
TEST_ESP_OK(gptimer_stop(gptimer));
TEST_ESP_OK(gptimer_disable(gptimer));
TEST_ESP_OK(gptimer_del_timer(gptimer));
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
// Clear sources
vTaskDelay(10);
vSemaphoreDelete(context->sem);
spi_flash_suspend_test_deinit(context->flash_handle);
free(context);
}
#endif //SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND

View File

@@ -1,6 +1,5 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import pytest
from pytest_embedded import Dut
@@ -11,6 +10,7 @@ from pytest_embedded import Dut
'config',
[
'release',
'i2c_isr_flash',
],
indirect=True,
)

View File

@@ -0,0 +1 @@
CONFIG_I2C_MASTER_ISR_HANDLER_IN_IRAM=n