Merge branch 'feature/esp32p4_hp_spi_slave_hd_support' into 'master'

Feature/esp32p4 hp spi slave hd support

Closes IDF-7505

See merge request espressif/esp-idf!25974
This commit is contained in:
Wan Lei
2023-11-09 14:42:05 +08:00
26 changed files with 401 additions and 304 deletions

View File

@@ -184,7 +184,9 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
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);
size_t alignment;
esp_cache_get_alignment(ESP_CACHE_MALLOC_FLAG_DMA, &alignment);
spihost[host]->internal_mem_align_size = alignment;
#else
spihost[host]->internal_mem_align_size = 4;
#endif

View File

@@ -1,10 +1,11 @@
/*
* SPDX-FileCopyrightText: 2010-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_check.h"
#include "esp_memory_utils.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
@@ -12,9 +13,12 @@
#include "freertos/ringbuf.h"
#include "driver/gpio.h"
#include "esp_private/spi_common_internal.h"
#include "esp_private/esp_cache_private.h"
#include "driver/spi_slave_hd.h"
#include "hal/spi_slave_hd_hal.h"
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#include "esp_cache.h"
#endif
#if (SOC_SPI_PERIPH_NUM == 2)
#define VALID_HOST(x) ((x) == SPI2_HOST)
@@ -23,8 +27,15 @@
#endif
#define SPIHD_CHECK(cond,warn,ret) do{if(!(cond)){ESP_LOGE(TAG, warn); return ret;}} while(0)
/// struct to hold private transaction data (like tx and rx buffer for DMA).
typedef struct {
spi_slave_hd_data_t *trans; //original trans
void *aligned_buffer; //actually trans buffer (re-malloced if needed)
} spi_slave_hd_trans_priv_t;
typedef struct {
bool dma_enabled;
uint16_t internal_mem_align_size;
int max_transfer_sz;
uint32_t flags;
portMUX_TYPE int_spinlock;
@@ -45,8 +56,8 @@ typedef struct {
QueueHandle_t tx_cnting_sem;
QueueHandle_t rx_cnting_sem;
spi_slave_hd_data_t *tx_desc;
spi_slave_hd_data_t *rx_desc;
spi_slave_hd_trans_priv_t tx_curr_trans;
spi_slave_hd_trans_priv_t rx_curr_trans;
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock;
#endif
@@ -89,12 +100,47 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
spihost[host_id] = host;
host->int_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
host->dma_enabled = (config->dma_chan != SPI_DMA_DISABLED);
host->append_mode = append_mode;
if (host->dma_enabled) {
ret = spicommon_dma_chan_alloc(host_id, config->dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan);
if (ret != ESP_OK) {
goto cleanup;
}
//Malloc for all the DMA descriptors
int dma_desc_ct = (bus_config->max_transfer_sz + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
if (dma_desc_ct == 0) {
dma_desc_ct = 1; //default to 4k when max is not given
}
host->hal.dma_desc_num = dma_desc_ct;
spi_dma_desc_t *orig_dmadesc_tx = heap_caps_aligned_alloc(DMA_DESC_MEM_ALIGN_SIZE, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA);
spi_dma_desc_t *orig_dmadesc_rx = heap_caps_aligned_alloc(DMA_DESC_MEM_ALIGN_SIZE, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA);
host->hal.dmadesc_tx = heap_caps_malloc(sizeof(spi_slave_hd_hal_desc_append_t) * dma_desc_ct, MALLOC_CAP_DEFAULT);
host->hal.dmadesc_rx = heap_caps_malloc(sizeof(spi_slave_hd_hal_desc_append_t) * dma_desc_ct, MALLOC_CAP_DEFAULT);
if (!(host->hal.dmadesc_tx && host->hal.dmadesc_rx && orig_dmadesc_tx && orig_dmadesc_rx)) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
//Pair each desc to each possible trans
for (int i = 0; i < dma_desc_ct; i ++) {
host->hal.dmadesc_tx[i].desc = &orig_dmadesc_tx[i];
host->hal.dmadesc_rx[i].desc = &orig_dmadesc_rx[i];
}
//Get the actual SPI bus transaction size in bytes.
host->max_transfer_sz = dma_desc_ct * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
size_t alignment;
esp_cache_get_alignment(ESP_CACHE_MALLOC_FLAG_DMA, &alignment);
host->internal_mem_align_size = alignment;
#else
host->internal_mem_align_size = 4;
#endif
} else {
//We're limited to non-DMA transfers: the SPI work registers can hold (72 for S2, 64 for others) bytes at most.
host->max_transfer_sz = 0;
}
ret = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, &host->flags);
@@ -102,9 +148,7 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
goto cleanup;
}
gpio_set_direction(config->spics_io_num, GPIO_MODE_INPUT);
spicommon_cs_initialize(host_id, config->spics_io_num, 0,
!(bus_config->flags & SPICOMMON_BUSFLAG_NATIVE_PINS));
host->append_mode = append_mode;
spicommon_cs_initialize(host_id, config->spics_io_num, 0, !(bus_config->flags & SPICOMMON_BUSFLAG_NATIVE_PINS));
spi_slave_hd_hal_config_t hal_config = {
.host_id = host_id,
@@ -119,23 +163,6 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
.rx_lsbfirst = (config->flags & SPI_SLAVE_HD_TXBIT_LSBFIRST),
};
if (host->dma_enabled) {
//Malloc for all the DMA descriptors
uint32_t total_desc_size = spi_slave_hd_hal_get_total_desc_size(&host->hal, bus_config->max_transfer_sz);
host->hal.dmadesc_tx = heap_caps_malloc(total_desc_size, MALLOC_CAP_DMA);
host->hal.dmadesc_rx = heap_caps_malloc(total_desc_size, MALLOC_CAP_DMA);
if (!host->hal.dmadesc_tx || !host->hal.dmadesc_rx) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
//Get the actual SPI bus transaction size in bytes.
host->max_transfer_sz = spi_salve_hd_hal_get_max_bus_size(&host->hal);
} else {
//We're limited to non-DMA transfers: the SPI work registers can hold 64 bytes at most.
host->max_transfer_sz = 0;
}
//Init the hal according to the hal_config set above
spi_slave_hd_hal_init(&host->hal, &hal_config);
@@ -149,11 +176,11 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
#endif //CONFIG_PM_ENABLE
//Create Queues and Semaphores
host->tx_ret_queue = xQueueCreate(config->queue_size, sizeof(spi_slave_hd_data_t *));
host->rx_ret_queue = xQueueCreate(config->queue_size, sizeof(spi_slave_hd_data_t *));
host->tx_ret_queue = xQueueCreate(config->queue_size, sizeof(spi_slave_hd_trans_priv_t));
host->rx_ret_queue = xQueueCreate(config->queue_size, sizeof(spi_slave_hd_trans_priv_t));
if (!host->append_mode) {
host->tx_trans_queue = xQueueCreate(config->queue_size, sizeof(spi_slave_hd_data_t *));
host->rx_trans_queue = xQueueCreate(config->queue_size, sizeof(spi_slave_hd_data_t *));
host->tx_trans_queue = xQueueCreate(config->queue_size, sizeof(spi_slave_hd_trans_priv_t));
host->rx_trans_queue = xQueueCreate(config->queue_size, sizeof(spi_slave_hd_trans_priv_t));
if (!host->tx_trans_queue || !host->rx_trans_queue) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
@@ -232,21 +259,21 @@ esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id)
if (host->rx_ret_queue) vQueueDelete(host->rx_ret_queue);
if (host->tx_cnting_sem) vSemaphoreDelete(host->tx_cnting_sem);
if (host->rx_cnting_sem) vSemaphoreDelete(host->rx_cnting_sem);
if (host) {
free(host->hal.dmadesc_tx);
free(host->hal.dmadesc_rx);
esp_intr_free(host->intr);
esp_intr_free(host->intr_dma);
esp_intr_free(host->intr);
esp_intr_free(host->intr_dma);
#ifdef CONFIG_PM_ENABLE
if (host->pm_lock) {
esp_pm_lock_release(host->pm_lock);
esp_pm_lock_delete(host->pm_lock);
}
#endif
if (host->pm_lock) {
esp_pm_lock_release(host->pm_lock);
esp_pm_lock_delete(host->pm_lock);
}
#endif
spicommon_periph_free(host_id);
if (host->dma_enabled) {
free(host->hal.dmadesc_tx->desc);
free(host->hal.dmadesc_rx->desc);
free(host->hal.dmadesc_tx);
free(host->hal.dmadesc_rx);
spicommon_dma_chan_free(host_id);
}
free(host);
@@ -295,10 +322,10 @@ static IRAM_ATTR void spi_slave_hd_intr_segment(void *arg)
bool rx_done = false;
portENTER_CRITICAL_ISR(&host->int_spinlock);
if (host->tx_desc && spi_slave_hd_hal_check_disable_event(hal, SPI_EV_SEND)) {
if (host->tx_curr_trans.trans && spi_slave_hd_hal_check_disable_event(hal, SPI_EV_SEND)) {
tx_done = true;
}
if (host->rx_desc && spi_slave_hd_hal_check_disable_event(hal, SPI_EV_RECV)) {
if (host->rx_curr_trans.trans && spi_slave_hd_hal_check_disable_event(hal, SPI_EV_RECV)) {
rx_done = true;
}
portEXIT_CRITICAL_ISR(&host->int_spinlock);
@@ -308,50 +335,56 @@ static IRAM_ATTR void spi_slave_hd_intr_segment(void *arg)
if (callback->cb_sent) {
spi_slave_hd_event_t ev = {
.event = SPI_EV_SEND,
.trans = host->tx_desc,
.trans = host->tx_curr_trans.trans,
};
BaseType_t cb_awoken = pdFALSE;
ret_queue = callback->cb_sent(callback->arg, &ev, &cb_awoken);
awoken |= cb_awoken;
}
if (ret_queue) {
ret = xQueueSendFromISR(host->tx_ret_queue, &host->tx_desc, &awoken);
ret = xQueueSendFromISR(host->tx_ret_queue, &host->tx_curr_trans, &awoken);
// The return queue is full. All the data remian in send_queue + ret_queue should not be more than the queue length.
assert(ret == pdTRUE);
}
host->tx_desc = NULL;
host->tx_curr_trans.trans = NULL;
}
if (rx_done) {
bool ret_queue = true;
host->rx_desc->trans_len = spi_slave_hd_hal_rxdma_seg_get_len(hal);
host->rx_curr_trans.trans->trans_len = spi_slave_hd_hal_rxdma_seg_get_len(hal);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE //invalidate here to let user access rx data in post_cb if possible
uint16_t alignment = host->internal_mem_align_size;
uint32_t buff_len = (host->rx_curr_trans.trans->len + alignment - 1) & (~(alignment - 1));
esp_err_t ret = esp_cache_msync((void *)host->rx_curr_trans.aligned_buffer, buff_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
assert(ret == ESP_OK);
#endif
if (callback->cb_recv) {
spi_slave_hd_event_t ev = {
.event = SPI_EV_RECV,
.trans = host->rx_desc,
.trans = host->rx_curr_trans.trans,
};
BaseType_t cb_awoken = pdFALSE;
ret_queue = callback->cb_recv(callback->arg, &ev, &cb_awoken);
awoken |= cb_awoken;
}
if (ret_queue) {
ret = xQueueSendFromISR(host->rx_ret_queue, &host->rx_desc, &awoken);
ret = xQueueSendFromISR(host->rx_ret_queue, &host->rx_curr_trans, &awoken);
// The return queue is full. All the data remian in send_queue + ret_queue should not be more than the queue length.
assert(ret == pdTRUE);
}
host->rx_desc = NULL;
host->rx_curr_trans.trans = NULL;
}
bool tx_sent = false;
bool rx_sent = false;
if (!host->tx_desc) {
ret = xQueueReceiveFromISR(host->tx_trans_queue, &host->tx_desc, &awoken);
if (!host->tx_curr_trans.trans) {
ret = xQueueReceiveFromISR(host->tx_trans_queue, &host->tx_curr_trans, &awoken);
if (ret == pdTRUE) {
spi_slave_hd_hal_txdma(hal, host->tx_desc->data, host->tx_desc->len);
spi_slave_hd_hal_txdma(hal, host->tx_curr_trans.aligned_buffer, host->tx_curr_trans.trans->len);
tx_sent = true;
if (callback->cb_send_dma_ready) {
spi_slave_hd_event_t ev = {
.event = SPI_EV_SEND_DMA_READY,
.trans = host->tx_desc,
.trans = host->tx_curr_trans.trans,
};
BaseType_t cb_awoken = pdFALSE;
callback->cb_send_dma_ready(callback->arg, &ev, &cb_awoken);
@@ -359,15 +392,15 @@ static IRAM_ATTR void spi_slave_hd_intr_segment(void *arg)
}
}
}
if (!host->rx_desc) {
ret = xQueueReceiveFromISR(host->rx_trans_queue, &host->rx_desc, &awoken);
if (!host->rx_curr_trans.trans) {
ret = xQueueReceiveFromISR(host->rx_trans_queue, &host->rx_curr_trans, &awoken);
if (ret == pdTRUE) {
spi_slave_hd_hal_rxdma(hal, host->rx_desc->data, host->rx_desc->len);
spi_slave_hd_hal_rxdma(hal, host->rx_curr_trans.aligned_buffer, host->rx_curr_trans.trans->len);
rx_sent = true;
if (callback->cb_recv_dma_ready) {
spi_slave_hd_event_t ev = {
.event = SPI_EV_RECV_DMA_READY,
.trans = host->rx_desc,
.trans = host->rx_curr_trans.trans,
};
BaseType_t cb_awoken = pdFALSE;
callback->cb_recv_dma_ready(callback->arg, &ev, &cb_awoken);
@@ -396,10 +429,10 @@ static IRAM_ATTR void spi_slave_hd_append_tx_isr(void *arg)
BaseType_t awoken = pdFALSE;
BaseType_t ret __attribute__((unused));
spi_slave_hd_data_t *trans_desc;
spi_slave_hd_trans_priv_t ret_priv_trans;
while (1) {
bool trans_finish = false;
trans_finish = spi_slave_hd_hal_get_tx_finished_trans(hal, (void **)&trans_desc);
trans_finish = spi_slave_hd_hal_get_tx_finished_trans(hal, (void **)&ret_priv_trans.trans, &ret_priv_trans.aligned_buffer);
if (!trans_finish) {
break;
}
@@ -408,7 +441,7 @@ static IRAM_ATTR void spi_slave_hd_append_tx_isr(void *arg)
if (callback->cb_sent) {
spi_slave_hd_event_t ev = {
.event = SPI_EV_SEND,
.trans = trans_desc,
.trans = ret_priv_trans.trans,
};
BaseType_t cb_awoken = pdFALSE;
ret_queue = callback->cb_sent(callback->arg, &ev, &cb_awoken);
@@ -416,7 +449,7 @@ static IRAM_ATTR void spi_slave_hd_append_tx_isr(void *arg)
}
if (ret_queue) {
ret = xQueueSendFromISR(host->tx_ret_queue, &trans_desc, &awoken);
ret = xQueueSendFromISR(host->tx_ret_queue, &ret_priv_trans, &awoken);
assert(ret == pdTRUE);
ret = xSemaphoreGiveFromISR(host->tx_cnting_sem, &awoken);
@@ -434,21 +467,27 @@ static IRAM_ATTR void spi_slave_hd_append_rx_isr(void *arg)
BaseType_t awoken = pdFALSE;
BaseType_t ret __attribute__((unused));
spi_slave_hd_data_t *trans_desc;
spi_slave_hd_trans_priv_t ret_priv_trans;
size_t trans_len;
while (1) {
bool trans_finish = false;
trans_finish = spi_slave_hd_hal_get_rx_finished_trans(hal, (void **)&trans_desc, &trans_len);
trans_finish = spi_slave_hd_hal_get_rx_finished_trans(hal, (void **)&ret_priv_trans.trans, &ret_priv_trans.aligned_buffer, &trans_len);
if (!trans_finish) {
break;
}
trans_desc->trans_len = trans_len;
ret_priv_trans.trans->trans_len = trans_len;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE //invalidate here to let user access rx data in post_cb if possible
uint16_t alignment = host->internal_mem_align_size;
uint32_t buff_len = (ret_priv_trans.trans->len + alignment - 1) & (~(alignment - 1));
esp_err_t ret = esp_cache_msync((void *)ret_priv_trans.aligned_buffer, buff_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
assert(ret == ESP_OK);
#endif
bool ret_queue = true;
if (callback->cb_recv) {
spi_slave_hd_event_t ev = {
.event = SPI_EV_RECV,
.trans = trans_desc,
.trans = ret_priv_trans.trans,
};
BaseType_t cb_awoken = pdFALSE;
ret_queue = callback->cb_recv(callback->arg, &ev, &cb_awoken);
@@ -456,7 +495,7 @@ static IRAM_ATTR void spi_slave_hd_append_rx_isr(void *arg)
}
if (ret_queue) {
ret = xQueueSendFromISR(host->rx_ret_queue, &trans_desc, &awoken);
ret = xQueueSendFromISR(host->rx_ret_queue, &ret_priv_trans, &awoken);
assert(ret == pdTRUE);
ret = xSemaphoreGiveFromISR(host->rx_cnting_sem, &awoken);
@@ -504,22 +543,64 @@ static IRAM_ATTR void spi_slave_hd_intr_append(void *arg)
}
}
static void s_spi_slave_hd_destroy_priv_trans(spi_host_device_t host, spi_slave_hd_trans_priv_t *priv_trans, spi_slave_chan_t chan)
{
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
spi_slave_hd_data_t *orig_trans = priv_trans->trans;
if (priv_trans->aligned_buffer != orig_trans->data) {
if (chan == SPI_SLAVE_CHAN_RX) {
memcpy(orig_trans->data, priv_trans->aligned_buffer, orig_trans->trans_len);
}
free(priv_trans->aligned_buffer);
}
#endif //SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
}
static esp_err_t s_spi_slave_hd_setup_priv_trans(spi_host_device_t host, spi_slave_hd_trans_priv_t *priv_trans, spi_slave_chan_t chan)
{
spi_slave_hd_data_t *orig_trans = priv_trans->trans;
priv_trans->aligned_buffer = orig_trans->data;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
uint16_t alignment = spihost[host]->internal_mem_align_size;
uint32_t byte_len = orig_trans->len;
if (((uint32_t)orig_trans->data) | (byte_len & (alignment - 1))) {
ESP_RETURN_ON_FALSE(orig_trans->flags & SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO, ESP_ERR_INVALID_ARG, TAG, "data buffer addr&len not align to %d, or not dma_capable", alignment);
byte_len = (byte_len + alignment - 1) & (~(alignment - 1)); // up align to alignment
ESP_LOGD(TAG, "Re-allocate %s buffer of len %ld for DMA", (chan == SPI_SLAVE_CHAN_TX)?"TX":"RX", byte_len);
priv_trans->aligned_buffer = heap_caps_aligned_alloc(64, byte_len, MALLOC_CAP_DMA);
if (priv_trans->aligned_buffer == NULL) {
return ESP_ERR_NO_MEM;
}
}
if (chan == SPI_SLAVE_CHAN_TX) {
memcpy(priv_trans->aligned_buffer, orig_trans->data, orig_trans->len);
esp_err_t ret = esp_cache_msync((void *)priv_trans->aligned_buffer, byte_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
ESP_RETURN_ON_FALSE(ESP_OK == ret, ESP_ERR_INVALID_STATE, TAG, "mem sync c2m(writeback) fail");
}
#endif //SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
return ESP_OK;
}
static esp_err_t get_ret_queue_result(spi_host_device_t host_id, spi_slave_chan_t chan, spi_slave_hd_data_t **out_trans, TickType_t timeout)
{
spi_slave_hd_slot_t *host = spihost[host_id];
spi_slave_hd_data_t *trans;
spi_slave_hd_trans_priv_t hd_priv_trans;
BaseType_t ret;
if (chan == SPI_SLAVE_CHAN_TX) {
ret = xQueueReceive(host->tx_ret_queue, &trans, timeout);
ret = xQueueReceive(host->tx_ret_queue, &hd_priv_trans, timeout);
} else {
ret = xQueueReceive(host->rx_ret_queue, &trans, timeout);
ret = xQueueReceive(host->rx_ret_queue, &hd_priv_trans, timeout);
}
if (ret == pdFALSE) {
return ESP_ERR_TIMEOUT;
}
*out_trans = trans;
s_spi_slave_hd_destroy_priv_trans(host_id, &hd_priv_trans, chan);
*out_trans = hd_priv_trans.trans;
return ESP_OK;
}
@@ -533,14 +614,17 @@ esp_err_t spi_slave_hd_queue_trans(spi_host_device_t host_id, spi_slave_chan_t c
SPIHD_CHECK(trans->len <= host->max_transfer_sz && trans->len > 0, "Invalid buffer size", ESP_ERR_INVALID_ARG);
SPIHD_CHECK(chan == SPI_SLAVE_CHAN_TX || chan == SPI_SLAVE_CHAN_RX, "Invalid channel", ESP_ERR_INVALID_ARG);
spi_slave_hd_trans_priv_t hd_priv_trans = {.trans = trans};
SPIHD_CHECK( ESP_OK == s_spi_slave_hd_setup_priv_trans(host_id, &hd_priv_trans, chan), "No mem to allocate new cache buffer", ESP_ERR_NO_MEM);
if (chan == SPI_SLAVE_CHAN_TX) {
BaseType_t ret = xQueueSend(host->tx_trans_queue, &trans, timeout);
BaseType_t ret = xQueueSend(host->tx_trans_queue, &hd_priv_trans, timeout);
if (ret == pdFALSE) {
return ESP_ERR_TIMEOUT;
}
tx_invoke(host);
} else { //chan == SPI_SLAVE_CHAN_RX
BaseType_t ret = xQueueSend(host->rx_trans_queue, &trans, timeout);
BaseType_t ret = xQueueSend(host->rx_trans_queue, &hd_priv_trans, timeout);
if (ret == pdFALSE) {
return ESP_ERR_TIMEOUT;
}
@@ -584,18 +668,21 @@ esp_err_t spi_slave_hd_append_trans(spi_host_device_t host_id, spi_slave_chan_t
SPIHD_CHECK(trans->len <= host->max_transfer_sz && trans->len > 0, "Invalid buffer size", ESP_ERR_INVALID_ARG);
SPIHD_CHECK(chan == SPI_SLAVE_CHAN_TX || chan == SPI_SLAVE_CHAN_RX, "Invalid channel", ESP_ERR_INVALID_ARG);
spi_slave_hd_trans_priv_t hd_priv_trans = {.trans = trans};
SPIHD_CHECK( ESP_OK == s_spi_slave_hd_setup_priv_trans(host_id, &hd_priv_trans, chan), "No mem to allocate new cache buffer", ESP_ERR_NO_MEM);
if (chan == SPI_SLAVE_CHAN_TX) {
BaseType_t ret = xSemaphoreTake(host->tx_cnting_sem, timeout);
if (ret == pdFALSE) {
return ESP_ERR_TIMEOUT;
}
err = spi_slave_hd_hal_txdma_append(hal, trans->data, trans->len, trans);
err = spi_slave_hd_hal_txdma_append(hal, hd_priv_trans.aligned_buffer, trans->len, trans);
} else {
BaseType_t ret = xSemaphoreTake(host->rx_cnting_sem, timeout);
if (ret == pdFALSE) {
return ESP_ERR_TIMEOUT;
}
err = spi_slave_hd_hal_rxdma_append(hal, trans->data, trans->len, trans);
err = spi_slave_hd_hal_rxdma_append(hal, hd_priv_trans.aligned_buffer, trans->len, trans);
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "Wait until the DMA finishes its transaction");

View File

@@ -23,11 +23,14 @@ extern "C"
#error The SPI peripheral does not support this feature
#endif
#define SPI_SLAVE_HD_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 lose some memory and performance
/// Descriptor of data to send/receive
typedef struct {
uint8_t* data; ///< Buffer to send, must be DMA capable
size_t len; ///< Len of data to send/receive. For receiving the buffer length should be multiples of 4 bytes, otherwise the extra part will be truncated.
size_t trans_len; ///< For RX direction, it indicates the data actually received. For TX direction, it is meaningless.
uint32_t flags; ///< Bitwise OR of SPI_SLAVE_HD_TRANS_* flags
void* arg; ///< Extra argument indiciating this data
} spi_slave_hd_data_t;

View File

@@ -146,9 +146,6 @@ components/driver/test_apps/spi/master:
components/driver/test_apps/spi/param:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
- if: IDF_TARGET in ["esp32p4"]
temporary: true
reason: target(s) is not supported yet # TODO: IDF-7505
components/driver/test_apps/spi/slave:
disable:

View File

@@ -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 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |

View File

@@ -1374,6 +1374,7 @@ static void test_slave_fd_dma(void)
.tx_buffer = slave_send,
.rx_buffer = slave_recive,
.length = test_trans_len * 8,
.flags = SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
unity_send_signal("Slave ready");
TEST_ESP_OK(spi_slave_transmit(TEST_SPI_HOST, &trans_cfg, portMAX_DELAY));
@@ -1589,6 +1590,7 @@ static void test_slave_hd_dma(void)
spi_slave_hd_data_t *ret_trans, slave_trans = {
.data = slave_send,
.len = test_trans_len,
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
unity_send_signal("Slave ready");
TEST_ESP_OK(spi_slave_hd_queue_trans(TEST_SPI_HOST, SPI_SLAVE_CHAN_TX, &slave_trans, portMAX_DELAY));
@@ -1690,6 +1692,7 @@ static void test_slave_hd_no_dma(void)
spi_slave_hd_data_t *ret_trans, slave_trans = {
.data = slave_send,
.len = test_trans_len,
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
unity_send_signal("Slave ready");
TEST_ESP_OK(spi_slave_hd_queue_trans(TEST_SPI_HOST, SPI_SLAVE_CHAN_TX, &slave_trans, portMAX_DELAY));
@@ -1826,6 +1829,7 @@ static void test_slave_sio_dma(void)
.length = TEST_STEP_LEN * 8,
.tx_buffer = slave_send,
.rx_buffer = slave_recive,
.flags = SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
unity_send_signal("Slave ready");
TEST_ESP_OK(spi_slave_transmit(TEST_SPI_HOST, &trans, portMAX_DELAY));

View File

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

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
*/
@@ -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)

