Merge branch 'feature/spi_isr_pin_to_core' into 'master'

spi: add feature to assign core_id of spi isr registered

Closes IDF-6371

See merge request espressif/esp-idf!21597
This commit is contained in:
Wan Lei
2023-01-31 15:57:33 +08:00
8 changed files with 211 additions and 12 deletions
@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
///< Selecting the ISR to be registered on which core
typedef enum {
INTR_CPU_ID_AUTO, ///< Register intr ISR to core automatically select by FreeRTOS.
INTR_CPU_ID_0, ///< Register intr ISR to core 0.
INTR_CPU_ID_1, ///< Register intr ISR to core 1.
} intr_cpu_id_t;
#define INTR_CPU_CONVERT_ID(cpu_id) ((cpu_id) - 1)
#ifdef __cplusplus
}
#endif
@@ -10,6 +10,8 @@
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_ipc.h"
#include "intr_types.h"
#include "hal/spi_types.h"
#ifdef __cplusplus
@@ -115,6 +117,7 @@ typedef struct {
int data7_io_num; ///< GPIO pin for spi data7 signal in octal mode, or -1 if not used.
int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4092 if 0 when DMA enabled, or to `SOC_SPI_MAXIMUM_BUFFER_SIZE` if DMA is disabled.
uint32_t flags; ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.
intr_cpu_id_t isr_cpu_id; ///< Select cpu core to register SPI ISR.
int intr_flags; /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see
* ``esp_intr_alloc.h``. Note that the EDGE, INTRDISABLED attribute are ignored
* by the driver. Note that if ESP_INTR_FLAG_IRAM is set, ALL the callbacks of
+29 -4
View File
@@ -115,6 +115,7 @@ We have two bits to control the interrupt:
#include "driver/spi_master.h"
#include "clk_tree.h"
#include "esp_log.h"
#include "esp_ipc.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "soc/soc_memory_layout.h"
@@ -191,6 +192,20 @@ static inline bool is_valid_host(spi_host_device_t host)
#endif
}
#if (SOC_CPU_CORES_NUM > 1) && (!CONFIG_FREERTOS_UNICORE)
typedef struct {
spi_host_t *spi_host;
esp_err_t *err;
} spi_ipc_param_t;
static void ipc_isr_reg_to_core(void *args)
{
spi_host_t *host = ((spi_ipc_param_t *)args)->spi_host;
const spi_bus_attr_t* bus_attr = host->bus_attr;
*((spi_ipc_param_t *)args)->err = esp_intr_alloc(spicommon_irqsource_for_host(host->id), bus_attr->bus_cfg.intr_flags | ESP_INTR_FLAG_INTRDISABLED, spi_intr, host, &host->intr);
}
#endif
// Should be called before any devices are actually registered or used.
// Currently automatically called after `spi_bus_initialize()` and when first device is registered.
static esp_err_t spi_master_init_driver(spi_host_device_t host_id)
@@ -215,11 +230,21 @@ static esp_err_t spi_master_init_driver(spi_host_device_t host_id)
.bus_attr = bus_attr,
};
// interrupts are not allowed on SPI1 bus
if (host_id != SPI1_HOST) {
// interrupts are not allowed on SPI1 bus
err = esp_intr_alloc(spicommon_irqsource_for_host(host_id),
bus_attr->bus_cfg.intr_flags | ESP_INTR_FLAG_INTRDISABLED,
spi_intr, host, &host->intr);
#if (SOC_CPU_CORES_NUM > 1) && (!CONFIG_FREERTOS_UNICORE)
if(bus_attr->bus_cfg.isr_cpu_id > INTR_CPU_ID_AUTO) {
SPI_CHECK(bus_attr->bus_cfg.isr_cpu_id <= INTR_CPU_ID_1, "invalid core id", ESP_ERR_INVALID_ARG);
spi_ipc_param_t ipc_arg = {
.spi_host = host,
.err = &err,
};
esp_ipc_call_blocking(INTR_CPU_CONVERT_ID(bus_attr->bus_cfg.isr_cpu_id), ipc_isr_reg_to_core, (void *) &ipc_arg);
} else
#endif
{
err = esp_intr_alloc(spicommon_irqsource_for_host(host_id), bus_attr->bus_cfg.intr_flags | ESP_INTR_FLAG_INTRDISABLED, spi_intr, host, &host->intr);
}
if (err != ESP_OK) {
goto cleanup;
}
+35 -4
View File
@@ -55,6 +55,7 @@ typedef struct {
spi_slave_hal_context_t hal;
spi_slave_transaction_t *cur_trans;
uint32_t flags;
uint32_t intr_flags;
int max_transfer_sz;
QueueHandle_t trans_queue;
QueueHandle_t ret_queue;
@@ -106,6 +107,23 @@ static inline void SPI_SLAVE_ISR_ATTR restore_cs(spi_slave_t *host)
}
}
#if (SOC_CPU_CORES_NUM > 1) && (!CONFIG_FREERTOS_UNICORE)
typedef struct {
spi_slave_t *host;
esp_err_t *err;
} spi_ipc_param_t;
static void ipc_isr_reg_to_core(void *args)
{
spi_slave_t *host = ((spi_ipc_param_t *)args)->host;
int flags = host->intr_flags | ESP_INTR_FLAG_INTRDISABLED;
#ifdef CONFIG_SPI_SLAVE_ISR_IN_IRAM
flags |= ESP_INTR_FLAG_IRAM;
#endif
*((spi_ipc_param_t *)args)->err = esp_intr_alloc(spicommon_irqsource_for_host(host->id), flags, spi_intr, (void *)host, &host->intr);
}
#endif
esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, spi_dma_chan_t dma_chan)
{
bool spi_chan_claimed;
@@ -205,11 +223,24 @@ 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;
#ifdef CONFIG_SPI_SLAVE_ISR_IN_IRAM
flags |= ESP_INTR_FLAG_IRAM;
#if (SOC_CPU_CORES_NUM > 1) && (!CONFIG_FREERTOS_UNICORE)
if(bus_config->isr_cpu_id > INTR_CPU_ID_AUTO) {
spihost[host]->intr_flags = bus_config->intr_flags;
SPI_CHECK(bus_config->isr_cpu_id <= INTR_CPU_ID_1, "invalid core id", ESP_ERR_INVALID_ARG);
spi_ipc_param_t ipc_args = {
.host = spihost[host],
.err = &err,
};
esp_ipc_call_blocking(INTR_CPU_CONVERT_ID(bus_config->isr_cpu_id), ipc_isr_reg_to_core, (void *)&ipc_args);
} else
#endif
err = esp_intr_alloc(spicommon_irqsource_for_host(host), flags, spi_intr, (void *)spihost[host], &spihost[host]->intr);
{
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);
}
if (err != ESP_OK) {
ret = err;
goto cleanup;
@@ -1560,3 +1560,62 @@ void test_add_device_slave(void)
}
TEST_CASE_MULTIPLE_DEVICES("SPI_Master:Test multiple devices", "[spi_ms][test_env=generic_multi_device]", test_add_device_master, test_add_device_slave);
#if (SOC_CPU_CORES_NUM > 1) && (!CONFIG_FREERTOS_UNICORE)
#define TEST_ISR_CNT 100
static void test_master_isr_core_post_trans_cbk(spi_transaction_t *curr_trans){
*((int *)curr_trans->user) += esp_cpu_get_core_id();
}
TEST_CASE("test_master_isr_pin_to_core","[spi]")
{
spi_device_handle_t dev0;
uint32_t master_send;
uint32_t master_recive;
uint32_t master_expect;
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
devcfg.post_cb = test_master_isr_core_post_trans_cbk;
spi_transaction_t trans_cfg = {
.tx_buffer = &master_send,
.rx_buffer = &master_recive,
.user = & master_expect,
.length = sizeof(uint32_t) * 8,
};
master_expect = 0;
for (int i = 0; i < TEST_ISR_CNT; i++) {
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &dev0));
TEST_ESP_OK(spi_device_transmit(dev0, &trans_cfg));
TEST_ESP_OK(spi_bus_remove_device(dev0));
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST));
}
printf("Test Master ISR Not Assign: %d : %ld\n", TEST_ISR_CNT, master_expect);
// by default the esp_intr_alloc is called on ESP_MAIN_TASK_AFFINITY_CPU0 now
TEST_ASSERT_EQUAL_UINT32(0, master_expect);
//-------------------------------------CPU1---------------------------------------
buscfg.isr_cpu_id = INTR_CPU_ID_1;
master_expect = 0;
for (int i = 0; i < TEST_ISR_CNT; i++) {
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &dev0));
TEST_ESP_OK(spi_device_transmit(dev0, &trans_cfg));
TEST_ESP_OK(spi_bus_remove_device(dev0));
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST));
}
printf("Test Master ISR Assign CPU1: %d : %ld\n", TEST_ISR_CNT, master_expect);
TEST_ASSERT_EQUAL_UINT32(TEST_ISR_CNT, master_expect);
}
#endif
@@ -12,6 +12,7 @@
#include "unity.h"
#include "test_utils.h"
#include "test_spi_utils.h"
#include "hal/spi_slave_hal.h"
#include "driver/spi_master.h"
#include "driver/spi_slave.h"
#include "driver/gpio.h"
@@ -688,6 +689,62 @@ static IRAM_ATTR void spi_queue_reset_in_isr(void)
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
#if (SOC_CPU_CORES_NUM > 1) && (!CONFIG_FREERTOS_UNICORE)
#define TEST_ISR_CNT 100
static void test_slave_isr_core_setup_cbk(spi_slave_transaction_t *curr_trans){
*((int *)curr_trans->user) += esp_cpu_get_core_id();
}
TEST_CASE("test_slave_isr_pin_to_core","[spi]")
{
uint32_t slave_send;
uint32_t slave_recive;
uint32_t slave_expect;
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
spi_slave_interface_config_t slvcfg = SPI_SLAVE_TEST_DEFAULT_CONFIG();
slvcfg.post_setup_cb = test_slave_isr_core_setup_cbk;
spi_slave_transaction_t trans_cfg = {
.tx_buffer = &slave_send,
.rx_buffer = &slave_recive,
.user = &slave_expect,
.length = sizeof(uint32_t) * 8,
};
slave_expect = 0;
for (int i = 0; i < TEST_ISR_CNT; i++) {
TEST_ESP_OK(spi_slave_initialize(TEST_SPI_HOST, &buscfg, &slvcfg, SPI_DMA_CH_AUTO));
TEST_ESP_OK(spi_slave_queue_trans(TEST_SPI_HOST, &trans_cfg, portMAX_DELAY));
TEST_ESP_OK(spi_slave_free(TEST_SPI_HOST));
}
printf("Test Slave ISR Not Assign: %d : %ld\n", TEST_ISR_CNT, slave_expect);
// by default the esp_intr_alloc is called on ESP_MAIN_TASK_AFFINITY_CPU0 now
TEST_ASSERT_EQUAL_UINT32(0, slave_expect);
//-------------------------------------CPU1---------------------------------------
buscfg.isr_cpu_id = INTR_CPU_ID_1;
slave_expect = 0;
for (int i = 0; i < TEST_ISR_CNT; i++) {
TEST_ESP_OK(spi_slave_initialize(TEST_SPI_HOST, &buscfg, &slvcfg, SPI_DMA_CH_AUTO));
TEST_ESP_OK(spi_slave_queue_trans(TEST_SPI_HOST, &trans_cfg, portMAX_DELAY));
// This two delay used for hardware to activate a interrupt after invoke
vTaskDelay(1);
// to invoke a trans_done intr for spi slave without a master
spi_ll_set_int_stat(SPI_LL_GET_HW(TEST_SPI_HOST));
vTaskDelay(1);
TEST_ESP_OK(spi_slave_free(TEST_SPI_HOST));
}
printf("Test Slave ISR Assign CPU1: %d : %ld\n", TEST_ISR_CNT, slave_expect);
TEST_ASSERT_EQUAL_UINT32(TEST_ISR_CNT, slave_expect);
}
#endif