Merge branch 'feature/esp32p4_hp_spi_slave_support' into 'master'

Feature/esp32p4 hp spi slave support

Closes IDF-7503

See merge request espressif/esp-idf!25700
pull/12525/head
Wan Lei 2023-10-31 23:31:24 +08:00
commit 10401d95d0
23 zmienionych plików z 348 dodań i 244 usunięć

Wyświetl plik

@ -13,6 +13,7 @@
#include "freertos/FreeRTOS.h"
#include "hal/spi_types.h"
#include "hal/dma_types.h"
#include "soc/gdma_channel.h"
#include "esp_pm.h"
#if SOC_GDMA_SUPPORTED
#include "esp_private/gdma.h"
@ -46,19 +47,14 @@ extern "C"
#define BUS_LOCK_DEBUG_EXECUTE_CHECK(x)
#endif
#if !defined(SOC_GDMA_TRIG_PERIPH_SPI2_BUS)
#define DMA_DESC_MEM_ALIGN_SIZE 4
typedef dma_descriptor_align4_t spi_dma_desc_t;
#else
#if defined(SOC_GDMA_BUS_AXI) && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI)
#define DMA_DESC_MEM_ALIGN_SIZE 8
#define SPI_GDMA_NEW_CHANNEL gdma_new_axi_channel
typedef dma_descriptor_align8_t spi_dma_desc_t;
#elif defined(SOC_GDMA_BUS_AHB) && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB)
#if SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB
#define DMA_DESC_MEM_ALIGN_SIZE 4
#define SPI_GDMA_NEW_CHANNEL gdma_new_ahb_channel
typedef dma_descriptor_align4_t spi_dma_desc_t;
#endif
#else
#define DMA_DESC_MEM_ALIGN_SIZE 8
#define SPI_GDMA_NEW_CHANNEL gdma_new_axi_channel
typedef dma_descriptor_align8_t spi_dma_desc_t;
#endif
struct spi_bus_lock_t;

Wyświetl plik

