diff --git a/components/driver/include/esp_private/spi_slave_internal.h b/components/driver/include/esp_private/spi_slave_internal.h index 3b5d270155..abb62e5f69 100644 --- a/components/driver/include/esp_private/spi_slave_internal.h +++ b/components/driver/include/esp_private/spi_slave_internal.h @@ -40,6 +40,20 @@ extern "C" { esp_err_t spi_slave_queue_reset(spi_host_device_t host); +/** + * @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 * diff --git a/components/driver/spi_slave.c b/components/driver/spi_slave.c index dfcaa66c2b..bfe9c227a1 100644 --- a/components/driver/spi_slave.c +++ b/components/driver/spi_slave.c @@ -319,6 +319,24 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_queue_reset(spi_host_device_t host) 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) { BaseType_t r; diff --git a/components/driver/test_apps/spi/slave/main/test_spi_slave.c b/components/driver/test_apps/spi/slave/main/test_spi_slave.c index 2d092a2026..0b9ab3293b 100644 --- a/components/driver/test_apps/spi/slave/main/test_spi_slave.c +++ b/components/driver/test_apps/spi/slave/main/test_spi_slave.c @@ -385,13 +385,13 @@ static void unaligned_test_slave(void) 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) #if CONFIG_SPI_SLAVE_ISR_IN_IRAM #define TEST_IRAM_TRANS_NUM 8 -#define TEST_TRANS_LEN 64 +#define TEST_TRANS_LEN 120 #define TEST_BUFFER_SZ (TEST_IRAM_TRANS_NUM*TEST_TRANS_LEN) static void test_slave_iram_master_normal(void){ @@ -424,9 +424,10 @@ static void test_slave_iram_master_normal(void){ 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("master rx", trans_cfg.rx_buffer, TEST_TRANS_LEN); - // ESP_LOG_BUFFER_HEX("master exp", trans_cfg.user, 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); } @@ -442,8 +443,7 @@ static IRAM_ATTR void ESP_LOG_BUFFER_HEX_ISR(const char *tag, const uint8_t *buf esp_rom_printf(DRAM_STR("%s: "), tag); for(uint16_t i=0; i 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)){ + 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