Merge branch 'feature/add_api_spi_slave_trans_in_isr' into 'master'

spi_slave: add isr version api to add transaction in isr callback

Closes IDF-6199 and IDF-6049

See merge request espressif/esp-idf!20587
This commit is contained in:
Wan Lei
2023-01-05 12:46:01 +08:00
18 changed files with 514 additions and 92 deletions

View File

@@ -104,6 +104,7 @@ menu "Driver Configurations"
config SPI_SLAVE_ISR_IN_IRAM config SPI_SLAVE_ISR_IN_IRAM
bool "Place SPI slave ISR function into IRAM" bool "Place SPI slave ISR function into IRAM"
default y default y
select PERIPH_CTRL_FUNC_IN_IRAM
help help
Place the SPI slave ISR in to IRAM to avoid possible cache miss. Place the SPI slave ISR in to IRAM to avoid possible cache miss.

View File

@@ -16,6 +16,7 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_err.h" #include "esp_err.h"
#include "hal/spi_types.h" #include "hal/spi_types.h"
#include "driver/spi_slave.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -23,6 +24,7 @@ extern "C" {
/** /**
* @brief Reset the trans Queue of slave driver
* @note * @note
* This API is used to reset SPI Slave transaction queue. After calling this function: * This API is used to reset SPI Slave transaction queue. After calling this function:
* - The SPI Slave transaction queue will be reset. * - The SPI Slave transaction queue will be reset.
@@ -37,3 +39,39 @@ extern "C" {
* - ESP_OK on success * - ESP_OK on success
*/ */
esp_err_t spi_slave_queue_reset(spi_host_device_t host); esp_err_t spi_slave_queue_reset(spi_host_device_t host);
/**
* @brief Reset the trans Queue from within ISR of slave driver
* @note
* This API is used to reset SPI Slave transaction queue from within ISR. After calling this function:
* - The SPI Slave transaction queue will be empty.
*
* @param host SPI peripheral that is acting as a slave
*
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spi_slave_queue_reset_isr(spi_host_device_t host);
/**
* @brief Queue a SPI transaction in ISR
* @note
* Similar as ``spi_slave_queue_trans``, but can and can only called within an ISR, then get the transaction results
* through the transaction descriptor passed in ``spi_slave_interface_config_t::post_trans_cb``. if use this API, you
* should trigger a transaction by normal ``spi_slave_queue_trans`` once and only once to start isr
*
* If you use both ``spi_slave_queue_trans`` and ``spi_slave_queue_trans_isr`` simultaneously to transfer valid data,
* you should deal with concurrency issues on your self risk
*
* @param host SPI peripheral that is acting as a slave
* @param trans_desc Description of transaction to execute. Not const because we may want to write status back
* into the transaction description.
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NO_MEM if trans_queue is full
* - ESP_OK on success
*/
esp_err_t spi_slave_queue_trans_isr(spi_host_device_t host, const spi_slave_transaction_t *trans_desc);

View File