@ -887,15 +887,15 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_host_t *host, spi_trans
uint32_t tx_byte_len = (trans_desc->length + 7) / 8;
uint32_t rx_byte_len = (trans_desc->rxlength + 7) / 8;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
bool tx_un_align = ((((uint32_t)send_ptr) | tx_byte_len) & (alignment - 1));
bool rx_un_align = ((((uint32_t)rcv_ptr) | rx_byte_len) & (alignment - 1));
bool tx_unaligned = ((((uint32_t)send_ptr) | tx_byte_len) & (alignment - 1));
bool rx_unaligned = ((((uint32_t)rcv_ptr) | rx_byte_len) & (alignment - 1));
#else
bool tx_un_align = false; //tx don't need align on addr or length, for other chips
bool rx_un_align = (((uint32_t)rcv_ptr) & (alignment - 1));
bool tx_unaligned = false; //tx don't need align on addr or length, for other chips
bool rx_unaligned = (((uint32_t)rcv_ptr) & (alignment - 1));
#endif
if (send_ptr && bus_attr->dma_enabled) {
if ((!esp_ptr_dma_capable(send_ptr) || tx_un_align )) {
if ((!esp_ptr_dma_capable(send_ptr) || tx_unaligned )) {
ESP_RETURN_ON_FALSE(!(trans_desc->flags & SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL), ESP_ERR_INVALID_ARG, SPI_TAG, "Set flag SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL but TX buffer addr&len not align to %d, or not dma_capable", alignment);
//if txbuf in the desc not DMA-capable, or not bytes aligned to alignment, malloc a new one
ESP_EARLY_LOGD(SPI_TAG, "Allocate TX buffer for DMA" );
@ -914,7 +914,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_host_t *host, spi_trans
#endif
}
if (rcv_ptr && bus_attr->dma_enabled && (!esp_ptr_dma_capable(rcv_ptr) || rx_un_align )) {
if (rcv_ptr && bus_attr->dma_enabled && (!esp_ptr_dma_capable(rcv_ptr) || rx_unaligned )) {
ESP_RETURN_ON_FALSE(!(trans_desc->flags & SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL), ESP_ERR_INVALID_ARG, SPI_TAG, "Set flag SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL but RX buffer addr&len not align to %d, or not dma_capable", alignment);
//if rxbuf in the desc not DMA-capable, or not aligned to alignment, malloc a new one
ESP_EARLY_LOGD(SPI_TAG, "Allocate RX buffer for DMA" );

Wyświetl plik

@ -12,6 +12,7 @@
#include "esp_log.h"
#include "esp_err.h"
#include "esp_pm.h"
#include "esp_cache.h"
#include "esp_heap_caps.h"
#include "esp_rom_sys.h"
#include "soc/lldesc.h"
@ -29,7 +30,7 @@
#include "hal/spi_slave_hal.h"
#include "esp_private/spi_slave_internal.h"
#include "esp_private/spi_common_internal.h"
#include "esp_private/esp_cache_private.h"
static const char *SPI_TAG = "spi_slave";
@ -48,13 +49,20 @@ static const char *SPI_TAG = "spi_slave";
#define SPI_SLAVE_ATTR
#endif
/// struct to hold private transaction data (like tx and rx buffer for DMA).
typedef struct {
spi_slave_transaction_t *trans; //original trans
void *tx_buffer; //actually tx buffer (re-malloced if needed)
void *rx_buffer; //actually rx buffer (re-malloced if needed)
} spi_slave_trans_priv_t;
typedef struct {
int id;
spi_bus_config_t bus_config;
spi_slave_interface_config_t cfg;
intr_handle_t intr;
spi_slave_hal_context_t hal;
spi_slave_transaction_t *cur_trans;
spi_slave_trans_priv_t cur_trans;
uint32_t flags;
uint32_t intr_flags;
int max_transfer_sz;
@ -63,6 +71,7 @@ typedef struct {
bool dma_enabled;
bool cs_iomux;
uint8_t cs_in_signal;
uint16_t internal_mem_align_size;
uint32_t tx_dma_chan;
uint32_t rx_dma_chan;
#ifdef CONFIG_PM_ENABLE
@ -159,17 +168,37 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
memcpy(&spihost[host]->cfg, slave_config, sizeof(spi_slave_interface_config_t));
memcpy(&spihost[host]->bus_config, bus_config, sizeof(spi_bus_config_t));
spihost[host]->id = host;
spi_slave_hal_context_t *hal = &spihost[host]->hal;
bool use_dma = (dma_chan != SPI_DMA_DISABLED);
spihost[host]->dma_enabled = use_dma;
if (use_dma) {
#if CONFIG_IDF_TARGET_ESP32P4
abort(); //will supported in IDF-7503
#endif
spihost[host]->dma_enabled = (dma_chan != SPI_DMA_DISABLED);
if (spihost[host]->dma_enabled) {
ret = spicommon_dma_chan_alloc(host, dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan);
if (ret != ESP_OK) {
goto cleanup;
}
spihost[host]->tx_dma_chan = actual_tx_dma_chan;
spihost[host]->rx_dma_chan = actual_rx_dma_chan;
//See how many dma descriptors we need and allocate them
int dma_desc_ct = (bus_config->max_transfer_sz + SPI_MAX_DMA_LEN - 1) / SPI_MAX_DMA_LEN;
if (dma_desc_ct == 0) dma_desc_ct = 1; //default to 4k when max is not given
spihost[host]->max_transfer_sz = dma_desc_ct * SPI_MAX_DMA_LEN;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_get_alignment(ESP_CACHE_MALLOC_FLAG_DMA, (size_t *)&spihost[host]->internal_mem_align_size);
#else
spihost[host]->internal_mem_align_size = 4;
#endif
hal->dmadesc_tx = heap_caps_aligned_alloc(DMA_DESC_MEM_ALIGN_SIZE, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA);
hal->dmadesc_rx = heap_caps_aligned_alloc(DMA_DESC_MEM_ALIGN_SIZE, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA);
if (!hal->dmadesc_tx || !hal->dmadesc_rx) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
hal->dmadesc_n = dma_desc_ct;
} else {
//We're limited to non-DMA transfers: the SPI work registers can hold 64 bytes at most.
spihost[host]->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE;
}
err = spicommon_bus_initialize_io(host, bus_config, SPICOMMON_BUSFLAG_SLAVE|bus_config->flags, &spihost[host]->flags);
@ -185,20 +214,8 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
}
// The slave DMA suffers from unexpected transactions. Forbid reading if DMA is enabled by disabling the CS line.
if (use_dma) freeze_cs(spihost[host]);
if (spihost[host]->dma_enabled) freeze_cs(spihost[host]);
int dma_desc_ct = 0;
spihost[host]->tx_dma_chan = actual_tx_dma_chan;
spihost[host]->rx_dma_chan = actual_rx_dma_chan;
if (use_dma) {
//See how many dma descriptors we need and allocate them
dma_desc_ct = (bus_config->max_transfer_sz + SPI_MAX_DMA_LEN - 1) / SPI_MAX_DMA_LEN;
if (dma_desc_ct == 0) dma_desc_ct = 1; //default to 4k when max is not given
spihost[host]->max_transfer_sz = dma_desc_ct * SPI_MAX_DMA_LEN;
} else {
//We're limited to non-DMA transfers: the SPI work registers can hold 64 bytes at most.
spihost[host]->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE;
}
#ifdef CONFIG_PM_ENABLE
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave",
&spihost[host]->pm_lock);
@ -211,13 +228,13 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
#endif //CONFIG_PM_ENABLE
//Create queues
spihost[host]->trans_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_transaction_t *));
spihost[host]->trans_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_trans_priv_t));
if (!spihost[host]->trans_queue) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
if(!(slave_config->flags & SPI_SLAVE_NO_RETURN_RESULT)) {
spihost[host]->ret_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_transaction_t *));
spihost[host]->ret_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_trans_priv_t));
if (!spihost[host]->ret_queue) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
@ -243,7 +260,6 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
goto cleanup;
}
spi_slave_hal_context_t *hal = &spihost[host]->hal;
//assign the SPI, RX DMA and TX DMA peripheral registers beginning address
spi_slave_hal_config_t hal_config = {
.host_id = host,
@ -252,32 +268,20 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
};
spi_slave_hal_init(hal, &hal_config);
if (dma_desc_ct) {
hal->dmadesc_tx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA);
hal->dmadesc_rx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA);
if (!hal->dmadesc_tx || !hal->dmadesc_rx) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
}
hal->dmadesc_n = dma_desc_ct;
hal->rx_lsbfirst = (slave_config->flags & SPI_SLAVE_RXBIT_LSBFIRST) ? 1 : 0;
hal->tx_lsbfirst = (slave_config->flags & SPI_SLAVE_TXBIT_LSBFIRST) ? 1 : 0;
hal->mode = slave_config->mode;
hal->use_dma = use_dma;
hal->use_dma = spihost[host]->dma_enabled;
hal->tx_dma_chan = actual_tx_dma_chan;
hal->rx_dma_chan = actual_rx_dma_chan;
spi_slave_hal_setup_device(hal);
return ESP_OK;
cleanup:
if (spihost[host]) {
if (spihost[host]->trans_queue) vQueueDelete(spihost[host]->trans_queue);
if (spihost[host]->ret_queue) vQueueDelete(spihost[host]->ret_queue);
free(spihost[host]->hal.dmadesc_tx);
free(spihost[host]->hal.dmadesc_rx);
#ifdef CONFIG_PM_ENABLE
if (spihost[host]->pm_lock) {
esp_pm_lock_release(spihost[host]->pm_lock);
@ -288,6 +292,8 @@ cleanup:
spi_slave_hal_deinit(&spihost[host]->hal);
if (spihost[host]->dma_enabled) {
spicommon_dma_chan_free(host);
free(spihost[host]->hal.dmadesc_tx);
free(spihost[host]->hal.dmadesc_rx);
}
free(spihost[host]);
@ -305,10 +311,10 @@ esp_err_t spi_slave_free(spi_host_device_t host)
if (spihost[host]->ret_queue) vQueueDelete(spihost[host]->ret_queue);
if (spihost[host]->dma_enabled) {
spicommon_dma_chan_free(host);
free(spihost[host]->hal.dmadesc_tx);
free(spihost[host]->hal.dmadesc_rx);
}
spicommon_bus_free_io_cfg(&spihost[host]->bus_config);
free(spihost[host]->hal.dmadesc_tx);
free(spihost[host]->hal.dmadesc_rx);
esp_intr_free(spihost[host]->intr);
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_release(spihost[host]->pm_lock);
@ -320,6 +326,89 @@ esp_err_t spi_slave_free(spi_host_device_t host)
return ESP_OK;
}
static void SPI_SLAVE_ISR_ATTR spi_slave_uninstall_priv_trans(spi_host_device_t host, spi_slave_trans_priv_t *priv_trans)
{
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
spi_slave_transaction_t *trans = (spi_slave_transaction_t *)priv_trans->trans;
if (spihost[host]->dma_enabled) {
if (trans->tx_buffer && (trans->tx_buffer != priv_trans->tx_buffer)) {
free(priv_trans->tx_buffer);
}
if (trans->rx_buffer && (trans->rx_buffer != priv_trans->rx_buffer)) {
memcpy(trans->rx_buffer, priv_trans->rx_buffer, (trans->length + 7) / 8);
free(priv_trans->rx_buffer);
}
}
#endif //SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
}
static esp_err_t SPI_SLAVE_ISR_ATTR spi_slave_setup_priv_trans(spi_host_device_t host, spi_slave_trans_priv_t *priv_trans)
{
spi_slave_transaction_t *trans = (spi_slave_transaction_t *)priv_trans->trans;
priv_trans->tx_buffer = (void *)trans->tx_buffer;
priv_trans->rx_buffer = trans->rx_buffer;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
uint16_t alignment = spihost[host]->internal_mem_align_size;
uint32_t buffer_byte_len = (trans->length + 7) / 8;
if (spihost[host]->dma_enabled && trans->tx_buffer) {
if ((!esp_ptr_dma_capable( trans->tx_buffer ) || ((((uint32_t)trans->tx_buffer) | buffer_byte_len) & (alignment - 1)))) {
ESP_RETURN_ON_FALSE_ISR(trans->flags & SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO, ESP_ERR_INVALID_ARG, SPI_TAG, "TX buffer addr&len not align to %d, or not dma_capable", alignment);
//if txbuf in the desc not DMA-capable, or not align to "alignment", malloc a new one
ESP_EARLY_LOGD(SPI_TAG, "Allocate TX buffer for DMA" );
buffer_byte_len = (buffer_byte_len + alignment - 1) & (~(alignment - 1)); // up align to "alignment"
uint32_t *temp = heap_caps_aligned_alloc(alignment, buffer_byte_len, MALLOC_CAP_DMA);
if (temp == NULL) {
return ESP_ERR_NO_MEM;
}
memcpy(temp, trans->tx_buffer, (trans->length + 7) / 8);
priv_trans->tx_buffer = temp;
}
esp_err_t ret = esp_cache_msync((void *)priv_trans->tx_buffer, buffer_byte_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
ESP_RETURN_ON_FALSE_ISR(ESP_OK == ret, ESP_ERR_INVALID_STATE, SPI_TAG, "mem sync c2m(writeback) fail");
}
if (spihost[host]->dma_enabled && trans->rx_buffer && (!esp_ptr_dma_capable(trans->rx_buffer) || ((((uint32_t)trans->rx_buffer) | (trans->length + 7) / 8) & (alignment - 1)))) {
ESP_RETURN_ON_FALSE_ISR(trans->flags & SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO, ESP_ERR_INVALID_ARG, SPI_TAG, "RX buffer addr&len not align to %d, or not dma_capable", alignment);
//if rxbuf in the desc not DMA-capable, or not align to "alignment", malloc a new one
ESP_EARLY_LOGD(SPI_TAG, "Allocate RX buffer for DMA" );
buffer_byte_len = (buffer_byte_len + alignment - 1) & (~(alignment - 1)); // up align to "alignment"
priv_trans->rx_buffer = heap_caps_aligned_alloc(alignment, buffer_byte_len, MALLOC_CAP_DMA);
if (priv_trans->rx_buffer == NULL) {
free (priv_trans->tx_buffer);
return ESP_ERR_NO_MEM;
}
}
#endif //SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
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;
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host]->dma_enabled == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
"txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
SPI_CHECK(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)),
"rxdata not in DMA-capable memory or not WORD aligned", ESP_ERR_INVALID_ARG);
SPI_CHECK(trans_desc->length <= spihost[host]->max_transfer_sz * 8, "data transfer > host maximum", ESP_ERR_INVALID_ARG);
spi_slave_trans_priv_t priv_trans = {.trans = (spi_slave_transaction_t *)trans_desc};
SPI_CHECK(ESP_OK == spi_slave_setup_priv_trans(host, &priv_trans), "slave setup priv_trans failed", ESP_ERR_NO_MEM);
r = xQueueSend(spihost[host]->trans_queue, (void *)&priv_trans, ticks_to_wait);
if (!r) return ESP_ERR_TIMEOUT;
esp_intr_enable(spihost[host]->intr);
return ESP_OK;
}
/**
* @note
* This API is used to reset SPI Slave transaction queue. After calling this function:
@ -342,46 +431,13 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_queue_reset(spi_host_device_t host)
esp_intr_disable(spihost[host]->intr);
spi_ll_set_int_stat(spihost[host]->hal.hw);
spihost[host]->cur_trans = NULL;
xQueueReset(spihost[host]->trans_queue);
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();
spi_slave_trans_priv_t trans;
while( uxQueueMessagesWaiting(spihost[host]->trans_queue)) {
xQueueReceive(spihost[host]->trans_queue, &trans, 0);
spi_slave_uninstall_priv_trans(host, &trans);
}
spihost[host]->cur_trans.trans = NULL;
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;
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host]->dma_enabled == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
"txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
SPI_CHECK(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)),
"rxdata not in DMA-capable memory or not WORD aligned", ESP_ERR_INVALID_ARG);
SPI_CHECK(trans_desc->length <= spihost[host]->max_transfer_sz * 8, "data transfer > host maximum", ESP_ERR_INVALID_ARG);
r = xQueueSend(spihost[host]->trans_queue, (void *)&trans_desc, ticks_to_wait);
if (!r) return ESP_ERR_TIMEOUT;
esp_intr_enable(spihost[host]->intr);
return ESP_OK;
}
@ -391,15 +447,31 @@ esp_err_t SPI_SLAVE_ISR_ATTR spi_slave_queue_trans_isr(spi_host_device_t host, c
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");
if (spihost[host]->dma_enabled) {
uint16_t alignment = spihost[host]->internal_mem_align_size;
uint32_t buffer_byte_len = (trans_desc->length + 7) / 8;
r = xQueueSendFromISR(spihost[host]->trans_queue, (void *)&trans_desc, &do_yield);
ESP_RETURN_ON_FALSE_ISR(\
(trans_desc->tx_buffer && \
esp_ptr_dma_capable(trans_desc->tx_buffer) && \
((((uint32_t)trans_desc->tx_buffer) | buffer_byte_len) & (alignment - 1)) == 0), \
ESP_ERR_INVALID_ARG, SPI_TAG, "txdata addr & len not align to %d bytes or not dma_capable", alignment\
);
ESP_RETURN_ON_FALSE_ISR(\
(trans_desc->rx_buffer && \
esp_ptr_dma_capable(trans_desc->rx_buffer) && \
((((uint32_t)trans_desc->rx_buffer) | buffer_byte_len) & (alignment - 1)) == 0), \
ESP_ERR_INVALID_ARG, SPI_TAG, "rxdata addr & len not align to %d bytes or not dma_capable", alignment\
);
}
spi_slave_trans_priv_t priv_trans = {
.trans = (spi_slave_transaction_t *)trans_desc,
.tx_buffer = (void *)trans_desc->tx_buffer,
.rx_buffer = trans_desc->rx_buffer,
};
r = xQueueSendFromISR(spihost[host]->trans_queue, (void *)&priv_trans, &do_yield);
if (!r) {
return ESP_ERR_NO_MEM;
}
@ -409,6 +481,25 @@ esp_err_t SPI_SLAVE_ISR_ATTR spi_slave_queue_trans_isr(spi_host_device_t host, c
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_trans_priv_t trans;
BaseType_t do_yield = pdFALSE;
while( pdFALSE == xQueueIsQueueEmptyFromISR(spihost[host]->trans_queue)) {
xQueueReceiveFromISR(spihost[host]->trans_queue, &trans, &do_yield);
spi_slave_uninstall_priv_trans(host, &trans);
}
if (do_yield) {
portYIELD_FROM_ISR();
}
spihost[host]->cur_trans.trans = NULL;
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)
{
BaseType_t r;
@ -417,8 +508,12 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_get_trans_result(spi_host_device_t host, spi_
//if SPI_SLAVE_NO_RETURN_RESULT is set, ret_queue will always be empty
SPI_CHECK(!(spihost[host]->cfg.flags & SPI_SLAVE_NO_RETURN_RESULT), "API not Supported!", ESP_ERR_NOT_SUPPORTED);
r = xQueueReceive(spihost[host]->ret_queue, (void *)trans_desc, ticks_to_wait);
spi_slave_trans_priv_t priv_trans;
r = xQueueReceive(spihost[host]->ret_queue, (void *)&priv_trans, ticks_to_wait);
if (!r) return ESP_ERR_TIMEOUT;
spi_slave_uninstall_priv_trans(host, &priv_trans);
*trans_desc = priv_trans.trans;
return ESP_OK;
}
@ -451,19 +546,18 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
{
BaseType_t r;
BaseType_t do_yield = pdFALSE;
spi_slave_transaction_t *trans = NULL;
spi_slave_t *host = (spi_slave_t *)arg;
spi_slave_hal_context_t *hal = &host->hal;
assert(spi_slave_hal_usr_is_done(hal));
bool use_dma = host->dma_enabled;
if (host->cur_trans) {
if (host->cur_trans.trans) {
// When DMA is enabled, the slave rx dma suffers from unexpected transactions. Forbid reading until transaction ready.
if (use_dma) freeze_cs(host);
spi_slave_hal_store_result(hal);
host->cur_trans->trans_len = spi_slave_hal_get_rcv_bitlen(hal);
host->cur_trans.trans->trans_len = spi_slave_hal_get_rcv_bitlen(hal);
#if CONFIG_IDF_TARGET_ESP32
//This workaround is only for esp32
@ -473,12 +567,22 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
}
#endif //#if CONFIG_IDF_TARGET_ESP32
if (host->cfg.post_trans_cb) host->cfg.post_trans_cb(host->cur_trans);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE //invalidate here to let user access rx data in post_cb if possible
if (use_dma && host->cur_trans.rx_buffer) {
uint16_t alignment = host->internal_mem_align_size;
uint32_t buffer_byte_len = (host->cur_trans.trans->length + 7) / 8;
buffer_byte_len = (buffer_byte_len + alignment - 1) & (~(alignment - 1));
// invalidate priv_trans.buffer_to_rcv anyway, only user provide aligned buffer can rcv correct data in post_cb
esp_err_t ret = esp_cache_msync((void *)host->cur_trans.rx_buffer, buffer_byte_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
assert(ret == ESP_OK);
}
#endif
if (host->cfg.post_trans_cb) host->cfg.post_trans_cb(host->cur_trans.trans);
if(!(host->cfg.flags & SPI_SLAVE_NO_RETURN_RESULT)) {
xQueueSendFromISR(host->ret_queue, &host->cur_trans, &do_yield);
}
host->cur_trans = NULL;
host->cur_trans.trans = NULL;
}
#if CONFIG_IDF_TARGET_ESP32
@ -497,21 +601,22 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
//Disable interrupt before checking to avoid concurrency issue.
esp_intr_disable(host->intr);
spi_slave_trans_priv_t priv_trans;
//Grab next transaction
r = xQueueReceiveFromISR(host->trans_queue, &trans, &do_yield);
r = xQueueReceiveFromISR(host->trans_queue, &priv_trans, &do_yield);
if (r) {
// sanity check
assert(trans);
assert(priv_trans.trans);
//enable the interrupt again if there is packet to send
esp_intr_enable(host->intr);
//We have a transaction. Send it.
host->cur_trans = trans;
host->cur_trans = priv_trans;
hal->bitlen = trans->length;
hal->rx_buffer = trans->rx_buffer;
hal->tx_buffer = trans->tx_buffer;
hal->bitlen = priv_trans.trans->length;
hal->rx_buffer = priv_trans.rx_buffer;
hal->tx_buffer = priv_trans.tx_buffer;
#if CONFIG_IDF_TARGET_ESP32
if (use_dma) {
@ -530,7 +635,7 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
//Kick off transfer
spi_slave_hal_user_start(hal);
if (host->cfg.post_setup_cb) host->cfg.post_setup_cb(trans);
if (host->cfg.post_setup_cb) host->cfg.post_setup_cb(priv_trans.trans);
}
if (do_yield) portYIELD_FROM_ISR();
}

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2010-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -65,15 +65,19 @@ typedef struct {
*/
} spi_slave_interface_config_t;
#define SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO (1<<0) ///< Automatically re-malloc dma buffer if user buffer doesn't meet hardware alignment or dma_capable, this process may loss some memory and performance
/**
* This structure describes one SPI transaction
*/
struct spi_slave_transaction_t {
uint32_t flags; ///< Bitwise OR of SPI_SLAVE_TRANS_* flags
size_t length; ///< Total data length, in bits
size_t trans_len; ///< Transaction data length, in bits
const void *tx_buffer; ///< Pointer to transmit buffer, or NULL for no MOSI phase
void *rx_buffer; /**< Pointer to receive buffer, or NULL for no MISO phase.
* When the DMA is anabled, must start at WORD boundary (``rx_buffer%4==0``),
* When the DMA is enabled, must start at WORD boundary (``rx_buffer%4==0``),
* and has length of a multiple of 4 bytes.
*/
void *user; ///< User-defined variable. Can be used to store eg transaction ID.
@ -138,6 +142,8 @@ esp_err_t spi_slave_free(spi_host_device_t host);
* never time out.
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NO_MEM if set flag `SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO` but there is no free memory
* - ESP_ERR_INVALID_STATE if sync data between Cache and memory failed
* - ESP_OK on success
*/
esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait);