View File

@@ -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
*/
@@ -224,6 +224,7 @@ static void test_hd_start(spi_device_handle_t *spi, int freq, const spitest_para
ctx->tx_data = (spi_slave_hd_data_t) {
.data = &ctx->slave_rddma_buf[pos],
.len = len,
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
esp_err_t err = spi_slave_hd_queue_trans(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_TX, &ctx->tx_data, portMAX_DELAY);
TEST_ESP_OK(err);
@@ -231,6 +232,7 @@ static void test_hd_start(spi_device_handle_t *spi, int freq, const spitest_para
ctx->rx_data = (spi_slave_hd_data_t) {
.data = ctx->slave_wrdma_buf,
.len = TEST_DMA_MAX_SIZE,
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
err = spi_slave_hd_queue_trans(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_RX, &ctx->rx_data, portMAX_DELAY);
TEST_ESP_OK(err);
@@ -269,6 +271,7 @@ void test_wrdma(testhd_context_t* ctx, const spitest_param_set_t *cfg, spi_devic
ctx->rx_data = (spi_slave_hd_data_t) {
.data = ctx->slave_wrdma_buf,
.len = TEST_DMA_MAX_SIZE,
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
esp_err_t err = spi_slave_hd_queue_trans(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_RX, &ctx->rx_data, portMAX_DELAY);
TEST_ESP_OK(err);
@@ -302,6 +305,7 @@ void test_rddma(testhd_context_t* ctx, const spitest_param_set_t* cfg, spi_devic
ctx->tx_data = (spi_slave_hd_data_t) {
.data = &ctx->slave_rddma_buf[pos],
.len = len,
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
};
esp_err_t err = spi_slave_hd_queue_trans(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_TX, &ctx->tx_data, portMAX_DELAY);
TEST_ESP_OK(err);
@@ -415,6 +419,14 @@ static void test_hd_loop(const void* arg1, void* arg2)
TEST_ASSERT_EQUAL_HEX8_ARRAY(&slave_mem, recv_buffer, REG_REGION_SIZE);
}
//To release the re-malloced buffer remain in slave trans queue if possible
printf("clean tx %d rx %d\n", context->tx_data.len, context->rx_data.len);
TEST_ESP_OK(essl_spi_rddma(spi, context->master_rddma_buf, context->tx_data.len, TEST_SEG_SIZE, 0));
TEST_ESP_OK(essl_spi_wrdma(spi, context->master_wrdma_buf, context->rx_data.len, TEST_SEG_SIZE, 0));
spi_slave_hd_data_t* ret_trans;
TEST_ESP_OK(spi_slave_hd_get_trans_res(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_TX, &ret_trans, portMAX_DELAY));
TEST_ESP_OK(spi_slave_hd_get_trans_res(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_RX, &ret_trans, portMAX_DELAY));
master_free_device_bus(spi);
spi_slave_hd_deinit(TEST_SLAVE_HOST);
}
@@ -434,8 +446,8 @@ static const ptest_func_t hd_test_func = {
static int test_freq_hd[] = {
// 100*1000,
// 10 * 1000 * 1000, //maximum freq MISO stable before next latch edge
// 20 * 1000 * 1000, //maximum freq MISO stable before next latch edge
40 * 1000 * 1000, //maximum freq MISO stable before next latch edge
20 * 1000 * 1000, //maximum freq MISO stable before next latch edge
// 40 * 1000 * 1000, //maximum freq MISO stable before next latch edge
0,
};
@@ -520,19 +532,23 @@ TEST_CASE("test spi slave hd segment mode, master too long", "[spi][spi_slv_hd]"
{
.data = slave_recv_buf,
.len = (trans_len[0] + 3) & (~3),
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
},
{
.data = slave_recv_buf + send_buf_size,
.len = (trans_len[1] + 3) & (~3),
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
},
//send
{
.data = slave_send_buf,
.len = trans_len[0],
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
},
{
.data = slave_send_buf + send_buf_size,
.len = trans_len[1],
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
},
};
@@ -925,15 +941,17 @@ void slave_run_append(void)
ESP_LOG_BUFFER_HEX_LEVEL("slave exp", slave_exp, trans_len, ESP_LOG_DEBUG);
spitest_cmp_or_dump(slave_exp, ret_trans->data, trans_len);
// append one more transaction
int new_append_len = trans_len << 4;
if (new_append_len > TEST_TRANS_LEN) {
new_append_len = TEST_TRANS_LEN;
if (trans_num <= TEST_APPEND_CACHE_SIZE) {
// append one more transaction
int new_append_len = trans_len << 4;
if (new_append_len > TEST_TRANS_LEN) {
new_append_len = TEST_TRANS_LEN;
}
memset(ret_trans->data, 0, ret_trans->trans_len);
ret_trans->len = new_append_len;
ret_trans->trans_len = 0;
TEST_ESP_OK(spi_slave_hd_append_trans(TEST_SPI_HOST, SPI_SLAVE_CHAN_RX, ret_trans, portMAX_DELAY));
}
memset(ret_trans->data, 0, ret_trans->trans_len);
ret_trans->len = new_append_len;
ret_trans->trans_len = 0;
TEST_ESP_OK(spi_slave_hd_append_trans(TEST_SPI_HOST, SPI_SLAVE_CHAN_RX, ret_trans, portMAX_DELAY));
}
printf("================Master Tx Done==================\n\n");
free(slave_exp);
@@ -958,15 +976,17 @@ void slave_run_append(void)
ESP_LOGI("slave", "trasacted len: %d", ret_trans->len);
ESP_LOG_BUFFER_HEX_LEVEL("slave tx", ret_trans->data, ret_trans->len, ESP_LOG_DEBUG);
// append one more transaction
int new_append_len = 16 << (trans_num + 4);
if (new_append_len > TEST_TRANS_LEN) {
new_append_len = TEST_TRANS_LEN;
if (trans_num <= TEST_APPEND_CACHE_SIZE) {
// append one more transaction
int new_append_len = 16 << (trans_num + 4);
if (new_append_len > TEST_TRANS_LEN) {
new_append_len = TEST_TRANS_LEN;
}
ret_trans->len = new_append_len;
ret_trans->trans_len = 0;
prepare_data(ret_trans->data, ret_trans->len, -3);
TEST_ESP_OK(spi_slave_hd_append_trans(TEST_SPI_HOST, SPI_SLAVE_CHAN_TX, ret_trans, portMAX_DELAY));
}
ret_trans->len = new_append_len;
ret_trans->trans_len = 0;
prepare_data(ret_trans->data, ret_trans->len, -3);
TEST_ESP_OK(spi_slave_hd_append_trans(TEST_SPI_HOST, SPI_SLAVE_CHAN_TX, ret_trans, portMAX_DELAY));
}
printf("================Master Rx Done==================\n");
for (int i = 0; i < TEST_APPEND_CACHE_SIZE; i++) free(slave_tx_trans[i].data);

View File

@@ -46,7 +46,9 @@
#include "esp_types.h"
#include "esp_err.h"
#include "soc/soc_caps.h"
#include "soc/gdma_channel.h"
#include "hal/spi_types.h"
#include "hal/dma_types.h"
#if SOC_GPSPI_SUPPORTED
#include "hal/spi_ll.h"
#endif
@@ -57,13 +59,24 @@ extern "C" {
#if SOC_GPSPI_SUPPORTED
//NOTE!! If both A and B are not defined, '#if (A==B)' is true, because GCC use 0 stand for undefined symbol
#if !defined(SOC_GDMA_TRIG_PERIPH_SPI2_BUS)
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)
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)
typedef dma_descriptor_align4_t spi_dma_desc_t;
#endif
#endif
/**
* @brief Type of dma descriptor with appended members
* this structure inherits DMA descriptor, with a pointer to the transaction descriptor passed from users.
*/
typedef struct {
lldesc_t desc; ///< DMA descriptor
void *arg; ///< This points to the transaction descriptor user passed in
spi_dma_desc_t *desc; ///< DMA descriptor
void *arg; ///< This points to the transaction descriptor user passed in
} spi_slave_hd_hal_desc_append_t;
/// Configuration of the HAL
@@ -105,13 +118,11 @@ typedef struct {
spi_slave_hd_hal_desc_append_t *tx_cur_desc; ///< Current TX DMA descriptor that could be linked (set up).
spi_slave_hd_hal_desc_append_t *tx_dma_head; ///< Head of the linked TX DMA descriptors which are not used by hardware
spi_slave_hd_hal_desc_append_t *tx_dma_tail; ///< Tail of the linked TX DMA descriptors which are not used by hardware
spi_slave_hd_hal_desc_append_t tx_dummy_head; ///< Dummy descriptor for ``tx_dma_head`` to start
uint32_t tx_used_desc_cnt; ///< Number of the TX descriptors that have been setup
uint32_t tx_recycled_desc_cnt; ///< Number of the TX descriptors that could be recycled
spi_slave_hd_hal_desc_append_t *rx_cur_desc; ///< Current RX DMA descriptor that could be linked (set up).
spi_slave_hd_hal_desc_append_t *rx_dma_head; ///< Head of the linked RX DMA descriptors which are not used by hardware
spi_slave_hd_hal_desc_append_t *rx_dma_tail; ///< Tail of the linked RX DMA descriptors which are not used by hardware
spi_slave_hd_hal_desc_append_t rx_dummy_head; ///< Dummy descriptor for ``rx_dma_head`` to start
uint32_t rx_used_desc_cnt; ///< Number of the RX descriptors that have been setup
uint32_t rx_recycled_desc_cnt; ///< Number of the RX descriptors that could be recycled
@@ -129,23 +140,6 @@ typedef struct {
*/
void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_hal_config_t *hal_config);
/**
* @brief Get the size of one DMA descriptor
*
* @param hal Context of the HAL layer
* @param bus_size SPI bus maximum transfer size, in bytes.
* @return Total size needed for all the DMA descriptors
*/
uint32_t spi_slave_hd_hal_get_total_desc_size(spi_slave_hd_hal_context_t *hal, uint32_t bus_size);
/**
* @brief Get the actual bus size
*
* @param hal Context of the HAL layer
* @return Actual bus transaction size
*/
uint32_t spi_salve_hd_hal_get_max_bus_size(spi_slave_hd_hal_context_t *hal);
/**
* @brief Check and clear signal of one event
*
@@ -272,9 +266,10 @@ int spi_slave_hd_hal_get_last_addr(spi_slave_hd_hal_context_t *hal);
*
* @param hal Context of the HAL layer
* @param out_trans Pointer to the caller-defined transaction
* @param real_buff_addr Actually data buffer head the HW used
* @return 1: Transaction is finished; 0: Transaction is not finished
*/
bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans);
bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr);
/**
* @brief Return the finished RX transaction
@@ -285,10 +280,11 @@ bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, voi
*
* @param hal Context of the HAL layer
* @param out_trans Pointer to the caller-defined transaction
* @param real_buff_addr Actually data buffer head the HW used
* @param out_len Actual number of bytes of received data
* @return 1: Transaction is finished; 0: Transaction is not finished
*/
bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, size_t *out_len);
bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr, size_t *out_len);
/**
* @brief Load the TX DMA descriptors without stopping the DMA

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -14,11 +14,13 @@
#include "soc/spi_periph.h"
#include "soc/lldesc.h"
#include "soc/soc_caps.h"
#include "soc/ext_mem_defs.h"
#include "hal/spi_slave_hd_hal.h"
#include "hal/assert.h"
//This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros.
#if SOC_AHB_GDMA_VERSION == 1
#if SOC_GDMA_SUPPORTED
#if (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB) && (SOC_AHB_GDMA_VERSION == 1)
#include "soc/gdma_struct.h"
#include "hal/gdma_ll.h"
#define spi_dma_ll_tx_restart(dev, chan) gdma_ll_tx_restart(&GDMA, chan)
@@ -41,7 +43,31 @@
gdma_ll_tx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
gdma_ll_tx_start(&GDMA, chan);\
} while (0)
#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI)
#include "hal/axi_dma_ll.h"
#define spi_dma_ll_tx_restart(dev, chan) axi_dma_ll_tx_restart(&AXI_DMA, chan)
#define spi_dma_ll_rx_restart(dev, chan) axi_dma_ll_rx_restart(&AXI_DMA, chan)
#define spi_dma_ll_rx_reset(dev, chan) axi_dma_ll_rx_reset_channel(&AXI_DMA, chan)
#define spi_dma_ll_tx_reset(dev, chan) axi_dma_ll_tx_reset_channel(&AXI_DMA, chan)
#define spi_dma_ll_rx_enable_burst_data(dev, chan, enable) axi_dma_ll_rx_enable_data_burst(&AXI_DMA, chan, enable)
#define spi_dma_ll_tx_enable_burst_data(dev, chan, enable) axi_dma_ll_tx_enable_data_burst(&AXI_DMA, chan, enable)
#define spi_dma_ll_rx_enable_burst_desc(dev, chan, enable) axi_dma_ll_rx_enable_descriptor_burst(&AXI_DMA, chan, enable)
#define spi_dma_ll_tx_enable_burst_desc(dev, chan, enable) axi_dma_ll_tx_enable_descriptor_burst(&AXI_DMA, chan, enable)
#define spi_dma_ll_enable_out_auto_wrback(dev, chan, enable) axi_dma_ll_tx_enable_auto_write_back(&AXI_DMA, chan, enable)
#define spi_dma_ll_set_out_eof_generation(dev, chan, enable) axi_dma_ll_tx_set_eof_mode(&AXI_DMA, chan, enable)
#define spi_dma_ll_get_out_eof_desc_addr(dev, chan) axi_dma_ll_tx_get_eof_desc_addr(&AXI_DMA, chan)
#define spi_dma_ll_get_in_suc_eof_desc_addr(dev, chan) axi_dma_ll_rx_get_success_eof_desc_addr(&AXI_DMA, chan)
#define spi_dma_ll_rx_start(dev, chan, addr) do {\
axi_dma_ll_rx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\
axi_dma_ll_rx_start(&AXI_DMA, chan);\
} while (0)
#define spi_dma_ll_tx_start(dev, chan, addr) do {\
axi_dma_ll_tx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\
axi_dma_ll_tx_start(&AXI_DMA, chan);\
} while (0)
#endif
#endif //SOC_GDMA_SUPPORTED
static void s_spi_slave_hd_hal_dma_init_config(const spi_slave_hd_hal_context_t *hal)
{
@@ -63,12 +89,10 @@ void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_h
hal->tx_dma_chan = hal_config->tx_dma_chan;
hal->rx_dma_chan = hal_config->rx_dma_chan;
hal->append_mode = hal_config->append_mode;
hal->rx_cur_desc = hal->dmadesc_rx;
hal->tx_cur_desc = hal->dmadesc_tx;
STAILQ_NEXT(&hal->tx_dummy_head.desc, qe) = &hal->dmadesc_tx->desc;
hal->tx_dma_head = &hal->tx_dummy_head;
STAILQ_NEXT(&hal->rx_dummy_head.desc, qe) = &hal->dmadesc_rx->desc;
hal->rx_dma_head = &hal->rx_dummy_head;
hal->rx_cur_desc = hal->dmadesc_rx;
hal->tx_dma_head = hal->dmadesc_tx + hal->dma_desc_num -1;
hal->rx_dma_head = hal->dmadesc_rx + hal->dma_desc_num -1;
//Configure slave
if (hal_config->dma_enabled) {
@@ -119,26 +143,66 @@ void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_h
spi_ll_slave_set_seg_mode(hal->dev, true);
}
uint32_t spi_salve_hd_hal_get_max_bus_size(spi_slave_hd_hal_context_t *hal)
#if SOC_NON_CACHEABLE_OFFSET
#define ADDR_DMA_2_CPU(addr) ((typeof(addr))((uint32_t)(addr) + 0x40000000))
#define ADDR_CPU_2_DMA(addr) ((typeof(addr))((uint32_t)(addr) - 0x40000000))
#else
#define ADDR_DMA_2_CPU(addr) (addr)
#define ADDR_CPU_2_DMA(addr) (addr)
#endif
static void s_spi_hal_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx)
{
return hal->dma_desc_num * LLDESC_MAX_NUM_PER_DESC;
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);
dmadesc[n].dw0.length = (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 = 1;
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;
}
uint32_t spi_slave_hd_hal_get_total_desc_size(spi_slave_hd_hal_context_t *hal, uint32_t bus_size)
static int s_desc_get_received_len_addr(spi_dma_desc_t* head, spi_dma_desc_t** out_next, void **out_buff_head)
{
//See how many dma descriptors we need
int dma_desc_ct = (bus_size + LLDESC_MAX_NUM_PER_DESC - 1) / LLDESC_MAX_NUM_PER_DESC;
if (dma_desc_ct == 0) {
dma_desc_ct = 1; //default to 4k when max is not given
spi_dma_desc_t* desc_cpu = ADDR_DMA_2_CPU(head);
int len = 0;
if (out_buff_head) {
*out_buff_head = desc_cpu->buffer;
}
hal->dma_desc_num = dma_desc_ct;
return hal->dma_desc_num * sizeof(spi_slave_hd_hal_desc_append_t);
while(head) {
len += desc_cpu->dw0.length;
bool eof = desc_cpu->dw0.suc_eof;
desc_cpu = ADDR_DMA_2_CPU(desc_cpu->next);
head = head->next;
if (eof) break;
}
if (out_next) {
*out_next = head;
}
return len;
}
void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, size_t len)
{
lldesc_setup_link(&hal->dmadesc_rx->desc, out_buf, len, true);
s_spi_hal_dma_desc_setup_link(hal->dmadesc_rx->desc, out_buf, len, true);
spi_ll_dma_rx_fifo_reset(hal->dev);
spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan);
@@ -147,12 +211,12 @@ void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, s
spi_ll_clear_intr(hal->dev, SPI_LL_INTR_CMD7);
spi_ll_dma_rx_enable(hal->dev, 1);
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, &hal->dmadesc_rx->desc);
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, (lldesc_t *)hal->dmadesc_rx->desc);
}
void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len)
{
lldesc_setup_link(&hal->dmadesc_tx->desc, data, len, false);
s_spi_hal_dma_desc_setup_link(hal->dmadesc_tx->desc, data, len, false);
spi_ll_dma_tx_fifo_reset(hal->dev);
spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan);
@@ -161,7 +225,7 @@ void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size
spi_ll_clear_intr(hal->dev, SPI_LL_INTR_CMD8);
spi_ll_dma_tx_enable(hal->dev, 1);
spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, &hal->dmadesc_tx->desc);
spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, (lldesc_t *)hal->dmadesc_tx->desc);
}
static spi_ll_intr_t get_event_intr(spi_slave_hd_hal_context_t *hal, spi_event_t ev)
@@ -257,66 +321,44 @@ int spi_slave_hd_hal_get_rxlen(spi_slave_hd_hal_context_t *hal)
int spi_slave_hd_hal_rxdma_seg_get_len(spi_slave_hd_hal_context_t *hal)
{
lldesc_t *desc = &hal->dmadesc_rx->desc;
return lldesc_get_received_len(desc, NULL);
spi_dma_desc_t *desc = hal->dmadesc_rx->desc;
return s_desc_get_received_len_addr(desc, NULL, NULL);
}
bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans)
bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr)
{
if ((uint32_t)&hal->tx_dma_head->desc == spi_dma_ll_get_out_eof_desc_addr(hal->dma_out, hal->tx_dma_chan)) {
uint32_t desc_now = spi_dma_ll_get_out_eof_desc_addr(hal->dma_out, hal->tx_dma_chan);
if ((uint32_t)hal->tx_dma_head->desc == desc_now) {
return false;
}
hal->tx_dma_head = (spi_slave_hd_hal_desc_append_t *)STAILQ_NEXT(&hal->tx_dma_head->desc, qe);
//find used paired desc-trans by desc addr
hal->tx_dma_head++;
if (hal->tx_dma_head >= hal->dmadesc_tx + hal->dma_desc_num) {
hal->tx_dma_head = hal->dmadesc_tx;
}
*out_trans = hal->tx_dma_head->arg;
s_desc_get_received_len_addr(hal->tx_dma_head->desc, NULL, real_buff_addr);
hal->tx_recycled_desc_cnt++;
return true;
}
bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, size_t *out_len)
bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr, size_t *out_len)
{
if ((uint32_t)&hal->rx_dma_head->desc == spi_dma_ll_get_in_suc_eof_desc_addr(hal->dma_in, hal->rx_dma_chan)) {
uint32_t desc_now = spi_dma_ll_get_in_suc_eof_desc_addr(hal->dma_in, hal->rx_dma_chan);
if ((uint32_t)hal->rx_dma_head->desc == desc_now) {
return false;
}
hal->rx_dma_head = (spi_slave_hd_hal_desc_append_t *)STAILQ_NEXT(&hal->rx_dma_head->desc, qe);
*out_trans = hal->rx_dma_head->arg;
*out_len = hal->rx_dma_head->desc.length;
hal->rx_recycled_desc_cnt++;
return true;
}
static void spi_slave_hd_hal_link_append_desc(spi_slave_hd_hal_desc_append_t *dmadesc, const void *data, int len, bool isrx, void *arg)
{
HAL_ASSERT(len <= LLDESC_MAX_NUM_PER_DESC); //TODO: Add support for transaction with length larger than 4092, IDF-2660
int n = 0;
while (len) {
int dmachunklen = len;
if (dmachunklen > LLDESC_MAX_NUM_PER_DESC) {
dmachunklen = LLDESC_MAX_NUM_PER_DESC;
}
if (isrx) {
//Receive needs DMA length rounded to next 32-bit boundary
dmadesc[n].desc.size = (dmachunklen + 3) & (~3);
dmadesc[n].desc.length = (dmachunklen + 3) & (~3);
} else {
dmadesc[n].desc.size = dmachunklen;
dmadesc[n].desc.length = dmachunklen;
}
dmadesc[n].desc.buf = (uint8_t *)data;
dmadesc[n].desc.eof = 0;
dmadesc[n].desc.sosf = 0;
dmadesc[n].desc.owner = 1;
dmadesc[n].desc.qe.stqe_next = &dmadesc[n + 1].desc;
dmadesc[n].arg = arg;
len -= dmachunklen;
data += dmachunklen;
n++;
//find used paired desc-trans by desc addr
hal->rx_dma_head++;
if (hal->rx_dma_head >= hal->dmadesc_rx + hal->dma_desc_num) {
hal->rx_dma_head = hal->dmadesc_rx;
}
dmadesc[n - 1].desc.eof = 1; //Mark last DMA desc as end of stream.
dmadesc[n - 1].desc.qe.stqe_next = NULL;
*out_trans = hal->rx_dma_head->arg;
*out_len = s_desc_get_received_len_addr(hal->rx_dma_head->desc, NULL, real_buff_addr);
hal->rx_recycled_desc_cnt++;
return true;
}
esp_err_t spi_slave_hd_hal_txdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg)
@@ -329,7 +371,8 @@ esp_err_t spi_slave_hd_hal_txdma_append(spi_slave_hd_hal_context_t *hal, uint8_t
return ESP_ERR_INVALID_STATE;
}
spi_slave_hd_hal_link_append_desc(hal->tx_cur_desc, data, len, false, arg);
s_spi_hal_dma_desc_setup_link(hal->tx_cur_desc->desc, data, len, false);
hal->tx_cur_desc->arg = arg;
if (!hal->tx_dma_started) {
hal->tx_dma_started = true;
@@ -339,10 +382,10 @@ esp_err_t spi_slave_hd_hal_txdma_append(spi_slave_hd_hal_context_t *hal, uint8_t
spi_ll_outfifo_empty_clr(hal->dev);
spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan);
spi_ll_dma_tx_enable(hal->dev, 1);
spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, &hal->tx_cur_desc->desc);
spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, (lldesc_t *)hal->tx_cur_desc->desc);
} else {
//there is already a consecutive link
STAILQ_NEXT(&hal->tx_dma_tail->desc, qe) = &hal->tx_cur_desc->desc;
ADDR_DMA_2_CPU(hal->tx_dma_tail->desc)->next = hal->tx_cur_desc->desc;
hal->tx_dma_tail = hal->tx_cur_desc;
spi_dma_ll_tx_restart(hal->dma_out, hal->tx_dma_chan);
}
@@ -369,7 +412,8 @@ esp_err_t spi_slave_hd_hal_rxdma_append(spi_slave_hd_hal_context_t *hal, uint8_t
return ESP_ERR_INVALID_STATE;
}
spi_slave_hd_hal_link_append_desc(hal->rx_cur_desc, data, len, false, arg);
s_spi_hal_dma_desc_setup_link(hal->rx_cur_desc->desc, data, len, false);
hal->rx_cur_desc->arg = arg;
if (!hal->rx_dma_started) {
hal->rx_dma_started = true;
@@ -379,10 +423,10 @@ esp_err_t spi_slave_hd_hal_rxdma_append(spi_slave_hd_hal_context_t *hal, uint8_t
spi_ll_dma_rx_fifo_reset(hal->dma_in);
spi_ll_infifo_full_clr(hal->dev);
spi_ll_dma_rx_enable(hal->dev, 1);
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, &hal->rx_cur_desc->desc);
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, (lldesc_t *)hal->rx_cur_desc->desc);
} else {
//there is already a consecutive link
STAILQ_NEXT(&hal->rx_dma_tail->desc, qe) = &hal->rx_cur_desc->desc;
ADDR_DMA_2_CPU(hal->rx_dma_tail->desc)->next = hal->rx_cur_desc->desc;
hal->rx_dma_tail = hal->rx_cur_desc;
spi_dma_ll_rx_restart(hal->dma_in, hal->rx_dma_chan);
}

View File

@@ -891,6 +891,10 @@ config SOC_SPI_MAXIMUM_BUFFER_SIZE
int
default 64
config SOC_SPI_SUPPORT_SLAVE_HD_VER2
bool
default y
config SOC_SPI_SLAVE_SUPPORT_SEG_TRANS
bool
default y

View File

@@ -405,7 +405,7 @@
#define SOC_SPI_MAX_CS_NUM 6
#define SOC_SPI_MAXIMUM_BUFFER_SIZE 64
// #define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1 //TODO: IDF-7505
#define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1
#define SOC_SPI_SLAVE_SUPPORT_SEG_TRANS 1
#define SOC_SPI_SUPPORT_DDRCLK 1
#define SOC_SPI_SUPPORT_CD_SIG 1

View File

@@ -106,7 +106,6 @@ api-reference/peripherals/spi_flash/auto_suspend.inc
api-reference/peripherals/sdm.rst
api-reference/peripherals/touch_pad.rst
api-reference/peripherals/adc_calibration.rst
api-reference/peripherals/spi_slave_hd.rst
api-reference/peripherals/parlio.rst
api-reference/peripherals/i2c.rst
api-reference/peripherals/dedic_gpio.rst
@@ -168,7 +167,6 @@ api-reference/protocols/esp_local_ctrl.rst
api-reference/protocols/esp_crt_bundle.rst
api-reference/protocols/esp_http_client.rst
api-reference/protocols/esp_https_server.rst
api-reference/protocols/esp_spi_slave_protocol.rst
api-reference/protocols/modbus.rst
api-reference/protocols/esp_tls.rst
api-reference/protocols/mdns.rst

View File

@@ -14,21 +14,21 @@ ESP SPI Slave HD (Half Duplex) Mode Protocol
SPI Slave Capabilities of Espressif Chips
-----------------------------------------
+------------------+-------+----------+----------+----------+----------+----------+----------+
| | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 | ESP32-C2 | ESP32-C6 | ESP32-H2 |
+------------------+-------+----------+----------+----------+----------+----------+----------+
| SPI Slave HD | N | Y (v2) | Y (v2) | Y (v2) | Y (v2) | Y (v2) | Y (v2) |
+------------------+-------+----------+----------+----------+----------+----------+----------+
| Tohost intr | | N | N | N | N | N | N |
+------------------+-------+----------+----------+----------+----------+----------+----------+
| Frhost intr | | 2 \* | 2 \* | 2 \* | 2 \* | 2 \* | 2 \* |
+------------------+-------+----------+----------+----------+----------+----------+----------+
| TX DMA | | Y | Y | Y | Y | Y | Y |
+------------------+-------+----------+----------+----------+----------+----------+----------+
| RX DMA | | Y | Y | Y | Y | Y | Y |
+------------------+-------+----------+----------+----------+----------+----------+----------+
| Shared registers | | 72 | 64 | 64 | 64 | 64 | 64 |
+------------------+-------+----------+----------+----------+----------+----------+----------+
+------------------+-------+----------+----------+----------+----------+----------+----------+----------+
| | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 | ESP32-C2 | ESP32-C6 | ESP32-H2 | ESP32-P4 |
+------------------+-------+----------+----------+----------+----------+----------+----------+----------+
| SPI Slave HD | N | Y (v2) | Y (v2) | Y (v2) | Y (v2) | Y (v2) | Y (v2) | Y (v2) |
+------------------+-------+----------+----------+----------+----------+----------+----------+----------+
| Tohost intr | | N | N | N | N | N | N | N |
+------------------+-------+----------+----------+----------+----------+----------+----------+----------+
| Frhost intr | | 2 \* | 2 \* | 2 \* | 2 \* | 2 \* | 2 \* | 2 \* |
+------------------+-------+----------+----------+----------+----------+----------+----------+----------+
| TX DMA | | Y | Y | Y | Y | Y | Y | Y |
+------------------+-------+----------+----------+----------+----------+----------+----------+----------+
| RX DMA | | Y | Y | Y | Y | Y | Y | Y |
+------------------+-------+----------+----------+----------+----------+----------+----------+----------+
| Shared registers | | 72 | 64 | 64 | 64 | 64 | 64 | 64 |
+------------------+-------+----------+----------+----------+----------+----------+----------+----------+
Introduction
------------

View File

@@ -267,29 +267,19 @@ examples/peripherals/spi_slave:
examples/peripherals/spi_slave_hd/append_mode/master:
disable:
- if: IDF_TARGET in ["esp32c6", "esp32p4"]
temporary: true
reason: target(s) not supported yet # TODO: IDF-7505
- if: SOC_GPSPI_SUPPORTED != 1 or SOC_SPI_SUPPORT_SLAVE_HD_VER2 != 1
examples/peripherals/spi_slave_hd/append_mode/slave:
enable:
- if: IDF_TARGET == "esp32s2"
temporary: true
reason: the other targets are not tested yet
disable:
- if: SOC_GPSPI_SUPPORTED != 1 or SOC_SPI_SUPPORT_SLAVE_HD_VER2 != 1
examples/peripherals/spi_slave_hd/segment_mode/seg_master:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
- if: IDF_TARGET in ["esp32p4"]
temporary: true
reason: target(s) is not supported yet # TODO: IDF-7505 slave hd support
- if: SOC_GPSPI_SUPPORTED != 1 or SOC_SPI_SUPPORT_SLAVE_HD_VER2 != 1
examples/peripherals/spi_slave_hd/segment_mode/seg_slave:
disable:
- if: IDF_TARGET == "esp32" or SOC_GPSPI_SUPPORTED != 1
- if: IDF_TARGET in ["esp32p4"]
temporary: true
reason: target(s) is not supported yet # TODO: IDF-7505 slave hd support
- if: SOC_GPSPI_SUPPORTED != 1 or SOC_SPI_SUPPORT_SLAVE_HD_VER2 != 1
examples/peripherals/temperature_sensor/temp_sensor:
disable:

View File

@@ -1,4 +1,4 @@
# SPI Halfduplex Slave Append Mode Example
# SPI Slave Halfduplex: Append Mode Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)

View File

@@ -1,4 +1,4 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
See README.md in the parent directory

View File

@@ -15,18 +15,13 @@
#include "esp_serial_slave_link/essl.h"
#include "esp_serial_slave_link/essl_spi.h"
#ifdef CONFIG_IDF_TARGET_ESP32H2
#define GPIO_MOSI 5
#define GPIO_MISO 0
#define GPIO_SCLK 4
#define GPIO_CS 1
#else
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// Please update the following configuration according to your Hardware spec /////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
#define GPIO_MOSI 11
#define GPIO_MISO 13
#define GPIO_SCLK 12
#define GPIO_CS 10
#endif
#define HOST_ID SPI2_HOST
#define TRANSACTION_LEN 16

View File

@@ -1,4 +1,4 @@
| Supported Targets | ESP32-S2 |
| ----------------- | -------- |
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
See README.md in the parent directory

View File

@@ -15,11 +15,15 @@
#include "freertos/semphr.h"
#include "driver/spi_slave_hd.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// Please update the following configuration according to your Hardware spec /////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
#define GPIO_MOSI 11
#define GPIO_MISO 13
#define GPIO_SCLK 12
#define GPIO_CS 10
#define HOST_ID 1
#define HOST_ID SPI2_HOST
#define QUEUE_SIZE 6
#define TRANSACTION_LEN 16
#define SYNC_REG_FROM_HOST (14 * 4)

View File

@@ -10,7 +10,7 @@ These two projects illustrate the SPI Slave Halfduplex Segment Mode.
### Hardware Required
These two projects are supposed to be flashed onto two seperate boards and jumped together via correctly connected SPI pins defined in both of the ``app_main.c`` files. For the ``seg_master`` project, it could be flashed onto all the ESP Chips. Whereas the ``seg_slave`` currently could be flashed onto ESP32-S2. Once they are connected and flashed, they will use the SPI Master and SPI Slave Halfduplex drivers to communicate with each other.
These two projects are supposed to be flashed onto two seperate boards and jumped together via correctly connected SPI pins defined in both of the ``app_main.c`` files. Once they are connected and flashed, they will use the SPI Master and SPI Slave Halfduplex drivers to communicate with each other.
Following is the connection between 2 ESP32S2 boards:
@@ -21,8 +21,7 @@ Following is the connection between 2 ESP32S2 boards:
| SCLK | GPIO12 | GPIO12 |
| CS | GPIO10 | GPIO10 |
Plase refer to the macro definations at the top of ``app_main.c`` files, to know the connection on different chips.
Feel free to change the GPIO settings by editing the macro definations.
Feel free to change the GPIO settings by editing the macro definations on the top of the ``app_main.c``
### Build and Flash

View File

@@ -1,4 +1,4 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
See README.md in the parent directory

View File

@@ -14,34 +14,15 @@
#include "driver/spi_master.h"
#include "esp_serial_slave_link/essl_spi.h"
//Pin setting
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// Please update the following configuration according to your Hardware spec /////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
#define GPIO_MOSI 11
#define GPIO_MISO 13
#define GPIO_SCLK 12
#define GPIO_CS 10
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2
#define GPIO_MOSI 7
#define GPIO_MISO 2
#define GPIO_SCLK 6
#define GPIO_CS 10
#elif CONFIG_IDF_TARGET_ESP32C6
#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
#endif
#define MASTER_HOST SPI2_HOST
#define MASTER_HOST SPI2_HOST
#define DMA_CHAN SPI_DMA_CH_AUTO
#define TX_SIZE_MIN 40

View File

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

View File

@@ -15,33 +15,14 @@
#define TIME_IS_OUT(start, end, timeout) (timeout) > ((end)-(start)) ? 0 : 1
//Pin setting
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// Please update the following configuration according to your Hardware spec /////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
#define GPIO_MOSI 11
#define GPIO_MISO 13
#define GPIO_SCLK 12
#define GPIO_CS 10
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2
#define GPIO_MOSI 7
#define GPIO_MISO 2
#define GPIO_SCLK 6
#define GPIO_CS 10
#elif CONFIG_IDF_TARGET_ESP32C6
#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
#endif
#define SLAVE_HOST SPI2_HOST
#define DMA_CHAN SPI_DMA_CH_AUTO
#define QUEUE_SIZE 4