@@ -7,35 +7,34 @@
#include <string.h> #include <string.h>
#include "esp_types.h" #include "esp_types.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_check.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_pm.h" #include "esp_pm.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "esp_rom_gpio.h"
#include "esp_rom_sys.h" #include "esp_rom_sys.h"
#include "soc/lldesc.h" #include "soc/lldesc.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "soc/spi_periph.h" #include "soc/spi_periph.h"
#include "soc/soc_memory_layout.h" #include "soc/soc_memory_layout.h"
#include "hal/spi_ll.h"
#include "hal/spi_slave_hal.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "esp_private/spi_common_internal.h"
#include "driver/spi_slave.h" #include "driver/spi_slave.h"
#include "hal/gpio_hal.h"
#include "hal/spi_slave_hal.h" #include "hal/spi_slave_hal.h"
#include "esp_private/spi_slave_internal.h"
#include "esp_private/spi_common_internal.h"
static const char *SPI_TAG = "spi_slave"; static const char *SPI_TAG = "spi_slave";
#define SPI_CHECK(a, str, ret_val) \
if (!(a)) { \ #define SPI_CHECK(a, str, ret_val) ESP_RETURN_ON_FALSE(a, ret_val, SPI_TAG, str)
ESP_LOGE(SPI_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
return (ret_val); \
}
#ifdef CONFIG_SPI_SLAVE_ISR_IN_IRAM #ifdef CONFIG_SPI_SLAVE_ISR_IN_IRAM
#define SPI_SLAVE_ISR_ATTR IRAM_ATTR #define SPI_SLAVE_ISR_ATTR IRAM_ATTR
@@ -61,6 +60,7 @@ typedef struct {
QueueHandle_t ret_queue; QueueHandle_t ret_queue;
bool dma_enabled; bool dma_enabled;
bool cs_iomux; bool cs_iomux;
uint8_t cs_in_signal;
uint32_t tx_dma_chan; uint32_t tx_dma_chan;
uint32_t rx_dma_chan; uint32_t rx_dma_chan;
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
@@ -72,6 +72,7 @@ static spi_slave_t *spihost[SOC_SPI_PERIPH_NUM];
static void spi_intr(void *arg); static void spi_intr(void *arg);
__attribute__((always_inline))
static inline bool is_valid_host(spi_host_device_t host) static inline bool is_valid_host(spi_host_device_t host)
{ {
//SPI1 can be used as GPSPI only on ESP32 //SPI1 can be used as GPSPI only on ESP32
@@ -91,7 +92,7 @@ static inline bool SPI_SLAVE_ISR_ATTR bus_is_iomux(spi_slave_t *host)
static void SPI_SLAVE_ISR_ATTR freeze_cs(spi_slave_t *host) static void SPI_SLAVE_ISR_ATTR freeze_cs(spi_slave_t *host)
{ {
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, spi_periph_signal[host->id].spics_in, false); esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, host->cs_in_signal, false);
} }
// Use this function instead of cs_initial to avoid overwrite the output config // Use this function instead of cs_initial to avoid overwrite the output config
@@ -99,9 +100,9 @@ static void SPI_SLAVE_ISR_ATTR freeze_cs(spi_slave_t *host)
static inline void SPI_SLAVE_ISR_ATTR restore_cs(spi_slave_t *host) static inline void SPI_SLAVE_ISR_ATTR restore_cs(spi_slave_t *host)
{ {
if (host->cs_iomux) { if (host->cs_iomux) {
gpio_iomux_in(host->cfg.spics_io_num, spi_periph_signal[host->id].spics_in); gpio_ll_iomux_in(GPIO_HAL_GET_HW(GPIO_PORT_0), host->cfg.spics_io_num, host->cs_in_signal);
} else { } else {
esp_rom_gpio_connect_in_signal(host->cfg.spics_io_num, spi_periph_signal[host->id].spics_in, false); esp_rom_gpio_connect_in_signal(host->cfg.spics_io_num, host->cs_in_signal, false);
} }
} }
@@ -161,6 +162,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
spicommon_cs_initialize(host, slave_config->spics_io_num, 0, !bus_is_iomux(spihost[host])); spicommon_cs_initialize(host, slave_config->spics_io_num, 0, !bus_is_iomux(spihost[host]));
// check and save where cs line really route through // check and save where cs line really route through
spihost[host]->cs_iomux = (slave_config->spics_io_num == spi_periph_signal[host].spics0_iomux_pin) && bus_is_iomux(spihost[host]); spihost[host]->cs_iomux = (slave_config->spics_io_num == spi_periph_signal[host].spics0_iomux_pin) && bus_is_iomux(spihost[host]);
spihost[host]->cs_in_signal = spi_periph_signal[host].spics_in;
} }
// The slave DMA suffers from unexpected transactions. Forbid reading if DMA is enabled by disabling the CS line. // The slave DMA suffers from unexpected transactions. Forbid reading if DMA is enabled by disabling the CS line.
@@ -204,6 +206,9 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
} }
int flags = bus_config->intr_flags | ESP_INTR_FLAG_INTRDISABLED; int flags = bus_config->intr_flags | ESP_INTR_FLAG_INTRDISABLED;
#ifdef CONFIG_SPI_SLAVE_ISR_IN_IRAM
flags |= ESP_INTR_FLAG_IRAM;
#endif
err = esp_intr_alloc(spicommon_irqsource_for_host(host), flags, spi_intr, (void *)spihost[host], &spihost[host]->intr); err = esp_intr_alloc(spicommon_irqsource_for_host(host), flags, spi_intr, (void *)spihost[host], &spihost[host]->intr);
if (err != ESP_OK) { if (err != ESP_OK) {
ret = err; ret = err;
@@ -314,6 +319,24 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_queue_reset(spi_host_device_t host)
return ESP_OK; return ESP_OK;
} }
esp_err_t SPI_SLAVE_ISR_ATTR spi_slave_queue_reset_isr(spi_host_device_t host)
{
ESP_RETURN_ON_FALSE_ISR(is_valid_host(host), ESP_ERR_INVALID_ARG, SPI_TAG, "invalid host");
ESP_RETURN_ON_FALSE_ISR(spihost[host], ESP_ERR_INVALID_ARG, SPI_TAG, "host not slave");
spi_slave_transaction_t *trans = NULL;
BaseType_t do_yield = pdFALSE;
while( pdFALSE == xQueueIsQueueEmptyFromISR(spihost[host]->trans_queue)) {
xQueueReceiveFromISR(spihost[host]->trans_queue, &trans, &do_yield);
}
if (do_yield) {
portYIELD_FROM_ISR();
}
spihost[host]->cur_trans = NULL;
return ESP_OK;
}
esp_err_t SPI_SLAVE_ATTR spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait) esp_err_t SPI_SLAVE_ATTR spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait)
{ {
BaseType_t r; BaseType_t r;
@@ -333,6 +356,29 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_queue_trans(spi_host_device_t host, const spi
return ESP_OK; return ESP_OK;
} }
esp_err_t SPI_SLAVE_ISR_ATTR spi_slave_queue_trans_isr(spi_host_device_t host, const spi_slave_transaction_t *trans_desc)
{
BaseType_t r;
BaseType_t do_yield = pdFALSE;
ESP_RETURN_ON_FALSE_ISR(is_valid_host(host), ESP_ERR_INVALID_ARG, SPI_TAG, "invalid host");
ESP_RETURN_ON_FALSE_ISR(spihost[host], ESP_ERR_INVALID_ARG, SPI_TAG, "host not slave");
ESP_RETURN_ON_FALSE_ISR(spihost[host]->dma_enabled == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
ESP_ERR_INVALID_ARG, SPI_TAG, "txdata not in DMA-capable memory");
ESP_RETURN_ON_FALSE_ISR(spihost[host]->dma_enabled == 0 || trans_desc->rx_buffer==NULL ||
(esp_ptr_dma_capable(trans_desc->rx_buffer) && esp_ptr_word_aligned(trans_desc->rx_buffer) &&
(trans_desc->length%4==0)),
ESP_ERR_INVALID_ARG, SPI_TAG, "rxdata not in DMA-capable memory or not WORD aligned");
ESP_RETURN_ON_FALSE_ISR(trans_desc->length <= spihost[host]->max_transfer_sz * 8, ESP_ERR_INVALID_ARG, SPI_TAG, "data transfer > host maximum");
r = xQueueSendFromISR(spihost[host]->trans_queue, (void *)&trans_desc, &do_yield);
if (!r) {
return ESP_ERR_NO_MEM;
}
if (do_yield) {
portYIELD_FROM_ISR();
}
return ESP_OK;
}
esp_err_t SPI_SLAVE_ATTR spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transaction_t **trans_desc, TickType_t ticks_to_wait) esp_err_t SPI_SLAVE_ATTR spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transaction_t **trans_desc, TickType_t ticks_to_wait)
{ {

View File

@@ -8,3 +8,16 @@ set(EXTRA_COMPONENT_DIRS
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(spi_slave_test) project(spi_slave_test)
if(CONFIG_COMPILER_DUMP_RTL_FILES)
add_custom_target(check_test_app_sections ALL
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py
--rtl-dir ${CMAKE_BINARY_DIR}/esp-idf/driver/
--elf-file ${CMAKE_BINARY_DIR}/spi_slave_test.elf
find-refs
--from-sections=.iram0.text
--to-sections=.flash.text,.flash.rodata
--exit-code
DEPENDS ${elf}
)
endif()

View File

@@ -10,6 +10,6 @@ set(srcs
# the component can be registered as WHOLE_ARCHIVE # the component can be registered as WHOLE_ARCHIVE
idf_component_register( idf_component_register(
SRCS ${srcs} SRCS ${srcs}
PRIV_REQUIRES test_utils driver test_driver_utils PRIV_REQUIRES test_utils driver test_driver_utils spi_flash
WHOLE_ARCHIVE WHOLE_ARCHIVE
) )

View File

@@ -15,6 +15,8 @@
#include "driver/spi_master.h" #include "driver/spi_master.h"
#include "driver/spi_slave.h" #include "driver/spi_slave.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "esp_private/cache_utils.h"
#include "esp_private/spi_slave_internal.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"
@@ -40,47 +42,47 @@ static inline void int_connect( uint32_t gpio, uint32_t sigo, uint32_t sigi )
esp_rom_gpio_connect_in_signal( gpio, sigi, false ); esp_rom_gpio_connect_in_signal( gpio, sigi, false );
} }
static void master_init( spi_device_handle_t* spi) static void master_init( spi_device_handle_t *spi)
{ {
esp_err_t ret; esp_err_t ret;
spi_bus_config_t buscfg={ spi_bus_config_t buscfg = {
.miso_io_num=PIN_NUM_MISO, .miso_io_num = PIN_NUM_MISO,
.mosi_io_num=PIN_NUM_MOSI, .mosi_io_num = PIN_NUM_MOSI,
.sclk_io_num=PIN_NUM_CLK, .sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num=UNCONNECTED_PIN, .quadwp_io_num = UNCONNECTED_PIN,
.quadhd_io_num=-1 .quadhd_io_num = -1
}; };
spi_device_interface_config_t devcfg={ spi_device_interface_config_t devcfg = {
.clock_speed_hz=4*1000*1000, //currently only up to 4MHz for internel connect .clock_speed_hz = 4 * 1000 * 1000, //currently only up to 4MHz for internel connect
.mode=0, //SPI mode 0 .mode = 0, //SPI mode 0
.spics_io_num=PIN_NUM_CS, //CS pin .spics_io_num = PIN_NUM_CS, //CS pin
.queue_size=7, //We want to be able to queue 7 transactions at a time .queue_size = 7, //We want to be able to queue 7 transactions at a time
.pre_cb=NULL, .pre_cb = NULL,
.cs_ena_posttrans=5, .cs_ena_posttrans = 5,
.cs_ena_pretrans=1, .cs_ena_pretrans = 1,
}; };
//Initialize the SPI bus //Initialize the SPI bus
ret=spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO); ret = spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
TEST_ASSERT(ret==ESP_OK); TEST_ASSERT(ret == ESP_OK);
//Attach the LCD to the SPI bus //Attach the LCD to the SPI bus
ret=spi_bus_add_device(TEST_SPI_HOST, &devcfg, spi); ret = spi_bus_add_device(TEST_SPI_HOST, &devcfg, spi);
TEST_ASSERT(ret==ESP_OK); TEST_ASSERT(ret == ESP_OK);
} }
static void slave_init(void) static void slave_init(void)
{ {
//Configuration for the SPI bus //Configuration for the SPI bus
spi_bus_config_t buscfg={ spi_bus_config_t buscfg = {
.mosi_io_num=PIN_NUM_MOSI, .mosi_io_num = PIN_NUM_MOSI,
.miso_io_num=PIN_NUM_MISO, .miso_io_num = PIN_NUM_MISO,
.sclk_io_num=PIN_NUM_CLK .sclk_io_num = PIN_NUM_CLK
}; };
//Configuration for the SPI slave interface //Configuration for the SPI slave interface
spi_slave_interface_config_t slvcfg={ spi_slave_interface_config_t slvcfg = {
.mode=0, .mode = 0,
.spics_io_num=PIN_NUM_CS, .spics_io_num = PIN_NUM_CS,
.queue_size=3, .queue_size = 3,
.flags=0, .flags = 0,
}; };
//Enable pull-ups on SPI lines so we don't detect rogue pulses when no master is connected. //Enable pull-ups on SPI lines so we don't detect rogue pulses when no master is connected.
gpio_set_pull_mode(PIN_NUM_MOSI, GPIO_PULLUP_ONLY); gpio_set_pull_mode(PIN_NUM_MOSI, GPIO_PULLUP_ONLY);
@@ -90,7 +92,8 @@ static void slave_init(void)
TEST_ESP_OK(spi_slave_initialize(TEST_SLAVE_HOST, &buscfg, &slvcfg, SPI_DMA_CH_AUTO)); TEST_ESP_OK(spi_slave_initialize(TEST_SLAVE_HOST, &buscfg, &slvcfg, SPI_DMA_CH_AUTO));
} }
static void custom_setup(void) { static void custom_setup(void)
{
//Initialize buffers //Initialize buffers
memset(master_txbuf, 0, sizeof(master_txbuf)); memset(master_txbuf, 0, sizeof(master_txbuf));
memset(master_rxbuf, 0, sizeof(master_rxbuf)); memset(master_rxbuf, 0, sizeof(master_rxbuf));
@@ -109,13 +112,14 @@ static void custom_setup(void) {
int_connect( PIN_NUM_CLK, spi_periph_signal[TEST_SPI_HOST].spiclk_out, spi_periph_signal[TEST_SLAVE_HOST].spiclk_in ); int_connect( PIN_NUM_CLK, spi_periph_signal[TEST_SPI_HOST].spiclk_out, spi_periph_signal[TEST_SLAVE_HOST].spiclk_in );
} }
static void custom_teardown(void) { static void custom_teardown(void)
{
TEST_ASSERT(spi_slave_free(TEST_SLAVE_HOST) == ESP_OK); TEST_ASSERT(spi_slave_free(TEST_SLAVE_HOST) == ESP_OK);
TEST_ASSERT(spi_bus_remove_device(spi) == ESP_OK); TEST_ASSERT(spi_bus_remove_device(spi) == ESP_OK);
TEST_ASSERT(spi_bus_free(TEST_SPI_HOST) == ESP_OK); TEST_ASSERT(spi_bus_free(TEST_SPI_HOST) == ESP_OK);
} }
TEST_CASE("test fullduplex slave with only RX direction","[spi]") TEST_CASE("test fullduplex slave with only RX direction", "[spi]")
{ {
custom_setup(); custom_setup();
@@ -124,11 +128,11 @@ TEST_CASE("test fullduplex slave with only RX direction","[spi]")
for ( int i = 0; i < 4; i ++ ) { for ( int i = 0; i < 4; i ++ ) {
//slave send //slave send
spi_slave_transaction_t slave_t; spi_slave_transaction_t slave_t;
spi_slave_transaction_t* out; spi_slave_transaction_t *out;
memset(&slave_t, 0, sizeof(spi_slave_transaction_t)); memset(&slave_t, 0, sizeof(spi_slave_transaction_t));
slave_t.length=8*32; slave_t.length = 8 * 32;
slave_t.tx_buffer=NULL; slave_t.tx_buffer = NULL;
slave_t.rx_buffer=slave_rxbuf; slave_t.rx_buffer = slave_rxbuf;
// Colorize RX buffer with known pattern // Colorize RX buffer with known pattern
memset( slave_rxbuf, 0x66, sizeof(slave_rxbuf)); memset( slave_rxbuf, 0x66, sizeof(slave_rxbuf));
@@ -137,22 +141,22 @@ TEST_CASE("test fullduplex slave with only RX direction","[spi]")
//send //send
spi_transaction_t t = {}; spi_transaction_t t = {};
t.length = 32*(i+1); t.length = 32 * (i + 1);
if ( t.length != 0 ) { if ( t.length != 0 ) {
t.tx_buffer = master_txbuf; t.tx_buffer = master_txbuf;
t.rx_buffer = NULL; t.rx_buffer = NULL;
} }
spi_device_transmit( spi, (spi_transaction_t*)&t ); spi_device_transmit( spi, (spi_transaction_t *)&t );
//wait for end //wait for end
TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &out, portMAX_DELAY)); TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &out, portMAX_DELAY));
//show result //show result
ESP_LOGI(SLAVE_TAG, "trans_len: %d", slave_t.trans_len); ESP_LOGI(SLAVE_TAG, "trans_len: %d", slave_t.trans_len);
ESP_LOG_BUFFER_HEX( "master tx", t.tx_buffer, t.length/8 ); ESP_LOG_BUFFER_HEX( "master tx", t.tx_buffer, t.length / 8 );
ESP_LOG_BUFFER_HEX( "slave rx", slave_t.rx_buffer, (slave_t.trans_len+7)/8); ESP_LOG_BUFFER_HEX( "slave rx", slave_t.rx_buffer, (slave_t.trans_len + 7) / 8);
TEST_ASSERT_EQUAL_HEX8_ARRAY( t.tx_buffer, slave_t.rx_buffer, t.length/8 ); TEST_ASSERT_EQUAL_HEX8_ARRAY( t.tx_buffer, slave_t.rx_buffer, t.length / 8 );
TEST_ASSERT_EQUAL( t.length, slave_t.trans_len ); TEST_ASSERT_EQUAL( t.length, slave_t.trans_len );
} }
@@ -161,7 +165,7 @@ TEST_CASE("test fullduplex slave with only RX direction","[spi]")
ESP_LOGI(SLAVE_TAG, "test passed."); ESP_LOGI(SLAVE_TAG, "test passed.");
} }
TEST_CASE("test fullduplex slave with only TX direction","[spi]") TEST_CASE("test fullduplex slave with only TX direction", "[spi]")
{ {
custom_setup(); custom_setup();
@@ -170,11 +174,11 @@ TEST_CASE("test fullduplex slave with only TX direction","[spi]")
for ( int i = 0; i < 4; i ++ ) { for ( int i = 0; i < 4; i ++ ) {
//slave send //slave send
spi_slave_transaction_t slave_t; spi_slave_transaction_t slave_t;
spi_slave_transaction_t* out; spi_slave_transaction_t *out;
memset(&slave_t, 0, sizeof(spi_slave_transaction_t)); memset(&slave_t, 0, sizeof(spi_slave_transaction_t));
slave_t.length=8*32; slave_t.length = 8 * 32;
slave_t.tx_buffer=slave_txbuf; slave_t.tx_buffer = slave_txbuf;
slave_t.rx_buffer=NULL; slave_t.rx_buffer = NULL;
// Colorize RX buffer with known pattern // Colorize RX buffer with known pattern
memset( master_rxbuf, 0x66, sizeof(master_rxbuf)); memset( master_rxbuf, 0x66, sizeof(master_rxbuf));
@@ -183,22 +187,22 @@ TEST_CASE("test fullduplex slave with only TX direction","[spi]")
//send //send
spi_transaction_t t = {}; spi_transaction_t t = {};
t.length = 32*(i+1); t.length = 32 * (i + 1);
if ( t.length != 0 ) { if ( t.length != 0 ) {
t.tx_buffer = NULL; t.tx_buffer = NULL;
t.rx_buffer = master_rxbuf; t.rx_buffer = master_rxbuf;
} }
spi_device_transmit( spi, (spi_transaction_t*)&t ); spi_device_transmit( spi, (spi_transaction_t *)&t );
//wait for end //wait for end
TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &out, portMAX_DELAY)); TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &out, portMAX_DELAY));
//show result //show result
ESP_LOGI(SLAVE_TAG, "trans_len: %d", slave_t.trans_len); ESP_LOGI(SLAVE_TAG, "trans_len: %d", slave_t.trans_len);
ESP_LOG_BUFFER_HEX( "master rx", t.rx_buffer, t.length/8 ); ESP_LOG_BUFFER_HEX( "master rx", t.rx_buffer, t.length / 8 );
ESP_LOG_BUFFER_HEX( "slave tx", slave_t.tx_buffer, (slave_t.trans_len+7)/8); ESP_LOG_BUFFER_HEX( "slave tx", slave_t.tx_buffer, (slave_t.trans_len + 7) / 8);
TEST_ASSERT_EQUAL_HEX8_ARRAY( slave_t.tx_buffer, t.rx_buffer, t.length/8 ); TEST_ASSERT_EQUAL_HEX8_ARRAY( slave_t.tx_buffer, t.rx_buffer, t.length / 8 );
TEST_ASSERT_EQUAL( t.length, slave_t.trans_len ); TEST_ASSERT_EQUAL( t.length, slave_t.trans_len );
} }
@@ -207,7 +211,7 @@ TEST_CASE("test fullduplex slave with only TX direction","[spi]")
ESP_LOGI(SLAVE_TAG, "test passed."); ESP_LOGI(SLAVE_TAG, "test passed.");
} }
TEST_CASE("test slave send unaligned","[spi]") TEST_CASE("test slave send unaligned", "[spi]")
{ {
custom_setup(); custom_setup();
@@ -217,11 +221,11 @@ TEST_CASE("test slave send unaligned","[spi]")
for ( int i = 0; i < 4; i ++ ) { for ( int i = 0; i < 4; i ++ ) {
//slave send //slave send
spi_slave_transaction_t slave_t; spi_slave_transaction_t slave_t;
spi_slave_transaction_t* out; spi_slave_transaction_t *out;
memset(&slave_t, 0, sizeof(spi_slave_transaction_t)); memset(&slave_t, 0, sizeof(spi_slave_transaction_t));
slave_t.length=8*32; slave_t.length = 8 * 32;
slave_t.tx_buffer=slave_txbuf+i; slave_t.tx_buffer = slave_txbuf + i;
slave_t.rx_buffer=slave_rxbuf; slave_t.rx_buffer = slave_rxbuf;
// Colorize RX buffers with known pattern // Colorize RX buffers with known pattern
memset( master_rxbuf, 0x66, sizeof(master_rxbuf)); memset( master_rxbuf, 0x66, sizeof(master_rxbuf));
@@ -231,25 +235,25 @@ TEST_CASE("test slave send unaligned","[spi]")
//send //send
spi_transaction_t t = {}; spi_transaction_t t = {};
t.length = 32*(i+1); t.length = 32 * (i + 1);
if ( t.length != 0 ) { if ( t.length != 0 ) {
t.tx_buffer = master_txbuf+i; t.tx_buffer = master_txbuf + i;
t.rx_buffer = master_rxbuf+i; t.rx_buffer = master_rxbuf + i;
} }
spi_device_transmit( spi, (spi_transaction_t*)&t ); spi_device_transmit( spi, (spi_transaction_t *)&t );
//wait for end //wait for end
TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &out, portMAX_DELAY)); TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &out, portMAX_DELAY));
//show result //show result
ESP_LOGI(SLAVE_TAG, "trans_len: %d", slave_t.trans_len); ESP_LOGI(SLAVE_TAG, "trans_len: %d", slave_t.trans_len);
ESP_LOG_BUFFER_HEX( "master tx", t.tx_buffer, t.length/8 ); ESP_LOG_BUFFER_HEX( "master tx", t.tx_buffer, t.length / 8 );
ESP_LOG_BUFFER_HEX( "master rx", t.rx_buffer, t.length/8 ); ESP_LOG_BUFFER_HEX( "master rx", t.rx_buffer, t.length / 8 );
ESP_LOG_BUFFER_HEX( "slave tx", slave_t.tx_buffer, (slave_t.trans_len+7)/8); ESP_LOG_BUFFER_HEX( "slave tx", slave_t.tx_buffer, (slave_t.trans_len + 7) / 8);
ESP_LOG_BUFFER_HEX( "slave rx", slave_t.rx_buffer, (slave_t.trans_len+7)/8); ESP_LOG_BUFFER_HEX( "slave rx", slave_t.rx_buffer, (slave_t.trans_len + 7) / 8);
TEST_ASSERT_EQUAL_HEX8_ARRAY( t.tx_buffer, slave_t.rx_buffer, t.length/8 ); TEST_ASSERT_EQUAL_HEX8_ARRAY( t.tx_buffer, slave_t.rx_buffer, t.length / 8 );
TEST_ASSERT_EQUAL_HEX8_ARRAY( slave_t.tx_buffer, t.rx_buffer, t.length/8 ); TEST_ASSERT_EQUAL_HEX8_ARRAY( slave_t.tx_buffer, t.rx_buffer, t.length / 8 );
TEST_ASSERT_EQUAL( t.length, slave_t.trans_len ); TEST_ASSERT_EQUAL( t.length, slave_t.trans_len );
} }
@@ -316,12 +320,12 @@ static void unaligned_test_master(void)
vTaskDelay(50); vTaskDelay(50);
unity_wait_for_signal("Slave ready"); unity_wait_for_signal("Slave ready");
TEST_ESP_OK(spi_device_transmit(spi, (spi_transaction_t*)&t)); TEST_ESP_OK(spi_device_transmit(spi, (spi_transaction_t *)&t));
//show result //show result
ESP_LOG_BUFFER_HEX("master tx:", master_send_buf+i, length_in_bytes); ESP_LOG_BUFFER_HEX("master tx:", master_send_buf + i, length_in_bytes);
ESP_LOG_BUFFER_HEX("master rx:", master_recv_buf, length_in_bytes); ESP_LOG_BUFFER_HEX("master rx:", master_recv_buf, length_in_bytes);
TEST_ASSERT_EQUAL_HEX8_ARRAY(slave_send_buf+i, master_recv_buf, length_in_bytes); TEST_ASSERT_EQUAL_HEX8_ARRAY(slave_send_buf + i, master_recv_buf, length_in_bytes);
//clean //clean
memset(master_recv_buf, 0x00, BUF_SIZE); memset(master_recv_buf, 0x00, BUF_SIZE);
@@ -383,6 +387,307 @@ static void unaligned_test_slave(void)
TEST_ASSERT(spi_slave_free(TEST_SPI_HOST) == ESP_OK); TEST_ASSERT(spi_slave_free(TEST_SPI_HOST) == ESP_OK);
} }
TEST_CASE_MULTIPLE_DEVICES("SPI_Slave_Unaligned_Test", "[spi_ms][test_env=generic_multi_device][timeout=120]", unaligned_test_master, unaligned_test_slave); TEST_CASE_MULTIPLE_DEVICES("SPI_Slave_Unaligned_Test", "[spi_ms][timeout=120]", unaligned_test_master, unaligned_test_slave);
#endif //#if (TEST_SPI_PERIPH_NUM == 1) #endif //#if (TEST_SPI_PERIPH_NUM == 1)
#if CONFIG_SPI_SLAVE_ISR_IN_IRAM
#define TEST_IRAM_TRANS_NUM 8
#define TEST_TRANS_LEN 120
#define TEST_BUFFER_SZ (TEST_IRAM_TRANS_NUM*TEST_TRANS_LEN)
static void test_slave_iram_master_normal(void)
{
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
spi_device_handle_t dev_handle = {0};
spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &dev_handle));
uint8_t *master_send = heap_caps_malloc(TEST_BUFFER_SZ, MALLOC_CAP_DMA);
uint8_t *master_recv = heap_caps_calloc(1, TEST_BUFFER_SZ, MALLOC_CAP_DMA);
uint8_t *master_exp = heap_caps_malloc(TEST_BUFFER_SZ, MALLOC_CAP_DEFAULT);
get_tx_buffer(1001, master_send, master_exp, TEST_BUFFER_SZ);
spi_transaction_t trans_cfg = {
.tx_buffer = master_send,
.rx_buffer = master_recv,
.user = master_exp,
.length = TEST_TRANS_LEN * 8,
};
//first trans to trigger slave enter isr
unity_send_signal("Master ready");
unity_wait_for_signal("Slave ready");
TEST_ESP_OK(spi_device_transmit(dev_handle, &trans_cfg));
for (uint8_t cnt = 0; cnt < TEST_IRAM_TRANS_NUM; cnt ++) {
trans_cfg.tx_buffer = master_send + TEST_TRANS_LEN * cnt;
trans_cfg.rx_buffer = master_recv + TEST_TRANS_LEN * cnt;
trans_cfg.user = master_exp + TEST_TRANS_LEN * cnt;
unity_wait_for_signal("Slave ready");
TEST_ESP_OK(spi_device_transmit(dev_handle, &trans_cfg));
ESP_LOG_BUFFER_HEX("master tx", trans_cfg.tx_buffer, TEST_TRANS_LEN);
ESP_LOG_BUFFER_HEX_LEVEL("master rx", trans_cfg.rx_buffer, TEST_TRANS_LEN, ESP_LOG_DEBUG);
ESP_LOG_BUFFER_HEX_LEVEL("master exp", trans_cfg.user, TEST_TRANS_LEN, ESP_LOG_DEBUG);
spitest_cmp_or_dump(trans_cfg.user, trans_cfg.rx_buffer, TEST_TRANS_LEN);
}
free(master_send);
free(master_recv);
free(master_exp);
spi_bus_remove_device(dev_handle);
spi_bus_free(TEST_SPI_HOST);
}
//------------------------------------test slave func-----------------------------------------
static IRAM_ATTR void ESP_LOG_BUFFER_HEX_ISR(const char *tag, const uint8_t *buff, const uint32_t byte_len)
{
esp_rom_printf(DRAM_STR("%s: "), tag);
for (uint16_t i = 0; i < byte_len; i++) {
if (0 == i % 16) {
esp_rom_printf(DRAM_STR("\n"));
}
esp_rom_printf(DRAM_STR("%02x "), buff[i]);
}
esp_rom_printf(DRAM_STR("\n"));
}
static uint32_t isr_iram_cnt;
static uint32_t iram_test_fail;
static IRAM_ATTR void test_slave_iram_post_trans_cbk(spi_slave_transaction_t *curr_trans)
{
isr_iram_cnt ++;
// first trans is the trigger trans with random data by master
if (isr_iram_cnt > 1) {
ESP_LOG_BUFFER_HEX_ISR(DRAM_STR("slave tx"), curr_trans->tx_buffer, curr_trans->trans_len / 8);
if (memcmp(curr_trans->rx_buffer, curr_trans->user, curr_trans->trans_len / 8)) {
ESP_LOG_BUFFER_HEX_ISR(DRAM_STR("slave rx"), curr_trans->rx_buffer, curr_trans->trans_len / 8);
ESP_LOG_BUFFER_HEX_ISR(DRAM_STR("slave exp"), curr_trans->user, curr_trans->trans_len / 8);
iram_test_fail = true;
}
}
if (isr_iram_cnt <= TEST_IRAM_TRANS_NUM) {
// str "Send signal: [Slave ready]!\n" used for CI to run test automatically
// here use `esp_rom_printf` instead `unity_send_signal` because cache is disabled by test
esp_rom_printf(DRAM_STR("Send signal: [Slave ready]!\n"));
}
}
static IRAM_ATTR void test_slave_isr_iram(void)
{
spi_bus_config_t bus_cfg = SPI_BUS_TEST_DEFAULT_CONFIG();
spi_slave_interface_config_t slvcfg = SPI_SLAVE_TEST_DEFAULT_CONFIG();
slvcfg.flags = SPI_SLAVE_NO_RETURN_RESULT;
slvcfg.queue_size = 16;
slvcfg.post_trans_cb = test_slave_iram_post_trans_cbk;
TEST_ESP_OK(spi_slave_initialize(TEST_SPI_HOST, &bus_cfg, &slvcfg, SPI_DMA_CH_AUTO));
uint8_t *slave_iram_send = heap_caps_malloc(TEST_BUFFER_SZ, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *slave_iram_recv = heap_caps_calloc(1, TEST_BUFFER_SZ, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *slave_iram_exp = heap_caps_malloc(TEST_BUFFER_SZ, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
get_tx_buffer(1001, slave_iram_exp, slave_iram_send, TEST_BUFFER_SZ);
spi_slave_transaction_t trans_cfg[TEST_IRAM_TRANS_NUM] = {0};
unity_wait_for_signal("Master ready");
trans_cfg[0].tx_buffer = slave_iram_send;
trans_cfg[0].rx_buffer = slave_iram_recv;
trans_cfg[0].user = slave_iram_exp;
trans_cfg[0].length = TEST_TRANS_LEN * 8;
spi_slave_queue_trans(TEST_SPI_HOST, &trans_cfg[0], portMAX_DELAY);
// mount several transaction first
for (uint8_t i = 0; i < TEST_IRAM_TRANS_NUM; i++) {
trans_cfg[i].tx_buffer = slave_iram_send + TEST_TRANS_LEN * i;
trans_cfg[i].rx_buffer = slave_iram_recv + TEST_TRANS_LEN * i;
trans_cfg[i].user = slave_iram_exp + TEST_TRANS_LEN * i;
trans_cfg[i].length = TEST_TRANS_LEN * 8;
spi_slave_queue_trans(TEST_SPI_HOST, &trans_cfg[i], portMAX_DELAY);
}
// disable cache then send signal `ready` to start transaction
spi_flash_disable_interrupts_caches_and_other_cpu();
esp_rom_printf(DRAM_STR("Send signal: [Slave ready]!\n"));
while (isr_iram_cnt <= TEST_IRAM_TRANS_NUM) {
esp_rom_delay_us(10);
}
spi_flash_enable_interrupts_caches_and_other_cpu();
if (iram_test_fail) {
TEST_FAIL();
}
free(slave_iram_send);
free(slave_iram_recv);
free(slave_iram_exp);
spi_slave_free(TEST_SPI_HOST);
}
TEST_CASE_MULTIPLE_DEVICES("SPI_Slave: Test_ISR_IRAM_disable_cache", "[spi_ms]", test_slave_iram_master_normal, test_slave_isr_iram);
static uint32_t isr_trans_cnt, isr_trans_test_fail;
static IRAM_ATTR void test_trans_in_isr_post_trans_cbk(spi_slave_transaction_t *curr_trans)
{
isr_trans_cnt ++;
//first trans is the trigger trans with random data
if (isr_trans_cnt > 1) {
ESP_LOG_BUFFER_HEX_ISR(DRAM_STR("slave tx"), curr_trans->tx_buffer, curr_trans->trans_len / 8);
if (memcmp(curr_trans->rx_buffer, curr_trans->user, curr_trans->trans_len / 8)) {
ESP_LOG_BUFFER_HEX_ISR(DRAM_STR("slave rx"), curr_trans->rx_buffer, curr_trans->trans_len / 8);
ESP_LOG_BUFFER_HEX_ISR(DRAM_STR("slave exp"), curr_trans->user, curr_trans->trans_len / 8);
isr_trans_test_fail = true;
}
curr_trans->tx_buffer = (uint8_t *)curr_trans->tx_buffer + TEST_TRANS_LEN;
curr_trans->rx_buffer = (uint8_t *)curr_trans->rx_buffer + TEST_TRANS_LEN;
curr_trans->user = (uint8_t *)curr_trans->user + TEST_TRANS_LEN;
}
if (isr_trans_cnt <= TEST_IRAM_TRANS_NUM) {
if (ESP_OK == spi_slave_queue_trans_isr(TEST_SPI_HOST, curr_trans)) {
// use `esp_rom_printf` instead `unity_send_signal` because cache is disabled by test
esp_rom_printf(DRAM_STR("Send signal: [Slave ready]!\n"));
} else {
esp_rom_printf(DRAM_STR("SPI Add trans in isr fail, Queue full\n"));
}
}
}
static IRAM_ATTR void spi_slave_trans_in_isr(void)
{
spi_bus_config_t bus_cfg = SPI_BUS_TEST_DEFAULT_CONFIG();
spi_slave_interface_config_t slvcfg = SPI_SLAVE_TEST_DEFAULT_CONFIG();
slvcfg.flags = SPI_SLAVE_NO_RETURN_RESULT;
slvcfg.queue_size = 16;
slvcfg.post_trans_cb = test_trans_in_isr_post_trans_cbk;
TEST_ESP_OK(spi_slave_initialize(TEST_SPI_HOST, &bus_cfg, &slvcfg, SPI_DMA_CH_AUTO));
uint8_t *slave_isr_send = heap_caps_malloc(TEST_BUFFER_SZ, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *slave_isr_recv = heap_caps_calloc(1, TEST_BUFFER_SZ, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *slave_isr_exp = heap_caps_malloc(TEST_BUFFER_SZ, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
get_tx_buffer(1001, slave_isr_exp, slave_isr_send, TEST_BUFFER_SZ);
spi_slave_transaction_t trans_cfg = {
.tx_buffer = slave_isr_send,
.rx_buffer = slave_isr_recv,
.user = slave_isr_exp,
.length = TEST_TRANS_LEN * 8,
};
unity_wait_for_signal("Master ready");
//start a trans by normal API first to trigger spi isr
spi_slave_queue_trans(TEST_SPI_HOST, &trans_cfg, portMAX_DELAY);
spi_flash_disable_interrupts_caches_and_other_cpu();
esp_rom_printf(DRAM_STR("Send signal: [Slave ready]!\n"));
while (isr_trans_cnt <= TEST_IRAM_TRANS_NUM) {
esp_rom_delay_us(10);
}
spi_flash_enable_interrupts_caches_and_other_cpu();
if (isr_trans_test_fail) {
TEST_FAIL();
}
free(slave_isr_send);
free(slave_isr_recv);
free(slave_isr_exp);
spi_slave_free(TEST_SPI_HOST);
}
TEST_CASE_MULTIPLE_DEVICES("SPI_Slave: Test_Queue_Trans_in_ISR", "[spi_ms]", test_slave_iram_master_normal, spi_slave_trans_in_isr);
uint32_t dummy_data[2] = {0x38383838, 0x5b5b5b5b};
spi_slave_transaction_t dummy_trans[2];
static uint32_t queue_reset_isr_trans_cnt, test_queue_reset_isr_fail;
static IRAM_ATTR void test_queue_reset_in_isr_post_trans_cbk(spi_slave_transaction_t *curr_trans)
{
queue_reset_isr_trans_cnt ++;
//first trans is the trigger trans with random data
if (queue_reset_isr_trans_cnt > 1) {
ESP_LOG_BUFFER_HEX_ISR(DRAM_STR("slave tx"), curr_trans->tx_buffer, curr_trans->length / 8);
if (memcmp(curr_trans->rx_buffer, curr_trans->user, curr_trans->length / 8)) {
ESP_LOG_BUFFER_HEX_ISR(DRAM_STR("slave rx"), curr_trans->rx_buffer, curr_trans->length / 8);
ESP_LOG_BUFFER_HEX_ISR(DRAM_STR("slave exp"), curr_trans->user, curr_trans->length / 8);
test_queue_reset_isr_fail = true;
}
if (queue_reset_isr_trans_cnt > 4) {
// add some confusing transactions
dummy_data[0] ++;
dummy_data[1] --;
spi_slave_queue_trans_isr(TEST_SPI_HOST, &dummy_trans[0]);
ESP_LOG_BUFFER_HEX_ISR(DRAM_STR("Queue Hacked hahhhhh..."), dummy_trans[0].tx_buffer, dummy_trans[0].length / 8);
spi_slave_queue_trans_isr(TEST_SPI_HOST, &dummy_trans[1]);
ESP_LOG_BUFFER_HEX_ISR(DRAM_STR("Queue Hacked hahhhhh..."), dummy_trans[1].tx_buffer, dummy_trans[1].length / 8);
if (ESP_OK == spi_slave_queue_reset_isr(TEST_SPI_HOST)) {
esp_rom_printf(DRAM_STR("Queue reset done, continue\n"));
}
}
curr_trans->tx_buffer = (uint8_t *)curr_trans->tx_buffer + TEST_TRANS_LEN;
curr_trans->rx_buffer = (uint8_t *)curr_trans->rx_buffer + TEST_TRANS_LEN;
curr_trans->user = (uint8_t *)curr_trans->user + TEST_TRANS_LEN;
}
if (queue_reset_isr_trans_cnt <= TEST_IRAM_TRANS_NUM) {
if (ESP_OK == spi_slave_queue_trans_isr(TEST_SPI_HOST, curr_trans)) {
// use `esp_rom_printf` instead `unity_send_signal` because cache is disabled by test
esp_rom_printf(DRAM_STR("Send signal: [Slave ready]!\n"));
} else {
esp_rom_printf(DRAM_STR("SPI Add trans in isr fail, Queue full\n"));
}
}
}
static IRAM_ATTR void spi_queue_reset_in_isr(void)
{
spi_bus_config_t bus_cfg = SPI_BUS_TEST_DEFAULT_CONFIG();
spi_slave_interface_config_t slvcfg = SPI_SLAVE_TEST_DEFAULT_CONFIG();
slvcfg.flags = SPI_SLAVE_NO_RETURN_RESULT;
slvcfg.queue_size = 16;
slvcfg.post_trans_cb = test_queue_reset_in_isr_post_trans_cbk;
TEST_ESP_OK(spi_slave_initialize(TEST_SPI_HOST, &bus_cfg, &slvcfg, SPI_DMA_CH_AUTO));
uint8_t *slave_isr_send = heap_caps_malloc(TEST_BUFFER_SZ, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *slave_isr_recv = heap_caps_calloc(1, TEST_BUFFER_SZ, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *slave_isr_exp = heap_caps_malloc(TEST_BUFFER_SZ, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
get_tx_buffer(1001, slave_isr_exp, slave_isr_send, TEST_BUFFER_SZ);
spi_slave_transaction_t trans_cfg = {
.tx_buffer = slave_isr_send,
.rx_buffer = slave_isr_recv,
.user = slave_isr_exp,
.length = TEST_TRANS_LEN * 8,
};
unity_wait_for_signal("Master ready");
for (uint8_t i = 0; i < 2; i++) {
dummy_trans[i].tx_buffer = &dummy_data[i];
dummy_trans[i].rx_buffer = &dummy_data[i];
dummy_trans[i].user = &dummy_data[i];
dummy_trans[i].length = sizeof(uint32_t) * 8;
}
// start a trans by normal API first to trigger spi isr
spi_slave_queue_trans(TEST_SPI_HOST, &trans_cfg, portMAX_DELAY);
// spi_flash_disable_interrupts_caches_and_other_cpu();
esp_rom_printf(DRAM_STR("Send signal: [Slave ready]!\n"));
while (queue_reset_isr_trans_cnt <= TEST_IRAM_TRANS_NUM) {
esp_rom_delay_us(10);
}
// spi_flash_enable_interrupts_caches_and_other_cpu();
if (test_queue_reset_isr_fail) {
TEST_FAIL();
}
free(slave_isr_send);
free(slave_isr_recv);
free(slave_isr_exp);
spi_slave_free(TEST_SPI_HOST);
}
TEST_CASE_MULTIPLE_DEVICES("SPI_Slave: Test_Queue_Reset_in_ISR", "[spi_ms]", test_slave_iram_master_normal, spi_queue_reset_in_isr);
#endif // CONFIG_SPI_SLAVE_ISR_IN_IRAM

View File

@@ -7,6 +7,7 @@ import pytest
# If `test_env` is define, should not run on generic runner # If `test_env` is define, should not run on generic runner
@pytest.mark.supported_targets @pytest.mark.supported_targets
@pytest.mark.generic @pytest.mark.generic
@pytest.mark.parametrize('config', ['defaults',], indirect=True)
def test_slave_single_dev(case_tester) -> None: # type: ignore def test_slave_single_dev(case_tester) -> None: # type: ignore
for case in case_tester.test_menu: for case in case_tester.test_menu:
if 'test_env' in case.attributes: if 'test_env' in case.attributes:
@@ -17,7 +18,7 @@ def test_slave_single_dev(case_tester) -> None: # type: ignore
# if `test_env` not defined, will run on `generic_multi_device` by default # if `test_env` not defined, will run on `generic_multi_device` by default
@pytest.mark.supported_targets @pytest.mark.supported_targets
@pytest.mark.generic_multi_device @pytest.mark.generic_multi_device
@pytest.mark.parametrize('count', [2,], indirect=True) @pytest.mark.parametrize('count, config', [(2, 'defaults'), (2, 'iram_safe')], indirect=True)
def test_slave_multi_dev(case_tester) -> None: # type: ignore def test_slave_multi_dev(case_tester) -> None: # type: ignore
for case in case_tester.test_menu: for case in case_tester.test_menu:
if case.attributes.get('test_env', 'generic_multi_device') == 'generic_multi_device': if case.attributes.get('test_env', 'generic_multi_device') == 'generic_multi_device':

View File

@@ -0,0 +1,2 @@
# don't delete.
# used for CI to compile a default config when 'sdkconfig.ci.xxxx' is exist

View File

@@ -0,0 +1,7 @@
CONFIG_COMPILER_DUMP_RTL_FILES=y
CONFIG_SPI_MASTER_ISR_IN_IRAM=n
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y
CONFIG_COMPILER_OPTIMIZATION_NONE=y
# silent the error check, as the error string are stored in rodata, causing RTL check failure
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y

View File

@@ -22,6 +22,7 @@ entries:
rtc_wdt (noflash_text) rtc_wdt (noflash_text)
if PERIPH_CTRL_FUNC_IN_IRAM = y: if PERIPH_CTRL_FUNC_IN_IRAM = y:
periph_ctrl: periph_module_reset (noflash) periph_ctrl: periph_module_reset (noflash)
if PERIPH_CTRL_FUNC_IN_IRAM = y && ESP32_WIFI_ENABLED = y:
periph_ctrl: wifi_module_enable (noflash) periph_ctrl: wifi_module_enable (noflash)
periph_ctrl: wifi_module_disable (noflash) periph_ctrl: wifi_module_disable (noflash)
if GDMA_CTRL_FUNC_IN_IRAM = y: if GDMA_CTRL_FUNC_IN_IRAM = y:

View File

@@ -625,10 +625,11 @@ static inline bool gpio_ll_is_digital_io_hold(gpio_dev_t *hw, uint32_t gpio_num)
* @param gpio_num GPIO number of the pad. * @param gpio_num GPIO number of the pad.
* @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``. * @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``.
*/ */
__attribute__((always_inline))
static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx) static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx)
{ {
hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0; hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0;
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]); PIN_INPUT_ENABLE(DR_REG_IO_MUX_BASE + GPIO_PIN_MUX_REG_OFFSET[gpio]);
} }
/** /**

View File

@@ -441,10 +441,11 @@ static inline bool gpio_ll_is_digital_io_hold(gpio_dev_t *hw, uint32_t gpio_num)
* @param gpio_num GPIO number of the pad. * @param gpio_num GPIO number of the pad.
* @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``. * @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``.
*/ */
__attribute__((always_inline))
static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx) static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx)
{ {
hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0; hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0;
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]); PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio * 4));
} }
/** /**

View File

@@ -453,10 +453,11 @@ static inline bool gpio_ll_is_digital_io_hold(gpio_dev_t *hw, uint32_t gpio_num)
* @param gpio_num GPIO number of the pad. * @param gpio_num GPIO number of the pad.
* @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``. * @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``.
*/ */
__attribute__((always_inline))
static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx) static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx)
{ {
hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0; hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0;
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]); PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio * 4));
} }
/** /**

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -402,6 +402,7 @@ static inline void gpio_ll_hold_dis(gpio_dev_t *hw, uint32_t gpio_num)
* @param gpio_num GPIO number of the pad. * @param gpio_num GPIO number of the pad.
* @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``. * @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``.
*/ */
__attribute__((always_inline))
static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx) static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx)
{ {
hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0; hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0;

View File

@@ -424,10 +424,11 @@ static inline void gpio_ll_hold_dis(gpio_dev_t *hw, uint32_t gpio_num)
* @param gpio_num GPIO number of the pad. * @param gpio_num GPIO number of the pad.
* @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``. * @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``.
*/ */
__attribute__((always_inline))
static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx) static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx)
{ {
hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0; hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0;
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]); PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio * 4));
} }
/** /**

View File

@@ -400,10 +400,11 @@ static inline void gpio_ll_hold_dis(gpio_dev_t *hw, uint32_t gpio_num)
* @param gpio_num GPIO number of the pad. * @param gpio_num GPIO number of the pad.
* @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``. * @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``.
*/ */
__attribute__((always_inline))
static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx) static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx)
{ {
hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0; hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0;
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]); PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio * 4));
} }
/** /**

View File

@@ -456,10 +456,11 @@ static inline bool gpio_ll_is_digital_io_hold(gpio_dev_t *hw, uint32_t gpio_num)
* @param gpio_num GPIO number of the pad. * @param gpio_num GPIO number of the pad.
* @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``. * @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``.
*/ */
__attribute__((always_inline))
static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx) static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx)
{ {
hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0; hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0;
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]); PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio * 4));
} }
/** /**

View File

@@ -472,10 +472,11 @@ static inline bool gpio_ll_is_digital_io_hold(gpio_dev_t *hw, uint32_t gpio_num)
* @param gpio_num GPIO number of the pad. * @param gpio_num GPIO number of the pad.
* @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``. * @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``.
*/ */
__attribute__((always_inline))
static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx) static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx)
{ {
hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0; hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0;
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]); PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio * 4));
} }
/** /**