Wyświetl plik

@ -144,14 +144,11 @@ components/driver/test_apps/spi/param:
- if: SOC_GPSPI_SUPPORTED != 1
- if: IDF_TARGET in ["esp32p4"]
temporary: true
reason: target(s) is not supported yet # TODO: IDF-7503
reason: target(s) is not supported yet # TODO: IDF-7505
components/driver/test_apps/spi/slave:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
- if: IDF_TARGET in ["esp32p4"]
temporary: true
reason: target(s) is not supported yet # TODO: IDF-7503 slave support
components/driver/test_apps/spi/slave_hd:
disable:

Wyświetl plik

@ -1047,7 +1047,7 @@ TEST_CASE("SPI master variable dummy test", "[spi]")
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &dev_cfg, &spi));
spi_slave_interface_config_t slave_cfg = SPI_SLAVE_TEST_DEFAULT_CONFIG();
TEST_ESP_OK(spi_slave_initialize(TEST_SLAVE_HOST, &bus_cfg, &slave_cfg, 0));
TEST_ESP_OK(spi_slave_initialize(TEST_SLAVE_HOST, &bus_cfg, &slave_cfg, SPI_DMA_DISABLED));
spitest_gpio_output_sel(bus_cfg.mosi_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_out);
spitest_gpio_output_sel(bus_cfg.miso_io_num, FUNC_GPIO, spi_periph_signal[TEST_SLAVE_HOST].spiq_out);
@ -1069,7 +1069,6 @@ TEST_CASE("SPI master variable dummy test", "[spi]")
master_free_device_bus(spi);
}
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4) //IDF-7503 slave support
/**
* This test is to check when the first transaction of the HD master is to send data without receiving data via DMA,
* then if the master could receive data correctly.
@ -1113,6 +1112,7 @@ TEST_CASE("SPI master hd dma TX without RX test", "[spi]")
spi_slave_transaction_t slave_trans = {
.rx_buffer = slv_recv_buf,
.length = buf_size * 8,
.flags = SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
TEST_ESP_OK(spi_slave_queue_trans(TEST_SLAVE_HOST, &slave_trans, portMAX_DELAY));
@ -1137,6 +1137,7 @@ TEST_CASE("SPI master hd dma TX without RX test", "[spi]")
slave_trans = (spi_slave_transaction_t) {};
slave_trans.tx_buffer = slv_send_buf;
slave_trans.length = buf_size * 8;
slave_trans.flags |= SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO;
TEST_ESP_OK(spi_slave_queue_trans(TEST_SLAVE_HOST, &slave_trans, portMAX_DELAY));
vTaskDelay(50);
@ -1158,10 +1159,8 @@ TEST_CASE("SPI master hd dma TX without RX test", "[spi]")
spi_slave_free(TEST_SLAVE_HOST);
master_free_device_bus(spi);
}
#endif
#endif //#if (TEST_SPI_PERIPH_NUM >= 2)
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4) //IDF-7503 slave support
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32) //TODO: IDF-3494
#define FD_TEST_BUF_SIZE 32
#define TEST_NUM 4
@ -1337,7 +1336,6 @@ static void fd_slave(void)
TEST_CASE_MULTIPLE_DEVICES("SPI Master: FD, DMA, Master Single Direction Test", "[spi_ms][test_env=generic_multi_device]", fd_master, fd_slave);
#endif //#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32) //TODO: IDF-3494
#endif //p4 slave support
//NOTE: Explained in IDF-1445 | MR !14996
@ -1491,7 +1489,6 @@ TEST_CASE("spi_speed", "[spi]")
#endif // CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE
#endif // !(CONFIG_SPIRAM) || (CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL >= 16384)
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4) //IDF-7503 slave support
//****************************************spi master add device test************************************//
//add dummy devices first
#if CONFIG_IDF_TARGET_ESP32
@ -1576,7 +1573,7 @@ void test_add_device_slave(void)
.spics_io_num = CS_REAL_DEV,
.queue_size = 3,
};
TEST_ESP_OK(spi_slave_initialize(TEST_SPI_HOST, &bus_cfg, &slvcfg, SPI_DMA_CH_AUTO));
TEST_ESP_OK(spi_slave_initialize(TEST_SPI_HOST, &bus_cfg, &slvcfg, SPI_DMA_DISABLED));
spi_slave_transaction_t slave_trans = {};
slave_trans.length = sizeof(slave_sendbuf) * 8;
@ -1602,7 +1599,7 @@ void test_add_device_slave(void)
}
TEST_CASE_MULTIPLE_DEVICES("SPI_Master:Test multiple devices", "[spi_ms]", test_add_device_master, test_add_device_slave);
#endif //p4 slave support
#if (SOC_CPU_CORES_NUM > 1) && (!CONFIG_FREERTOS_UNICORE)
@ -1662,7 +1659,6 @@ TEST_CASE("test_master_isr_pin_to_core","[spi]")
}
#endif
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4) //IDF-7503 slave support
#if CONFIG_SPI_MASTER_IN_IRAM
#define TEST_MASTER_IRAM_TRANS_LEN 120
static IRAM_ATTR void test_master_iram_post_trans_cbk(spi_transaction_t *trans)
@ -1768,4 +1764,3 @@ static void test_iram_slave_normal(void)
TEST_CASE_MULTIPLE_DEVICES("SPI_Master:IRAM_safe", "[spi_ms]", test_master_iram, test_iram_slave_normal);
#endif
#endif //p4 slave support

Wyświetl plik

@ -1,2 +1,2 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |

Wyświetl plik

@ -10,23 +10,15 @@
#define TEST_MEMORY_LEAK_THRESHOLD (200)
static size_t before_free_8bit;
static size_t before_free_32bit;
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
unity_utils_record_free_mem();
}
void tearDown(void)
{
esp_reent_cleanup(); //clean up some of the newlib's lazy allocations
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
printf("\n");
unity_utils_check_leak(before_free_8bit, after_free_8bit, "8BIT", TEST_MEMORY_LEAK_THRESHOLD);
unity_utils_check_leak(before_free_32bit, after_free_32bit, "32BIT", TEST_MEMORY_LEAK_THRESHOLD);
unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD);
}
void app_main(void)

Wyświetl plik

@ -133,6 +133,7 @@ TEST_CASE("test fullduplex slave with only RX direction", "[spi]")
slave_t.length = 8 * 32;
slave_t.tx_buffer = NULL;
slave_t.rx_buffer = slave_rxbuf;
slave_t.flags |= SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO;
// Colorize RX buffer with known pattern
memset( slave_rxbuf, 0x66, sizeof(slave_rxbuf));
@ -179,6 +180,7 @@ TEST_CASE("test fullduplex slave with only TX direction", "[spi]")
slave_t.length = 8 * 32;
slave_t.tx_buffer = slave_txbuf;
slave_t.rx_buffer = NULL;
slave_t.flags |= SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO;
// Colorize RX buffer with known pattern
memset( master_rxbuf, 0x66, sizeof(master_rxbuf));
@ -226,6 +228,7 @@ TEST_CASE("test slave send unaligned", "[spi]")
slave_t.length = 8 * 32;
slave_t.tx_buffer = slave_txbuf + i;
slave_t.rx_buffer = slave_rxbuf;
slave_t.flags |= SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO;
// Colorize RX buffers with known pattern
memset( master_rxbuf, 0x66, sizeof(master_rxbuf));
@ -391,7 +394,7 @@ TEST_CASE_MULTIPLE_DEVICES("SPI_Slave_Unaligned_Test", "[spi_ms][timeout=120]",
#if CONFIG_SPI_SLAVE_ISR_IN_IRAM
#define TEST_IRAM_TRANS_NUM 8
#define TEST_TRANS_LEN 120
#define TEST_TRANS_LEN 64
#define TEST_BUFFER_SZ (TEST_IRAM_TRANS_NUM*TEST_TRANS_LEN)
static void test_slave_iram_master_normal(void)
@ -484,8 +487,8 @@ static IRAM_ATTR void test_slave_isr_iram(void)
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_send = heap_caps_aligned_alloc(64, TEST_BUFFER_SZ, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *slave_iram_recv = heap_caps_aligned_alloc(64, 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};
@ -522,7 +525,6 @@ static IRAM_ATTR void test_slave_isr_iram(void)
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;
@ -565,8 +567,8 @@ static IRAM_ATTR void spi_slave_trans_in_isr(void)
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_send = heap_caps_aligned_alloc(64, TEST_BUFFER_SZ, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *slave_isr_recv = heap_caps_aligned_alloc(64, 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 = {
@ -596,7 +598,6 @@ static IRAM_ATTR void spi_slave_trans_in_isr(void)
}
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)
@ -615,8 +616,6 @@ static IRAM_ATTR void test_queue_reset_in_isr_post_trans_cbk(spi_slave_transacti
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]);
@ -651,10 +650,12 @@ static IRAM_ATTR void spi_queue_reset_in_isr(void)
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_send = heap_caps_aligned_alloc(64, TEST_BUFFER_SZ, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *slave_isr_recv = heap_caps_aligned_alloc(64, TEST_BUFFER_SZ, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *dummy_data = heap_caps_aligned_alloc(64, 64*2, 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);
get_tx_buffer(1001, dummy_data, dummy_data + 64, 64);
spi_slave_transaction_t trans_cfg = {
.tx_buffer = slave_isr_send,
.rx_buffer = slave_isr_recv,
@ -664,10 +665,10 @@ static IRAM_ATTR void spi_queue_reset_in_isr(void)
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;
dummy_trans[i].tx_buffer = dummy_data + i * 64;
dummy_trans[i].rx_buffer = dummy_data + i * 64;
dummy_trans[i].user = dummy_data + i * 64;
dummy_trans[i].length = 64 * 8;
}
// start a trans by normal API first to trigger spi isr
spi_slave_queue_trans(TEST_SPI_HOST, &trans_cfg, portMAX_DELAY);
@ -687,7 +688,7 @@ 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
#endif // CONFIG_SPI_SLAVE_ISR_IN_IRAM
#if (SOC_CPU_CORES_NUM > 1) && (!CONFIG_FREERTOS_UNICORE)
@ -716,7 +717,7 @@ TEST_CASE("test_slave_isr_pin_to_core", "[spi]")
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_initialize(TEST_SPI_HOST, &buscfg, &slvcfg, SPI_DMA_DISABLED));
TEST_ESP_OK(spi_slave_queue_trans(TEST_SPI_HOST, &trans_cfg, portMAX_DELAY));
TEST_ESP_OK(spi_slave_free(TEST_SPI_HOST));
}
@ -729,7 +730,7 @@ TEST_CASE("test_slave_isr_pin_to_core", "[spi]")
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_initialize(TEST_SPI_HOST, &buscfg, &slvcfg, SPI_DMA_DISABLED));
TEST_ESP_OK(spi_slave_queue_trans(TEST_SPI_HOST, &trans_cfg, portMAX_DELAY));
vTaskDelay(1); // Waiting ISR on core 1 to be done.
TEST_ESP_OK(spi_slave_free(TEST_SPI_HOST));
@ -737,5 +738,4 @@ TEST_CASE("test_slave_isr_pin_to_core", "[spi]")
printf("Test Slave ISR Assign CPU1: %d : %ld\n", TEST_ISR_CNT, slave_expect);
TEST_ASSERT_EQUAL_UINT32(TEST_ISR_CNT, slave_expect);
}
#endif

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -22,7 +22,6 @@
#define TEST_BUF_SIZE 32
#define TEST_TIMES 4
static void test_master(void)
{
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
@ -144,6 +143,7 @@ static void test_slave(void)
trans[0].tx_buffer = slv_tx_buf[0];
trans[0].rx_buffer = slv_rx_buf[0];
trans[0].length = TEST_BUF_SIZE * 8;
trans[0].flags |= SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO;
TEST_ESP_OK(spi_slave_queue_trans(SPI2_HOST, &trans[0], portMAX_DELAY));
unity_send_signal("Slave ready");
TEST_ESP_OK(spi_slave_get_trans_result(SPI2_HOST, &ret_trans, portMAX_DELAY));
@ -159,24 +159,28 @@ static void test_slave(void)
spi_slave_transaction_t dummy_trans0 = {
.tx_buffer = &dummy_data0,
.length = sizeof(uint32_t) * 8,
.flags = SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
TEST_ESP_OK(spi_slave_queue_trans(SPI2_HOST, &dummy_trans0, portMAX_DELAY));
uint32_t dummy_data1 = 0xBB;
spi_slave_transaction_t dummy_trans1 = {
.tx_buffer = &dummy_data1,
.length = sizeof(uint32_t) * 8,
.flags = SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
TEST_ESP_OK(spi_slave_queue_trans(SPI2_HOST, &dummy_trans1, portMAX_DELAY));
uint32_t dummy_data2 = 0xCC;
spi_slave_transaction_t dummy_trans2 = {
.tx_buffer = &dummy_data2,
.length = sizeof(uint32_t) * 8,
.flags = SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
TEST_ESP_OK(spi_slave_queue_trans(SPI2_HOST, &dummy_trans2, portMAX_DELAY));
uint32_t dummy_data3 = 0xDD;
spi_slave_transaction_t dummy_trans3 = {
.tx_buffer = &dummy_data3,
.length = sizeof(uint32_t) * 8,
.flags = SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
TEST_ESP_OK(spi_slave_queue_trans(SPI2_HOST, &dummy_trans3, portMAX_DELAY));
@ -185,16 +189,19 @@ static void test_slave(void)
trans[1].tx_buffer = slv_tx_buf[1];
trans[1].rx_buffer = slv_rx_buf[1];
trans[1].length = TEST_BUF_SIZE * 8;
trans[1].flags |= SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO;
TEST_ESP_OK(spi_slave_queue_trans(SPI2_HOST, &trans[1], portMAX_DELAY));
trans[2].tx_buffer = slv_tx_buf[2];
trans[2].rx_buffer = slv_rx_buf[2];
trans[2].length = TEST_BUF_SIZE * 8;
trans[2].flags |= SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO;
TEST_ESP_OK(spi_slave_queue_trans(SPI2_HOST, &trans[2], portMAX_DELAY));
trans[3].tx_buffer = slv_tx_buf[3];
trans[3].rx_buffer = slv_rx_buf[3];
trans[3].length = TEST_BUF_SIZE * 8;
trans[3].flags |= SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO;
TEST_ESP_OK(spi_slave_queue_trans(SPI2_HOST, &trans[3], portMAX_DELAY));
unity_send_signal("Slave ready");

Wyświetl plik

@ -286,7 +286,7 @@ void cache_hal_unfreeze(uint32_t cache_level, cache_type_t type)
uint32_t cache_hal_get_cache_line_size(uint32_t cache_level, cache_type_t type)
{
HAL_ASSERT(cache_level && (cache_level <= CACHE_LL_LEVEL_NUMS));
HAL_ASSERT(cache_level <= CACHE_LL_LEVEL_NUMS);
uint32_t line_size = 0;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE

Wyświetl plik

@ -55,7 +55,7 @@ bool cache_hal_vaddr_to_cache_level_id(uint32_t vaddr_start, uint32_t len, uint3
uint32_t cache_hal_get_cache_line_size(uint32_t cache_level, cache_type_t type)
{
HAL_ASSERT(cache_level && (cache_level <= CACHE_LL_LEVEL_NUMS));
HAL_ASSERT(cache_level <= CACHE_LL_LEVEL_NUMS);
uint32_t line_size = 0;

Wyświetl plik

@ -30,6 +30,7 @@
#include "soc/soc_caps.h"
#include "hal/spi_types.h"
#include "hal/dma_types.h"
#include "soc/gdma_channel.h"
#if SOC_GPSPI_SUPPORTED
#include "hal/spi_ll.h"
#endif

Wyświetl plik

@ -27,8 +27,9 @@
#include "sdkconfig.h"
#include "esp_types.h"
#include "soc/soc_caps.h"
#include "hal/dma_types.h"
#include "soc/gdma_channel.h"
#if SOC_GPSPI_SUPPORTED
#include "soc/lldesc.h"
#include "hal/spi_ll.h"
#endif
@ -37,6 +38,11 @@ extern "C" {
#endif
#if SOC_GPSPI_SUPPORTED
#if (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB)
typedef dma_descriptor_align4_t spi_dma_desc_t;
#else
typedef dma_descriptor_align8_t spi_dma_desc_t;
#endif
/**
* Context that should be maintained by both the driver and the HAL.
@ -47,11 +53,11 @@ typedef struct {
spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
/* should be configured by driver at initialization */
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the TX DMA.
spi_dma_desc_t *dmadesc_rx; /**< Array of DMA descriptor used by the TX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the RX DMA.
spi_dma_desc_t *dmadesc_tx; /**< Array of DMA descriptor used by the RX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/

Wyświetl plik

@ -35,7 +35,6 @@ static void s_spi_slave_hal_dma_init_config(const spi_slave_hal_context_t *hal)
void spi_slave_hal_init(spi_slave_hal_context_t *hal, const spi_slave_hal_config_t *hal_config)
{
memset(hal, 0, sizeof(spi_slave_hal_context_t));
spi_dev_t *hw = SPI_LL_GET_HW(hal_config->host_id);
hal->hw = hw;
hal->dma_in = hal_config->dma_in;

Wyświetl plik

@ -45,13 +45,49 @@ void spi_slave_hal_user_start(const spi_slave_hal_context_t *hal)
spi_ll_user_start(hal->hw);
}
#if SOC_NON_CACHEABLE_OFFSET
#define ADDR_DMA_2_CPU(addr) ((typeof(addr))((uint32_t)(addr) + SOC_NON_CACHEABLE_OFFSET))
#define ADDR_CPU_2_DMA(addr) ((typeof(addr))((uint32_t)(addr) - SOC_NON_CACHEABLE_OFFSET))
#else
#define ADDR_DMA_2_CPU(addr) (addr)
#define ADDR_CPU_2_DMA(addr) (addr)
#endif
static void s_spi_slave_hal_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx)
{
dmadesc = ADDR_DMA_2_CPU(dmadesc);
int n = 0;
while (len) {
int dmachunklen = len;
if (dmachunklen > DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) {
dmachunklen = DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
}
if (is_rx) {
//Receive needs DMA length rounded to next 32-bit boundary
dmadesc[n].dw0.size = (dmachunklen + 3) & (~3);
} else {
dmadesc[n].dw0.size = dmachunklen;
dmadesc[n].dw0.length = dmachunklen;
}
dmadesc[n].buffer = (uint8_t *)data;
dmadesc[n].dw0.suc_eof = 0;
dmadesc[n].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
dmadesc[n].next = ADDR_CPU_2_DMA(&dmadesc[n + 1]);
len -= dmachunklen;
data += dmachunklen;
n++;
}
dmadesc[n - 1].dw0.suc_eof = 1; //Mark last DMA desc as end of stream.
dmadesc[n - 1].next = NULL;
}
void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal)
{
if (hal->use_dma) {
//Fill DMA descriptors
if (hal->rx_buffer) {
lldesc_setup_link(hal->dmadesc_rx, hal->rx_buffer, ((hal->bitlen + 7) / 8), true);
s_spi_slave_hal_dma_desc_setup_link(hal->dmadesc_rx, hal->rx_buffer, ((hal->bitlen + 7) / 8), true);
//reset dma inlink, this should be reset before spi related reset
spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan);
@ -60,10 +96,10 @@ void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal)
spi_ll_infifo_full_clr(hal->hw);
spi_ll_dma_rx_enable(hal->hw, 1);
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, hal->dmadesc_rx);
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, (lldesc_t *)hal->dmadesc_rx);
}
if (hal->tx_buffer) {
lldesc_setup_link(hal->dmadesc_tx, hal->tx_buffer, (hal->bitlen + 7) / 8, false);
s_spi_slave_hal_dma_desc_setup_link(hal->dmadesc_tx, hal->tx_buffer, (hal->bitlen + 7) / 8, false);
//reset dma outlink, this should be reset before spi related reset
spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan);
@ -72,7 +108,7 @@ void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal)
spi_ll_outfifo_empty_clr(hal->hw);
spi_ll_dma_tx_enable(hal->hw, 1);
spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, hal->dmadesc_tx);
spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, (lldesc_t *)hal->dmadesc_tx);
}
} else {
//No DMA. Turn off SPI and copy data to transmit buffers.
@ -125,8 +161,8 @@ bool spi_slave_hal_dma_need_reset(const spi_slave_hal_context_t *hal)
//In case CS goes high too soon, the transfer is aborted while the DMA channel still thinks it's going. This
//leads to issues later on, so in that case we need to reset the channel. The state can be detected because
//the DMA system doesn't give back the offending descriptor; the owner is still set to DMA.
for (i = 0; hal->dmadesc_rx[i].eof == 0 && hal->dmadesc_rx[i].owner == 0; i++) {}
if (hal->dmadesc_rx[i].owner) {
for (i = 0; hal->dmadesc_rx[i].dw0.suc_eof == 0 && hal->dmadesc_rx[i].dw0.owner == 0; i++) {}
if (hal->dmadesc_rx[i].dw0.owner) {
ret = true;
}
}

Wyświetl plik

@ -89,7 +89,6 @@ api-reference/peripherals/usb_host/usb_host_notes_design.rst
api-reference/peripherals/usb_device.rst
api-reference/peripherals/gpio.rst
api-reference/peripherals/dac.rst
api-reference/peripherals/spi_slave.rst
api-reference/peripherals/touch_element.rst
api-reference/peripherals/lcd.rst
api-reference/peripherals/ana_cmpr.rst

Wyświetl plik

@ -141,12 +141,12 @@ GPIO Matrix and IO_MUX
.. only:: not esp32
{IDF_TARGET_SPI2_IOMUX_PIN_CS:default="N/A", esp32s2="10", esp32s3="10", esp32c2="10", esp32c3="10", esp32c6="16", esp32h2="1"}
{IDF_TARGET_SPI2_IOMUX_PIN_CLK:default="N/A", esp32s2="12", esp32s3="12", esp32c2="6", esp32c3="6", esp32c6="6", esp32h2="4"}
{IDF_TARGET_SPI2_IOMUX_PIN_MOSI:default="N/A", esp32s2="11" esp32s3="11", esp32c2="7" esp32c3="7", esp32c6="7", esp32h2="5"}
{IDF_TARGET_SPI2_IOMUX_PIN_MISO:default="N/A", esp32s2="13" esp32s3="13", esp32c2="2" esp32c3="2", esp32c6="2", esp32h2="0"}
{IDF_TARGET_SPI2_IOMUX_PIN_HD:default="N/A", esp32s2="9" esp32s3="9", esp32c2="4" esp32c3="4", esp32c6="4", esp32h2="3"}
{IDF_TARGET_SPI2_IOMUX_PIN_WP:default="N/A", esp32s2="14" esp32s3="14", esp32c2="5" esp32c3="5", esp32c6="5", esp32h2="2"}
{IDF_TARGET_SPI2_IOMUX_PIN_CS:default="N/A", esp32s2="10", esp32s3="10", esp32c2="10", esp32c3="10", esp32c6="16", esp32h2="1", esp32p4="7"}
{IDF_TARGET_SPI2_IOMUX_PIN_CLK:default="N/A", esp32s2="12", esp32s3="12", esp32c2="6", esp32c3="6", esp32c6="6", esp32h2="4", esp32p4="9"}
{IDF_TARGET_SPI2_IOMUX_PIN_MOSI:default="N/A", esp32s2="11" esp32s3="11", esp32c2="7" esp32c3="7", esp32c6="7", esp32h2="5", esp32p4="8"}
{IDF_TARGET_SPI2_IOMUX_PIN_MISO:default="N/A", esp32s2="13" esp32s3="13", esp32c2="2" esp32c3="2", esp32c6="2", esp32h2="0", esp32p4="10"}
{IDF_TARGET_SPI2_IOMUX_PIN_HD:default="N/A", esp32s2="9" esp32s3="9", esp32c2="4" esp32c3="4", esp32c6="4", esp32h2="3", esp32p4="6"}
{IDF_TARGET_SPI2_IOMUX_PIN_WP:default="N/A", esp32s2="14" esp32s3="14", esp32c2="5" esp32c3="5", esp32c6="5", esp32h2="2", esp32p4="11"}
Most of chip's peripheral signals have direct connection to their dedicated IO_MUX pins. However, the signals can also be routed to any other available pins using the less direct GPIO matrix. If at least one signal is routed through the GPIO matrix, then all signals will be routed through it.

Wyświetl plik

@ -141,12 +141,12 @@ GPIO 交换矩阵和 IO_MUX
.. only:: not esp32
{IDF_TARGET_SPI2_IOMUX_PIN_CS:default="N/A", esp32s2="10", esp32s3="10", esp32c2="10", esp32c3="10", esp32c6="16", esp32h2="1"}
{IDF_TARGET_SPI2_IOMUX_PIN_CLK:default="N/A", esp32s2="12", esp32s3="12", esp32c2="6", esp32c3="6", esp32c6="6", esp32h2="4"}
{IDF_TARGET_SPI2_IOMUX_PIN_MOSI:default="N/A", esp32s2="11" esp32s3="11", esp32c2="7" esp32c3="7", esp32c6="7", esp32h2="5"}
{IDF_TARGET_SPI2_IOMUX_PIN_MISO:default="N/A", esp32s2="13" esp32s3="13", esp32c2="2" esp32c3="2", esp32c6="2", esp32h2="0"}
{IDF_TARGET_SPI2_IOMUX_PIN_HD:default="N/A", esp32s2="9" esp32s3="9", esp32c2="4" esp32c3="4", esp32c6="4", esp32h2="3"}
{IDF_TARGET_SPI2_IOMUX_PIN_WP:default="N/A", esp32s2="14" esp32s3="14", esp32c2="5" esp32c3="5", esp32c6="5", esp32h2="2"}
{IDF_TARGET_SPI2_IOMUX_PIN_CS:default="N/A", esp32s2="10", esp32s3="10", esp32c2="10", esp32c3="10", esp32c6="16", esp32h2="1", esp32p4="7"}
{IDF_TARGET_SPI2_IOMUX_PIN_CLK:default="N/A", esp32s2="12", esp32s3="12", esp32c2="6", esp32c3="6", esp32c6="6", esp32h2="4", esp32p4="9"}
{IDF_TARGET_SPI2_IOMUX_PIN_MOSI:default="N/A", esp32s2="11" esp32s3="11", esp32c2="7" esp32c3="7", esp32c6="7", esp32h2="5", esp32p4="8"}
{IDF_TARGET_SPI2_IOMUX_PIN_MISO:default="N/A", esp32s2="13" esp32s3="13", esp32c2="2" esp32c3="2", esp32c6="2", esp32h2="0", esp32p4="10"}
{IDF_TARGET_SPI2_IOMUX_PIN_HD:default="N/A", esp32s2="9" esp32s3="9", esp32c2="4" esp32c3="4", esp32c6="4", esp32h2="3", esp32p4="6"}
{IDF_TARGET_SPI2_IOMUX_PIN_WP:default="N/A", esp32s2="14" esp32s3="14", esp32c2="5" esp32c3="5", esp32c6="5", esp32h2="2", esp32p4="11"}
{IDF_TARGET_NAME} 的大多数外设信号都直接连接到其专用的 IO_MUX 管脚。不过,也可以使用 GPIO 交换矩阵,将信号路由到任何可用的其他管脚。如果通过 GPIO 交换矩阵路由了至少一个信号,则所有信号都将通过 GPIO 交换矩阵路由。

Wyświetl plik

@ -260,9 +260,6 @@ examples/peripherals/spi_master/lcd:
examples/peripherals/spi_slave:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
- if: IDF_TARGET in ["esp32p4"]
temporary: true
reason: target(s) is not supported yet # TODO: IDF-7503 slave support
examples/peripherals/spi_slave_hd/append_mode/master:
disable:

Wyświetl plik

@ -1,22 +1,23 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
## SPI slave example
These two projects illustrate the SPI Slave driver. They're supposed to be flashed into two separate Espressif chips connected to eachother using the SPI pins defined in app_main.c. Once connected and flashed, they will use the spi master and spi slave driver to communicate with eachother. The example also includes a handshaking line to allow the master to only poll the slave when it is actually ready to parse a transaction.
### Connection
For different chip and host used, the connections may be different. Here show a example diagram of hardware connection, you can freely change the GPIO settings by editing defines in the top of `main/app_main.c` in the master/slave source code. and change the hardware relatively.
The default GPIOs used in the example are the following:
| Signal | ESP32 |
|-----------|--------|
| Handshake | GPIO2 |
| MOSI | GPIO12 |
| MISO | GPIO13 |
| SCLK | GPIO15 |
| CS | GPIO14 |
<table>
<tr align="middle">
<th bgcolor=#ffffcc>Signal</th> <td>Handshake</td> <td>MOSI</td> <td>MISO</td> <td>SCLK</td> <td>CS</td>
</tr>
<tr align="middle">
<th bgcolor=#ffffcc>Pin</th> <td>GPIO2</td> <td>GPIO12</td> <td>GPIO13</td> <td>GPIO15</td> <td>GPIO14</td>
</tr>
</table>
Please run wires between the following GPIOs between the slave and master to make the example function:

Wyświetl plik

@ -30,54 +30,21 @@ ready to send/receive data, this code uses a callback to set the handshake pin h
sending a transaction. As soon as the transaction is done, the line gets set low again.
*/
/*
Pins in use. The SPI Master can use the GPIO mux, so feel free to change these if needed.
*/
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#define GPIO_HANDSHAKE 2
#define GPIO_MOSI 12
#define GPIO_MISO 13
#define GPIO_SCLK 15
#define GPIO_CS 14
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2
#define GPIO_HANDSHAKE 3
#define GPIO_MOSI 7
#define GPIO_MISO 2
#define GPIO_SCLK 6
#define GPIO_CS 10
#elif CONFIG_IDF_TARGET_ESP32C6
#define GPIO_HANDSHAKE 15
#define GPIO_MOSI 19
#define GPIO_MISO 20
#define GPIO_SCLK 18
#define GPIO_CS 9
#elif CONFIG_IDF_TARGET_ESP32H2
#define GPIO_HANDSHAKE 2
#define GPIO_MOSI 5
#define GPIO_MISO 0
#define GPIO_SCLK 4
#define GPIO_CS 1
#elif CONFIG_IDF_TARGET_ESP32S3
#define GPIO_HANDSHAKE 2
#define GPIO_MOSI 11
#define GPIO_MISO 13
#define GPIO_SCLK 12
#define GPIO_CS 10
#endif //CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// Please update the following configuration according to your HardWare spec /////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef CONFIG_IDF_TARGET_ESP32
#define RCV_HOST HSPI_HOST
#else
#define RCV_HOST SPI2_HOST
#endif
#define GPIO_HANDSHAKE 2
#define GPIO_MOSI 12
#define GPIO_MISO 13
#define GPIO_SCLK 15
#define GPIO_CS 14
//Called after a transaction is queued and ready for pickup by master. We use this to set the handshake line high.
void my_post_setup_cb(spi_slave_transaction_t *trans)
{
@ -119,7 +86,7 @@ void app_main(void)
gpio_config_t io_conf = {
.intr_type = GPIO_INTR_DISABLE,
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = (1 << GPIO_HANDSHAKE)
.pin_bit_mask = BIT64(GPIO_HANDSHAKE),
};
//Configure handshake line as output

Wyświetl plik

@ -105,7 +105,7 @@ void app_main(void)
.intr_type = GPIO_INTR_POSEDGE,
.mode = GPIO_MODE_INPUT,
.pull_up_en = 1,
.pin_bit_mask = (1 << GPIO_HANDSHAKE)
.pin_bit_mask = BIT64(GPIO_HANDSHAKE),
};
int n = 0;