diff --git a/components/driver/include/esp_private/spi_common_internal.h b/components/driver/include/esp_private/spi_common_internal.h index 6cc711b522..38f0f00500 100644 --- a/components/driver/include/esp_private/spi_common_internal.h +++ b/components/driver/include/esp_private/spi_common_internal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,7 @@ #include "driver/spi_common.h" #include "freertos/FreeRTOS.h" #include "hal/spi_types.h" +#include "hal/dma_types.h" #include "esp_pm.h" #if SOC_GDMA_SUPPORTED #include "esp_private/gdma.h" @@ -45,6 +46,13 @@ extern "C" #define BUS_LOCK_DEBUG_EXECUTE_CHECK(x) #endif +#if SOC_GPSPI_SUPPORTED && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) +#define DMA_DESC_MEM_ALIGN_SIZE 8 +typedef dma_descriptor_align8_t spi_dma_desc_t; +#else +#define DMA_DESC_MEM_ALIGN_SIZE 4 +typedef dma_descriptor_align4_t spi_dma_desc_t; +#endif struct spi_bus_lock_t; struct spi_bus_lock_dev_t; @@ -56,22 +64,21 @@ typedef struct spi_bus_lock_dev_t* spi_bus_lock_dev_handle_t; /// Background operation control function typedef void (*bg_ctrl_func_t)(void*); -typedef struct lldesc_s lldesc_t; - /// Attributes of an SPI bus typedef struct { - spi_bus_config_t bus_cfg; ///< Config used to initialize the bus - uint32_t flags; ///< Flags (attributes) of the bus - int max_transfer_sz; ///< Maximum length of bytes available to send - bool dma_enabled; ///< To enable DMA or not - int tx_dma_chan; ///< TX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same - int rx_dma_chan; ///< RX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same - int dma_desc_num; ///< DMA descriptor number of dmadesc_tx or dmadesc_rx. - lldesc_t *dmadesc_tx; ///< DMA descriptor array for TX - lldesc_t *dmadesc_rx; ///< DMA descriptor array for RX + spi_bus_config_t bus_cfg; ///< Config used to initialize the bus + uint32_t flags; ///< Flags (attributes) of the bus + int max_transfer_sz; ///< Maximum length of bytes available to send + bool dma_enabled; ///< To enable DMA or not + uint16_t internal_mem_align_size; ///< Buffer align byte requirement for internal memory + int tx_dma_chan; ///< TX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same + int rx_dma_chan; ///< RX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same + int dma_desc_num; ///< DMA descriptor number of dmadesc_tx or dmadesc_rx. + spi_dma_desc_t *dmadesc_tx; ///< DMA descriptor array for TX + spi_dma_desc_t *dmadesc_rx; ///< DMA descriptor array for RX spi_bus_lock_handle_t lock; #ifdef CONFIG_PM_ENABLE - esp_pm_lock_handle_t pm_lock; ///< Power management lock + esp_pm_lock_handle_t pm_lock; ///< Power management lock #endif } spi_bus_attr_t; diff --git a/components/driver/spi/gpspi/spi_common.c b/components/driver/spi/gpspi/spi_common.c index f8fb9af13d..72a2ab3a77 100644 --- a/components/driver/spi/gpspi/spi_common.c +++ b/components/driver/spi/gpspi/spi_common.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,7 +13,6 @@ #include "esp_check.h" #include "esp_rom_gpio.h" #include "esp_heap_caps.h" -#include "soc/lldesc.h" #include "soc/spi_periph.h" #include "driver/gpio.h" #include "driver/spi_master.h" @@ -26,6 +25,14 @@ #endif #if SOC_GDMA_SUPPORTED #include "esp_private/gdma.h" +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" +#endif + +#if SOC_PERIPH_CLK_CTRL_SHARED +#define SPI_COMMON_RCC_CLOCK_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define SPI_COMMON_RCC_CLOCK_ATOMIC() #endif static const char *SPI_TAG = "spi"; @@ -100,7 +107,15 @@ bool spicommon_periph_claim(spi_host_device_t host, const char* source) bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &false_var, true); if (ret) { spi_claiming_func[host] = source; +#if CONFIG_IDF_TARGET_ESP32P4 //deprecate clk_gate_ll start from p4, others in TODO: IDF-8159 + SPI_COMMON_RCC_CLOCK_ATOMIC() { + spi_ll_enable_bus_clock(host, true); + spi_ll_reset_register(host); + spi_ll_enable_clock(host, true); + } +#else periph_module_enable(spi_periph_signal[host].module); +#endif } else { ESP_EARLY_LOGE(SPI_TAG, "SPI%d already claimed by %s.", host+1, spi_claiming_func[host]); } @@ -117,7 +132,15 @@ bool spicommon_periph_free(spi_host_device_t host) { bool true_var = true; bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &true_var, false); - if (ret) periph_module_disable(spi_periph_signal[host].module); + if (ret) { +#if CONFIG_IDF_TARGET_ESP32P4 + SPI_COMMON_RCC_CLOCK_ATOMIC() { + spi_ll_enable_bus_clock(host, false); + } +#else + periph_module_disable(spi_periph_signal[host].module); +#endif + } return ret; } @@ -218,6 +241,12 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch } #else //SOC_GDMA_SUPPORTED + +#if (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB) +static esp_err_t (*spi_gdma_chan_allocator)(const gdma_channel_alloc_config_t *, gdma_channel_handle_t *) = gdma_new_ahb_channel; +#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) +static esp_err_t (*spi_gdma_chan_allocator)(const gdma_channel_alloc_config_t *, gdma_channel_handle_t *) = gdma_new_axi_channel; +#endif static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan) { assert(is_valid_host(host_id)); @@ -231,19 +260,13 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch .flags.reserve_sibling = 1, .direction = GDMA_CHANNEL_DIRECTION_TX, }; - ret = gdma_new_channel(&tx_alloc_config, &ctx->tx_channel); - if (ret != ESP_OK) { - return ret; - } + ESP_RETURN_ON_ERROR(spi_gdma_chan_allocator(&tx_alloc_config, &ctx->tx_channel), SPI_TAG, "alloc gdma tx failed"); gdma_channel_alloc_config_t rx_alloc_config = { .direction = GDMA_CHANNEL_DIRECTION_RX, .sibling_chan = ctx->tx_channel, }; - ret = gdma_new_channel(&rx_alloc_config, &ctx->rx_channel); - if (ret != ESP_OK) { - return ret; - } + ESP_RETURN_ON_ERROR(spi_gdma_chan_allocator(&rx_alloc_config, &ctx->rx_channel), SPI_TAG, "alloc gdma rx failed"); if (host_id == SPI2_HOST) { gdma_connect(ctx->rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 2)); @@ -802,17 +825,22 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t * bus_attr->tx_dma_chan = actual_tx_dma_chan; bus_attr->rx_dma_chan = actual_rx_dma_chan; - int dma_desc_ct = lldesc_get_required_num(bus_config->max_transfer_sz); + 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 - bus_attr->max_transfer_sz = dma_desc_ct * LLDESC_MAX_NUM_PER_DESC; - bus_attr->dmadesc_tx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA); - bus_attr->dmadesc_rx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA); + bus_attr->max_transfer_sz = dma_desc_ct * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; + bus_attr->dmadesc_tx = heap_caps_aligned_alloc(DMA_DESC_MEM_ALIGN_SIZE, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA); + bus_attr->dmadesc_rx = heap_caps_aligned_alloc(DMA_DESC_MEM_ALIGN_SIZE, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA); if (bus_attr->dmadesc_tx == NULL || bus_attr->dmadesc_rx == NULL) { err = ESP_ERR_NO_MEM; goto cleanup; } bus_attr->dma_desc_num = dma_desc_ct; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + bus_attr->internal_mem_align_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); +#else + bus_attr->internal_mem_align_size = 4; +#endif } else { bus_attr->dma_enabled = 0; bus_attr->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE; diff --git a/components/driver/spi/gpspi/spi_master.c b/components/driver/spi/gpspi/spi_master.c index a3178346f7..0a47c4bddc 100644 --- a/components/driver/spi/gpspi/spi_master.c +++ b/components/driver/spi/gpspi/spi_master.c @@ -112,6 +112,7 @@ We have two bits to control the interrupt: #include #include +#include "esp_private/periph_ctrl.h" #include "esp_private/spi_common_internal.h" #include "driver/spi_master.h" #include "esp_clk_tree.h" @@ -126,6 +127,9 @@ We have two bits to control the interrupt: #include "hal/spi_hal.h" #include "hal/spi_ll.h" #include "esp_heap_caps.h" +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#include "esp_cache.h" +#endif typedef struct spi_device_t spi_device_t; @@ -172,6 +176,11 @@ static spi_host_t* bus_driver_ctx[SOC_SPI_PERIPH_NUM] = {}; static const char *SPI_TAG = "spi_master"; #define SPI_CHECK(a, str, ret_val) ESP_RETURN_ON_FALSE_ISR(a, ret_val, SPI_TAG, str) +#if SOC_PERIPH_CLK_CTRL_SHARED +#define SPI_MASTER_RCC_CLOCK_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define SPI_MASTER_RCC_CLOCK_ATOMIC() +#endif static void spi_intr(void *arg); static void spi_bus_intr_enable(void *host); @@ -547,6 +556,9 @@ static SPI_MASTER_ISR_ATTR void spi_setup_device(spi_device_t *dev) if (spi_bus_lock_touch(dev_lock)) { /* Configuration has not been applied yet. */ spi_hal_setup_device(hal, hal_dev); + SPI_MASTER_RCC_CLOCK_ATOMIC() { + spi_ll_set_clk_source(hal->hw, hal_dev->timing_conf.clock_source); + } } } @@ -680,13 +692,24 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg) const int cs = host->cur_cs; //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset. -#if CONFIG_IDF_TARGET_ESP32 if (bus_attr->dma_enabled) { +#if CONFIG_IDF_TARGET_ESP32 //This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same spicommon_dmaworkaround_idle(bus_attr->tx_dma_chan); - } #endif //#if CONFIG_IDF_TARGET_ESP32 +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE //invalidate here to let user access rx data in post_cb if possible + if (host->cur_trans_buf.buffer_to_rcv) { + uint16_t alignment = bus_attr->internal_mem_align_size; + uint32_t buffer_byte_len = (host->cur_trans_buf.trans->rxlength + 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_buf.buffer_to_rcv, buffer_byte_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + assert(ret == ESP_OK); + } +#endif + } + //cur_cs is changed to DEV_NUM_MAX here spi_post_trans(host); @@ -824,9 +847,7 @@ static SPI_MASTER_ISR_ATTR void uninstall_priv_desc(spi_trans_priv_t* trans_buf) free((void *)trans_buf->buffer_to_send); //force free, ignore const } // copy data from temporary DMA-capable buffer back to IRAM buffer and free the temporary one. - if (trans_buf->buffer_to_rcv && - (void *)trans_buf->buffer_to_rcv != &trans_desc->rx_data[0] && - trans_buf->buffer_to_rcv != trans_desc->rx_buffer) { // NOLINT(clang-analyzer-unix.Malloc) + if (trans_buf->buffer_to_rcv && (void *)trans_buf->buffer_to_rcv != &trans_desc->rx_data[0] && trans_buf->buffer_to_rcv != trans_desc->rx_buffer) { // NOLINT(clang-analyzer-unix.Malloc) if (trans_desc->flags & SPI_TRANS_USE_RXDATA) { memcpy((uint8_t *) & trans_desc->rx_data[0], trans_buf->buffer_to_rcv, (trans_desc->rxlength + 7) / 8); } else { @@ -836,9 +857,11 @@ static SPI_MASTER_ISR_ATTR void uninstall_priv_desc(spi_trans_priv_t* trans_buf) } } -static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_transaction_t *trans_desc, spi_trans_priv_t* new_desc, bool isdma) +static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_host_t *host, spi_trans_priv_t* priv_desc) { - *new_desc = (spi_trans_priv_t) { .trans = trans_desc, }; + spi_transaction_t *trans_desc = priv_desc->trans; + const spi_bus_attr_t *bus_attr = host->bus_attr; + uint16_t alignment = bus_attr->internal_mem_align_size; // rx memory assign uint32_t* rcv_ptr; @@ -848,13 +871,6 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_transaction_t *trans_de //if not use RXDATA neither rx_buffer, buffer_to_rcv assigned to NULL rcv_ptr = trans_desc->rx_buffer; } - if (rcv_ptr && isdma && (!esp_ptr_dma_capable(rcv_ptr) || ((int)rcv_ptr % 4 != 0))) { - //if rxbuf in the desc not DMA-capable, malloc a new one. The rx buffer need to be length of multiples of 32 bits to avoid heap corruption. - ESP_LOGD(SPI_TAG, "Allocate RX buffer for DMA" ); - rcv_ptr = heap_caps_malloc(((trans_desc->rxlength + 31) / 32) * 4, MALLOC_CAP_DMA); - if (rcv_ptr == NULL) goto clean_up; - } - new_desc->buffer_to_rcv = rcv_ptr; // tx memory assign const uint32_t *send_ptr; @@ -864,21 +880,53 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_transaction_t *trans_de //if not use TXDATA neither tx_buffer, tx data assigned to NULL send_ptr = trans_desc->tx_buffer ; } - if (send_ptr && isdma && !esp_ptr_dma_capable( send_ptr )) { - //if txbuf in the desc not DMA-capable, malloc a new one - ESP_LOGD(SPI_TAG, "Allocate TX buffer for DMA" ); - uint32_t *temp = heap_caps_malloc((trans_desc->length + 7) / 8, MALLOC_CAP_DMA); - if (temp == NULL) goto clean_up; - memcpy( temp, send_ptr, (trans_desc->length + 7) / 8 ); - send_ptr = temp; + 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)); +#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)); +#endif + + if (send_ptr && bus_attr->dma_enabled) { + if ((!esp_ptr_dma_capable(send_ptr) || tx_un_align )) { + 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" ); + tx_byte_len = (tx_byte_len + alignment - 1) & (~(alignment - 1)); // up align alignment + uint32_t *temp = heap_caps_aligned_alloc(alignment, tx_byte_len, MALLOC_CAP_DMA); + if (temp == NULL) { + goto clean_up; + } + + memcpy( temp, send_ptr, (trans_desc->length + 7) / 8 ); + send_ptr = temp; + } +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_err_t ret = esp_cache_msync((void *)send_ptr, tx_byte_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + assert(ret == ESP_OK); +#endif } - new_desc->buffer_to_send = send_ptr; + if (rcv_ptr && bus_attr->dma_enabled && (!esp_ptr_dma_capable(rcv_ptr) || rx_un_align )) { + 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" ); + rx_byte_len = (rx_byte_len + alignment - 1) & (~(alignment - 1)); // up align alignment + rcv_ptr = heap_caps_aligned_alloc(alignment, rx_byte_len, MALLOC_CAP_DMA); + if (rcv_ptr == NULL) { + goto clean_up; + } + } + priv_desc->buffer_to_send = send_ptr; + priv_desc->buffer_to_rcv = rcv_ptr; return ESP_OK; clean_up: - uninstall_priv_desc(new_desc); + uninstall_priv_desc(priv_desc); return ESP_ERR_NO_MEM; } @@ -897,8 +945,8 @@ esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi return ESP_ERR_INVALID_ARG; } - spi_trans_priv_t trans_buf; - ret = setup_priv_desc(trans_desc, &trans_buf, (host->bus_attr->dma_enabled)); + spi_trans_priv_t trans_buf = { .trans = trans_desc, }; + ret = setup_priv_desc(host, &trans_buf); if (ret != ESP_OK) return ret; #ifdef CONFIG_PM_ENABLE @@ -935,6 +983,7 @@ esp_err_t SPI_MASTER_ATTR spi_device_get_trans_result(spi_device_handle_t handle BaseType_t r; spi_trans_priv_t trans_buf; SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG); + bool use_dma = handle->host->bus_attr->dma_enabled; //if SPI_DEVICE_NO_RETURN_RESULT is set, ret_queue will always be empty SPI_CHECK(!(handle->cfg.flags & SPI_DEVICE_NO_RETURN_RESULT), "API not Supported!", ESP_ERR_NOT_SUPPORTED); @@ -947,8 +996,10 @@ esp_err_t SPI_MASTER_ATTR spi_device_get_trans_result(spi_device_handle_t handle // Every in-flight transaction request occupies internal memory as DMA buffer if needed. return ESP_ERR_TIMEOUT; } - //release temporary buffers - uninstall_priv_desc(&trans_buf); + //release temporary buffers used by dma + if (use_dma) { + uninstall_priv_desc(&trans_buf); + } (*trans_desc) = trans_buf.trans; return ESP_OK; @@ -1043,8 +1094,8 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_start(spi_device_handle_t handl SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot send polling transaction while the previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE ); spi_host_t *host = handle->host; - spi_trans_priv_t priv_polling_trans; - ret = setup_priv_desc(trans_desc, &priv_polling_trans, (host->bus_attr->dma_enabled)); + spi_trans_priv_t priv_polling_trans = { .trans = trans_desc, }; + ret = setup_priv_desc(host, &priv_polling_trans); if (ret!=ESP_OK) return ret; /* If device_acquiring_lock is set to handle, it means that the user has already @@ -1065,6 +1116,7 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_start(spi_device_handle_t handl ESP_LOGE(SPI_TAG, "polling can't get buslock"); return ret; } + //After holding the buslock, common resource can be accessed !! //Polling, no interrupt is used. host->polling = true; diff --git a/components/driver/spi/gpspi/spi_slave.c b/components/driver/spi/gpspi/spi_slave.c index 1991b56a35..af9ca699d9 100644 --- a/components/driver/spi/gpspi/spi_slave.c +++ b/components/driver/spi/gpspi/spi_slave.c @@ -163,6 +163,9 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b 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 ret = spicommon_dma_chan_alloc(host, dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan); if (ret != ESP_OK) { goto cleanup; diff --git a/components/driver/spi/include/driver/spi_master.h b/components/driver/spi/include/driver/spi_master.h index d5c6bcbc59..305d6beadd 100644 --- a/components/driver/spi/include/driver/spi_master.h +++ b/components/driver/spi/include/driver/spi_master.h @@ -115,6 +115,7 @@ typedef struct { #define SPI_TRANS_MULTILINE_CMD (1<<9) ///< The data lines used at command phase is the same as data phase (otherwise, only one data line is used at command phase) #define SPI_TRANS_MODE_OCT (1<<10) ///< Transmit/receive data in 8-bit mode #define SPI_TRANS_MULTILINE_ADDR SPI_TRANS_MODE_DIOQIO_ADDR ///< The data lines used at address phase is the same as data phase (otherwise, only one data line is used at address phase) +#define SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL (1<<11) ///< By default driver will automatically re-alloc dma buffer if it doesn't meet hardware alignment or dma_capable requirements, this flag is for you to disable this feature, you will need to take care of the alignment otherwise driver will return you error ESP_ERR_INVALID_ARG /** * This structure describes one SPI transaction. The descriptor should not be modified until the transaction finishes. @@ -208,6 +209,7 @@ esp_err_t spi_bus_remove_device(spi_device_handle_t handle); * @return * - ESP_ERR_INVALID_ARG if parameter is invalid. This can happen if SPI_TRANS_CS_KEEP_ACTIVE flag is specified while * the bus was not acquired (`spi_device_acquire_bus()` should be called first) + * or set flag SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL but tx or rx buffer not DMA-capable, or addr&len not align to cache line size * - ESP_ERR_TIMEOUT if there was no room in the queue before ticks_to_wait expired * - ESP_ERR_NO_MEM if allocating DMA-capable temporary buffer failed * - ESP_ERR_INVALID_STATE if previous transactions are not finished @@ -273,6 +275,7 @@ esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *tra * @return * - ESP_ERR_INVALID_ARG if parameter is invalid. This can happen if SPI_TRANS_CS_KEEP_ACTIVE flag is specified while * the bus was not acquired (`spi_device_acquire_bus()` should be called first) + * or set flag SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL but tx or rx buffer not DMA-capable, or addr&len not align to cache line size * - ESP_ERR_TIMEOUT if the device cannot get control of the bus before ``ticks_to_wait`` expired * - ESP_ERR_NO_MEM if allocating DMA-capable temporary buffer failed * - ESP_ERR_INVALID_STATE if previous transactions are not finished diff --git a/components/driver/test_apps/.build-test-rules.yml b/components/driver/test_apps/.build-test-rules.yml index b1fd554b0c..ee1ae4391f 100644 --- a/components/driver/test_apps/.build-test-rules.yml +++ b/components/driver/test_apps/.build-test-rules.yml @@ -146,10 +146,21 @@ 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-7503 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: + - if: SOC_GPSPI_SUPPORTED != 1 + - if: SOC_SPI_SUPPORT_SLAVE_HD_VER2 != 1 components/driver/test_apps/temperature_sensor: disable: diff --git a/components/driver/test_apps/components/test_driver_utils/include/test_spi_utils.h b/components/driver/test_apps/components/test_driver_utils/include/test_spi_utils.h index 0a88227dde..c27ce19dee 100644 --- a/components/driver/test_apps/components/test_driver_utils/include/test_spi_utils.h +++ b/components/driver/test_apps/components/test_driver_utils/include/test_spi_utils.h @@ -76,7 +76,7 @@ #define ESP_SPI_SLAVE_TV (12.5*3.5) #define WIRE_DELAY 12.5 -#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4 #define SLAVE_IOMUX_PIN_MISO -1 #define SLAVE_IOMUX_PIN_MOSI -1 #define SLAVE_IOMUX_PIN_SCLK -1 diff --git a/components/driver/test_apps/spi/master/README.md b/components/driver/test_apps/spi/master/README.md index 07b81b7c84..5b39ff9653 100644 --- a/components/driver/test_apps/spi/master/README.md +++ b/components/driver/test_apps/spi/master/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | \ No newline at end of file +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | \ No newline at end of file diff --git a/components/driver/test_apps/spi/master/main/test_app_main.c b/components/driver/test_apps/spi/master/main/test_app_main.c index f202bf7b7b..16ba4072f3 100644 --- a/components/driver/test_apps/spi/master/main/test_app_main.c +++ b/components/driver/test_apps/spi/master/main/test_app_main.c @@ -11,23 +11,15 @@ // iterator to load partition tables in `test spi bus lock, with flash` will lead memory not free #define TEST_MEMORY_LEAK_THRESHOLD (350) -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) diff --git a/components/driver/test_apps/spi/master/main/test_spi_master.c b/components/driver/test_apps/spi/master/main/test_spi_master.c index fb31bb12ce..4904d3a824 100644 --- a/components/driver/test_apps/spi/master/main/test_spi_master.c +++ b/components/driver/test_apps/spi/master/main/test_spi_master.c @@ -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 */ @@ -287,8 +287,8 @@ TEST_CASE("SPI Master test", "[spi]") success &= spi_test(handle, 4096 - 2); //multiple descs, edge case 1 success &= spi_test(handle, 4096 - 1); //multiple descs, edge case 2 success &= spi_test(handle, 4096 * 3); //multiple descs - master_free_device_bus(handle); + TEST_ASSERT(success); printf("Testing bus at 80KHz, non-DMA\n"); handle = setup_spi_bus_loopback(80000, false); @@ -299,19 +299,18 @@ TEST_CASE("SPI Master test", "[spi]") success &= spi_test(handle, 47); //small, unaligned success &= spi_test(handle, 63); //small success &= spi_test(handle, 64); //small, unaligned - master_free_device_bus(handle); + TEST_ASSERT(success); - printf("Testing bus at 26MHz\n"); + printf("Testing bus at 20MHz\n"); handle = setup_spi_bus_loopback(20000000, true); - success &= spi_test(handle, 128); //DMA, aligned success &= spi_test(handle, 4096 * 3); //DMA, multiple descs master_free_device_bus(handle); + TEST_ASSERT(success); printf("Testing bus at 900KHz\n"); handle = setup_spi_bus_loopback(9000000, true); - success &= spi_test(handle, 128); //DMA, aligned success &= spi_test(handle, 4096 * 3); //DMA, multiple descs master_free_device_bus(handle); @@ -790,11 +789,8 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]") //connect MOSI to two devices breaks the output, fix it. spitest_gpio_output_sel(buscfg.mosi_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_out); - memset(rx_buf, 0x66, 320); - for ( int i = 0; i < 8; i ++ ) { memset( rx_buf, 0x66, sizeof(rx_buf)); - spi_transaction_t t = {}; t.length = 8 * (i + 1); t.rxlength = 0; @@ -881,12 +877,12 @@ void test_cmd_addr(spi_slave_task_context_t *slave_context, bool lsb_first) vTaskDelay(50); //prepare master tx data int cmd_bits = (i + 1) * 2; - int addr_bits = + int addr_bits = 0; #ifdef CONFIG_IDF_TARGET_ESP32 - 56 - 8 * i; + addr_bits = 56 - 8 * i; #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 //ESP32S2 only supportes up to 32 bits address - 28 - 4 * i; + addr_bits = 28 - 4 * i; #endif int round_up = (cmd_bits + addr_bits + 7) / 8 * 8; addr_bits = round_up - cmd_bits; @@ -1073,6 +1069,7 @@ 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. @@ -1161,8 +1158,10 @@ 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 @@ -1338,6 +1337,7 @@ 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,6 +1491,7 @@ 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 @@ -1601,7 +1602,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) @@ -1661,8 +1662,8 @@ 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) { @@ -1767,3 +1768,4 @@ 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 diff --git a/components/driver/test_apps/spi/master/main/test_spi_sio.c b/components/driver/test_apps/spi/master/main/test_spi_sio.c index 02cd852fc8..49de330445 100644 --- a/components/driver/test_apps/spi/master/main/test_spi_sio.c +++ b/components/driver/test_apps/spi/master/main/test_spi_sio.c @@ -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 */ @@ -37,6 +37,8 @@ ********************************************************************************/ #if CONFIG_IDF_TARGET_ESP32 #define MASTER_DIN_SIGNAL HSPID_IN_IDX +#elif CONFIG_IDF_TARGET_ESP32P4 +#define MASTER_DIN_SIGNAL SPI2_D_PAD_IN_IDX #else #define MASTER_DIN_SIGNAL FSPID_IN_IDX #endif @@ -142,7 +144,7 @@ TEST_CASE("SPI Single Board Test SIO", "[spi]") } #endif //#if (TEST_SPI_PERIPH_NUM >= 2) - +#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4) //IDF-7503 slave support /******************************************************************************** * Test SIO Master * SIO Slave is not suported, and one unit test is limited to one feature, so,,, @@ -326,3 +328,4 @@ void test_slave_run(void) } TEST_CASE_MULTIPLE_DEVICES("SPI_Master:Test_SIO_Mode_Multi_Board", "[spi_ms][test_env=generic_multi_device]", test_master_run, test_slave_run); +#endif //p4 slave support diff --git a/components/driver/test_apps/spi/slave_hd/README.md b/components/driver/test_apps/spi/slave_hd/README.md index 5b39ff9653..e958430328 100644 --- a/components/driver/test_apps/spi/slave_hd/README.md +++ b/components/driver/test_apps/spi/slave_hd/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | \ No newline at end of file +| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- | \ No newline at end of file diff --git a/components/driver/test_apps/spi/slave_hd/pytest_spi_slave_hd.py b/components/driver/test_apps/spi/slave_hd/pytest_spi_slave_hd.py index b2202856d2..054c842dd9 100644 --- a/components/driver/test_apps/spi/slave_hd/pytest_spi_slave_hd.py +++ b/components/driver/test_apps/spi/slave_hd/pytest_spi_slave_hd.py @@ -5,7 +5,11 @@ import pytest # If `test_env` is define, should not run on generic runner -@pytest.mark.supported_targets +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +@pytest.mark.esp32c2 +@pytest.mark.esp32c3 +@pytest.mark.esp32c6 @pytest.mark.esp32h2 @pytest.mark.generic def test_slave_hd_single_dev(case_tester) -> None: # type: ignore @@ -16,7 +20,11 @@ def test_slave_hd_single_dev(case_tester) -> None: # type: ignore # if `test_env` not defined, will run on `generic_multi_device` by default -@pytest.mark.supported_targets +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +@pytest.mark.esp32c2 +@pytest.mark.esp32c3 +@pytest.mark.esp32c6 @pytest.mark.esp32h2 @pytest.mark.generic_multi_device @pytest.mark.parametrize('count', [2,], indirect=True) diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/README.md b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/README.md index a8b7833fa3..bf47d80ec6 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/README.md +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/README.md @@ -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 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_intr_alloc.c b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_intr_alloc.c index daf1cd36b5..2953b6de7c 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_intr_alloc.c +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_intr_alloc.c @@ -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 */ @@ -127,7 +127,11 @@ void static test_isr(void*arg) TEST_CASE("Allocate previously freed interrupt, with different flags", "[intr_alloc]") { intr_handle_t intr; +#if CONFIG_IDF_TARGET_ESP32P4 + int test_intr_source = ETS_GPIO_INTR0_SOURCE; +#else int test_intr_source = ETS_GPIO_INTR_SOURCE; +#endif int isr_flags = ESP_INTR_FLAG_LEVEL2; TEST_ESP_OK(esp_intr_alloc(test_intr_source, isr_flags, test_isr, NULL, &intr)); @@ -179,7 +183,15 @@ TEST_CASE("allocate 2 handlers for a same source and remove the later one", "[in intr_handle_t handle1, handle2; // enable SPI2 +#if CONFIG_IDF_TARGET_ESP32P4 //deprecate clk_gate_ll start from p4, others in TODO: IDF-8159 + PERIPH_RCC_ATOMIC() { + spi_ll_enable_bus_clock(1, true); + spi_ll_reset_register(1); + spi_ll_enable_clock(1, true); + } +#else periph_module_enable(spi_periph_signal[1].module); +#endif esp_err_t r; r = esp_intr_alloc(spi_periph_signal[1].irq, ESP_INTR_FLAG_SHARED, int_handler1, &ctx, &handle1); diff --git a/components/esp_lcd/test_apps/spi_lcd/README.md b/components/esp_lcd/test_apps/spi_lcd/README.md index f6872a4414..d8d99fb868 100644 --- a/components/esp_lcd/test_apps/spi_lcd/README.md +++ b/components/esp_lcd/test_apps/spi_lcd/README.md @@ -1,4 +1,4 @@ -| 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 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | This test app is used to test LCDs with SPI interface. diff --git a/components/esp_lcd/test_apps/spi_lcd/main/test_spi_lcd_panel.c b/components/esp_lcd/test_apps/spi_lcd/main/test_spi_lcd_panel.c index 4518259754..092f9abb0c 100644 --- a/components/esp_lcd/test_apps/spi_lcd/main/test_spi_lcd_panel.c +++ b/components/esp_lcd/test_apps/spi_lcd/main/test_spi_lcd_panel.c @@ -15,7 +15,6 @@ #include "esp_lcd_panel_vendor.h" #include "esp_lcd_panel_ops.h" #include "esp_lcd_panel_commands.h" -#include "esp_random.h" #include "soc/soc_caps.h" #include "test_spi_board.h" @@ -92,9 +91,9 @@ static void lcd_panel_test(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_ha gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 1); for (int i = 0; i < 200; i++) { - uint8_t color_byte = esp_random() & 0xFF; - int x_start = esp_random() % (TEST_LCD_H_RES - 200); - int y_start = esp_random() % (TEST_LCD_V_RES - 200); + uint8_t color_byte = rand() & 0xFF; + int x_start = rand() % (TEST_LCD_H_RES - 200); + int y_start = rand() % (TEST_LCD_V_RES - 200); memset(img, color_byte, TEST_IMG_SIZE); esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 200, y_start + 200, img); } @@ -202,7 +201,7 @@ TEST_CASE("spi_lcd_send_colors_to_fixed_region", "[lcd]") size_t color_size = (x_end - x_start) * (y_end - y_start) * 2; void *color_data = malloc(color_size); TEST_ASSERT_NOT_NULL(color_data); - uint8_t color_byte = esp_random() & 0xFF; + uint8_t color_byte = rand() & 0xFF; memset(color_data, color_byte, color_size); esp_lcd_panel_io_handle_t io_handle = NULL; @@ -249,7 +248,7 @@ TEST_CASE("spi_lcd_send_colors_to_fixed_region", "[lcd]") } vTaskDelay(pdMS_TO_TICKS(1000)); // change to another color - color_byte = esp_random() & 0xFF; + color_byte = rand() & 0xFF; memset(color_data, color_byte, color_size); for (int i = 0; i < steps; i++) { TEST_ESP_OK(esp_lcd_panel_io_tx_color(io_handle, -1, color_data + i * color_size_per_step, color_size_per_step)); diff --git a/components/hal/esp32/include/hal/spi_ll.h b/components/hal/esp32/include/hal/spi_ll.h index b5cad9a92a..42a64fa0cc 100644 --- a/components/hal/esp32/include/hal/spi_ll.h +++ b/components/hal/esp32/include/hal/spi_ll.h @@ -63,6 +63,7 @@ typedef spi_dev_t spi_dma_dev_t; * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source) { //empty, keep this for compatibility diff --git a/components/hal/esp32c2/include/hal/spi_ll.h b/components/hal/esp32c2/include/hal/spi_ll.h index e16c8c7055..7bad336400 100644 --- a/components/hal/esp32c2/include/hal/spi_ll.h +++ b/components/hal/esp32c2/include/hal/spi_ll.h @@ -97,6 +97,7 @@ typedef enum { * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source){ switch (clk_source) { diff --git a/components/hal/esp32c3/include/hal/spi_ll.h b/components/hal/esp32c3/include/hal/spi_ll.h index 0cd6d8fc3c..7f202ddc52 100644 --- a/components/hal/esp32c3/include/hal/spi_ll.h +++ b/components/hal/esp32c3/include/hal/spi_ll.h @@ -99,6 +99,7 @@ typedef enum { * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source){ switch (clk_source) { diff --git a/components/hal/esp32c6/include/hal/spi_ll.h b/components/hal/esp32c6/include/hal/spi_ll.h index 6599f0e1bf..effcdd505e 100644 --- a/components/hal/esp32c6/include/hal/spi_ll.h +++ b/components/hal/esp32c6/include/hal/spi_ll.h @@ -98,6 +98,7 @@ typedef enum { * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source) { switch (clk_source) diff --git a/components/hal/esp32h2/include/hal/spi_ll.h b/components/hal/esp32h2/include/hal/spi_ll.h index 1bdf297ab3..d18bb36638 100644 --- a/components/hal/esp32h2/include/hal/spi_ll.h +++ b/components/hal/esp32h2/include/hal/spi_ll.h @@ -100,6 +100,7 @@ typedef enum { * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source) { switch (clk_source) diff --git a/components/hal/esp32p4/include/hal/cache_ll.h b/components/hal/esp32p4/include/hal/cache_ll.h index 2054bebf5d..2452fb93ee 100644 --- a/components/hal/esp32p4/include/hal/cache_ll.h +++ b/components/hal/esp32p4/include/hal/cache_ll.h @@ -23,7 +23,7 @@ extern "C" { * @brief Given a L2MEM cached address, get the corresponding non-cacheable address * @example 0x4FF0_0000 => 0x8FF0_0000 */ -#define CACHE_LL_L2MEM_NON_CACHE_ADDR(addr) ((intptr_t)(addr) + 0x40000000) +#define CACHE_LL_L2MEM_NON_CACHE_ADDR(addr) ((intptr_t)(addr) + SOC_NON_CACHEABLE_OFFSET) /** * Cache capabilities diff --git a/components/hal/esp32p4/include/hal/clk_gate_ll.h b/components/hal/esp32p4/include/hal/clk_gate_ll.h index 4494544135..c5230a5b98 100644 --- a/components/hal/esp32p4/include/hal/clk_gate_ll.h +++ b/components/hal/esp32p4/include/hal/clk_gate_ll.h @@ -44,12 +44,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph) return HP_SYS_CLKRST_REG_TWAI1_CLK_EN; case PERIPH_TWAI2_MODULE: return HP_SYS_CLKRST_REG_TWAI2_CLK_EN; - case PERIPH_GPSPI_MODULE: - return HP_SYS_CLKRST_REG_GPSPI2_HS_CLK_EN; - case PERIPH_GPSPI2_MODULE: - return HP_SYS_CLKRST_REG_GPSPI2_MST_CLK_EN; - case PERIPH_GPSPI3_MODULE: - return HP_SYS_CLKRST_REG_GPSPI3_MST_CLK_EN; case PERIPH_I3C_MODULE: return HP_SYS_CLKRST_REG_I3C_MST_CLK_EN; case PERIPH_CAM_MODULE: @@ -125,10 +119,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en return HP_SYS_CLKRST_REG_RST_EN_CAN2; case PERIPH_LEDC_MODULE: return HP_SYS_CLKRST_REG_RST_EN_LEDC; - case PERIPH_GPSPI2_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_SPI2; - case PERIPH_GPSPI3_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_SPI3; case PERIPH_LCD_MODULE: return HP_SYS_CLKRST_REG_RST_EN_LCDCAM; case PERIPH_SARADC_MODULE: @@ -194,10 +184,6 @@ static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph) case PERIPH_TWAI1_MODULE: case PERIPH_TWAI2_MODULE: return HP_SYS_CLKRST_PERI_CLK_CTRL116_REG; - case PERIPH_GPSPI_MODULE: - case PERIPH_GPSPI2_MODULE: - case PERIPH_GPSPI3_MODULE: - return HP_SYS_CLKRST_PERI_CLK_CTRL117_REG; case PERIPH_I3C_MODULE: case PERIPH_CAM_MODULE: return HP_SYS_CLKRST_PERI_CLK_CTRL119_REG; @@ -247,8 +233,6 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph) case PERIPH_TWAI1_MODULE: case PERIPH_TWAI2_MODULE: case PERIPH_LEDC_MODULE: - case PERIPH_GPSPI2_MODULE: - case PERIPH_GPSPI3_MODULE: case PERIPH_CAM_MODULE: case PERIPH_SARADC_MODULE: case PERIPH_AES_MODULE: diff --git a/components/hal/esp32p4/include/hal/spi_ll.h b/components/hal/esp32p4/include/hal/spi_ll.h new file mode 100644 index 0000000000..923c4ec00b --- /dev/null +++ b/components/hal/esp32p4/include/hal/spi_ll.h @@ -0,0 +1,1279 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The LL layer for SPI register operations + +#pragma once + +#include //for abs() +#include +#include "esp_types.h" +#include "soc/spi_periph.h" +#include "soc/spi_struct.h" +#include "soc/lldesc.h" +#include "hal/assert.h" +#include "hal/misc.h" +#include "hal/spi_types.h" +#include "soc/hp_sys_clkrst_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Interrupt not used. Don't use in app. +#define SPI_LL_UNUSED_INT_MASK (SPI_TRANS_DONE_INT_ENA | SPI_SLV_WR_DMA_DONE_INT_ENA | SPI_SLV_RD_DMA_DONE_INT_ENA | SPI_SLV_WR_BUF_DONE_INT_ENA | SPI_SLV_RD_BUF_DONE_INT_ENA) +/// These 2 masks together will set SPI transaction to one line mode +#define SPI_LL_ONE_LINE_CTRL_MASK (SPI_FREAD_QUAD | SPI_FREAD_DUAL | SPI_FCMD_QUAD | SPI_FCMD_DUAL | SPI_FADDR_QUAD | SPI_FADDR_DUAL) +#define SPI_LL_ONE_LINE_USER_MASK (SPI_FWRITE_QUAD | SPI_FWRITE_DUAL) +/// Swap the bit order to its correct place to send +#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len)) +#define SPI_LL_GET_HW(ID) ((ID)==0? ({abort();NULL;}):((ID)==1? &GPSPI2 : &GPSPI3)) + +#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits +#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words + +/** + * The data structure holding calculated clock configuration. Since the + * calculation needs long time, it should be calculated during initialization and + * stored somewhere to be quickly used. + */ +typedef uint32_t spi_ll_clock_val_t; +typedef spi_dev_t spi_dma_dev_t; + +// Type definition of all supported interrupts +typedef enum { + SPI_LL_INTR_TRANS_DONE = BIT(0), ///< A transaction has done + SPI_LL_INTR_RDBUF = BIT(6), ///< Has received RDBUF command. Only available in slave HD. + SPI_LL_INTR_WRBUF = BIT(7), ///< Has received WRBUF command. Only available in slave HD. + SPI_LL_INTR_RDDMA = BIT(8), ///< Has received RDDMA command. Only available in slave HD. + SPI_LL_INTR_WRDMA = BIT(9), ///< Has received WRDMA command. Only available in slave HD. + SPI_LL_INTR_CMD7 = BIT(10), ///< Has received CMD7 command. Only available in slave HD. + SPI_LL_INTR_CMD8 = BIT(11), ///< Has received CMD8 command. Only available in slave HD. + SPI_LL_INTR_CMD9 = BIT(12), ///< Has received CMD9 command. Only available in slave HD. + SPI_LL_INTR_CMDA = BIT(13), ///< Has received CMDA command. Only available in slave HD. + SPI_LL_INTR_SEG_DONE = BIT(14), +} spi_ll_intr_t; + +// Flags for conditions under which the transaction length should be recorded +typedef enum { + SPI_LL_TRANS_LEN_COND_WRBUF = BIT(0), ///< WRBUF length will be recorded + SPI_LL_TRANS_LEN_COND_RDBUF = BIT(1), ///< RDBUF length will be recorded + SPI_LL_TRANS_LEN_COND_WRDMA = BIT(2), ///< WRDMA length will be recorded + SPI_LL_TRANS_LEN_COND_RDDMA = BIT(3), ///< RDDMA length will be recorded +} spi_ll_trans_len_cond_t; + +// SPI base command +typedef enum { + /* Slave HD Only */ + SPI_LL_BASE_CMD_HD_WRBUF = 0x01, + SPI_LL_BASE_CMD_HD_RDBUF = 0x02, + SPI_LL_BASE_CMD_HD_WRDMA = 0x03, + SPI_LL_BASE_CMD_HD_RDDMA = 0x04, + SPI_LL_BASE_CMD_HD_SEG_END = 0x05, + SPI_LL_BASE_CMD_HD_EN_QPI = 0x06, + SPI_LL_BASE_CMD_HD_WR_END = 0x07, + SPI_LL_BASE_CMD_HD_INT0 = 0x08, + SPI_LL_BASE_CMD_HD_INT1 = 0x09, + SPI_LL_BASE_CMD_HD_INT2 = 0x0A, +} spi_ll_base_command_t; +/*------------------------------------------------------------------------------ + * Control + *----------------------------------------------------------------------------*/ + +/** + * Enable peripheral register clock + * + * @param host_id Peripheral index number, see `spi_host_device_t` + * @param enable Enable/Disable + */ +static inline void spi_ll_enable_bus_clock(spi_host_device_t host_id, bool enable) { + switch (host_id) + { + case SPI2_HOST: + HP_SYS_CLKRST.soc_clk_ctrl1.reg_gpspi2_sys_clk_en = enable; + HP_SYS_CLKRST.soc_clk_ctrl2.reg_gpspi2_apb_clk_en = enable; + break; + case SPI3_HOST: + HP_SYS_CLKRST.soc_clk_ctrl1.reg_gpspi3_sys_clk_en = enable; + HP_SYS_CLKRST.soc_clk_ctrl2.reg_gpspi3_apb_clk_en = enable; + break; + default: HAL_ASSERT(false); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define spi_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; spi_ll_enable_bus_clock(__VA_ARGS__) + +/** + * Reset whole peripheral register to init value defined by HW design + * + * @param host_id Peripheral index number, see `spi_host_device_t` + */ +static inline void spi_ll_reset_register(spi_host_device_t host_id) { + switch (host_id) + { + case SPI2_HOST: + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_spi2 = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_spi2 = 0; + break; + case SPI3_HOST: + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_spi3 = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_spi3 = 0; + break; + default: HAL_ASSERT(false); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define spi_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; spi_ll_reset_register(__VA_ARGS__) + +/** + * Enable functional output clock within peripheral + * + * @param host_id Peripheral index number, see `spi_host_device_t` + * @param enable Enable/Disable + */ +static inline void spi_ll_enable_clock(spi_host_device_t host_id, bool enable) +{ + switch (host_id) + { + case SPI2_HOST: + HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_hs_clk_en = enable; + HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_mst_clk_en = enable; + break; + case SPI3_HOST: + HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi3_hs_clk_en = enable; + HP_SYS_CLKRST.peri_clk_ctrl117.reg_gpspi3_mst_clk_en = enable; + break; + default: HAL_ASSERT(false); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define spi_ll_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; spi_ll_enable_clock(__VA_ARGS__) + +/** + * Select SPI peripheral clock source (master). + * + * @param hw Beginning address of the peripheral registers. + * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` + */ +__attribute__((always_inline)) +static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source) +{ + uint32_t clk_id = 0; + switch (clk_source) { + case SPI_CLK_SRC_XTAL: + clk_id = 0; + break; + default: + HAL_ASSERT(false); + } + + if (hw == &GPSPI2) { + HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_clk_src_sel = clk_id; + } else if (hw == &GPSPI3) { + HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi3_clk_src_sel = clk_id; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define spi_ll_set_clk_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; spi_ll_set_clk_source(__VA_ARGS__) + +/** + * Initialize SPI peripheral (master). + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_master_init(spi_dev_t *hw) +{ + //Reset timing + hw->user1.cs_setup_time = 0; + hw->user1.cs_hold_time = 0; + + //use all 64 bytes of the buffer + hw->user.usr_miso_highpart = 0; + hw->user.usr_mosi_highpart = 0; + + //Disable unneeded ints + hw->slave.val = 0; + hw->user.val = 0; + + hw->dma_conf.val = 0; + hw->dma_conf.slv_tx_seg_trans_clr_en = 1; + hw->dma_conf.slv_rx_seg_trans_clr_en = 1; + hw->dma_conf.dma_slv_seg_trans_en = 0; +} + +/** + * Initialize SPI peripheral (slave). + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_init(spi_dev_t *hw) +{ + //Configure slave + hw->clock.val = 0; + hw->user.val = 0; + hw->ctrl.val = 0; + hw->user.doutdin = 1; //we only support full duplex + hw->user.sio = 0; + hw->slave.slave_mode = 1; + hw->slave.soft_reset = 1; + hw->slave.soft_reset = 0; + //use all 64 bytes of the buffer + hw->user.usr_miso_highpart = 0; + hw->user.usr_mosi_highpart = 0; + + // Configure DMA In-Link to not be terminated when transaction bit counter exceeds + hw->dma_conf.rx_eof_en = 0; + hw->dma_conf.dma_slv_seg_trans_en = 0; + + //Disable unneeded ints + hw->dma_int_ena.val &= ~SPI_LL_UNUSED_INT_MASK; +} + +/** + * Initialize SPI peripheral (slave half duplex mode) + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_hd_init(spi_dev_t *hw) +{ + hw->clock.val = 0; + hw->user.val = 0; + hw->ctrl.val = 0; + hw->user.doutdin = 0; + hw->user.sio = 0; + + hw->slave.soft_reset = 1; + hw->slave.soft_reset = 0; + hw->slave.slave_mode = 1; +} + +/** + * Check whether user-defined transaction is done. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if transaction is done, otherwise false. + */ +static inline bool spi_ll_usr_is_done(spi_dev_t *hw) +{ + return hw->dma_int_raw.trans_done_int; +} + +/** + * Apply the register configurations and wait until it's done + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_apply_config(spi_dev_t *hw) +{ + hw->cmd.update = 1; + while (hw->cmd.update); //waiting config applied +} + +/** + * Trigger start of user-defined transaction. + * The synchronization between two clock domains is required in ESP32-S3 + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_user_start(spi_dev_t *hw) +{ + hw->cmd.usr = 1; +} + +/** + * Get current running command bit-mask. (Preview) + * + * @param hw Beginning address of the peripheral registers. + * + * @return Bitmask of running command, see ``SPI_CMD_REG``. 0 if no in-flight command. + */ +static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw) +{ + return hw->cmd.usr; +} + +/** + * Reset the slave peripheral before next transaction. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_reset(spi_dev_t *hw) +{ + hw->slave.soft_reset = 1; + hw->slave.soft_reset = 0; +} + +/** + * Reset SPI CPU TX FIFO + * + * On P4, this function is not seperated + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_cpu_tx_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.buf_afifo_rst = 1; + hw->dma_conf.buf_afifo_rst = 0; +} + +/** + * Reset SPI CPU RX FIFO + * + * On P4, this function is not seperated + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_cpu_rx_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.rx_afifo_rst = 1; + hw->dma_conf.rx_afifo_rst = 0; +} + +/** + * Reset SPI DMA TX FIFO + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_dma_tx_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.dma_afifo_rst = 1; + hw->dma_conf.dma_afifo_rst = 0; +} + +/** + * Reset SPI DMA RX FIFO + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_dma_rx_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.rx_afifo_rst = 1; + hw->dma_conf.rx_afifo_rst = 0; +} + +/** + * Clear in fifo full error + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_infifo_full_clr(spi_dev_t *hw) +{ + hw->dma_int_clr.dma_infifo_full_err_int = 1; +} + +/** + * Clear out fifo empty error + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw) +{ + hw->dma_int_clr.dma_outfifo_empty_err_int = 1; +} + +/*------------------------------------------------------------------------------ + * DMA + *----------------------------------------------------------------------------*/ +/** + * Enable/Disable RX DMA (Peripherals->DMA->RAM) + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: enable; 2: disable + */ +static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable) +{ + hw->dma_conf.dma_rx_ena = enable; +} + +/** + * Enable/Disable TX DMA (RAM->DMA->Peripherals) + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: enable; 2: disable + */ +static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable) +{ + hw->dma_conf.dma_tx_ena = enable; +} + +/** + * Configuration of RX DMA EOF interrupt generation way + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: spi_dma_inlink_eof is set when the number of dma pushed data bytes is equal to the value of spi_slv/mst_dma_rd_bytelen[19:0] in spi dma transition. 0: spi_dma_inlink_eof is set by spi_trans_done in non-seg-trans or spi_dma_seg_trans_done in seg-trans. + */ +static inline void spi_ll_dma_set_rx_eof_generation(spi_dev_t *hw, bool enable) +{ + hw->dma_conf.rx_eof_en = enable; +} + +/*------------------------------------------------------------------------------ + * Buffer + *----------------------------------------------------------------------------*/ +/** + * Write to SPI hardware data buffer. + * + * @param hw Beginning address of the peripheral registers. + * @param buffer_to_send Address of the data to be written to the hardware data buffer. + * @param bitlen Length to write, in bits. + */ +static inline void spi_ll_write_buffer(spi_dev_t *hw, const uint8_t *buffer_to_send, size_t bitlen) +{ + for (int x = 0; x < bitlen; x += 32) { + //Use memcpy to get around alignment issues for txdata + uint32_t word; + memcpy(&word, &buffer_to_send[x / 8], 4); + hw->data_buf[(x / 32)].buf = word; + } +} + +/** + * Write to SPI hardware data buffer by buffer ID (address) + * + * @param hw Beginning address of the peripheral registers + * @param byte_id Start ID (address) of the hardware buffer to be written + * @param data Address of the data to be written to the hardware data buffer. + * @param len Length to write, in bytes. + */ +static inline void spi_ll_write_buffer_byte(spi_dev_t *hw, int byte_id, uint8_t *data, int len) +{ + HAL_ASSERT(byte_id + len <= 64); + HAL_ASSERT(len > 0); + HAL_ASSERT(byte_id >= 0); + + while (len > 0) { + uint32_t word; + int offset = byte_id % 4; + int copy_len = 4 - offset; + if (copy_len > len) { + copy_len = len; + } + + //read-modify-write + if (copy_len != 4) { + word = hw->data_buf[byte_id / 4].buf; //read + } + memcpy(((uint8_t *)&word) + offset, data, copy_len); //modify + hw->data_buf[byte_id / 4].buf = word; //write + + data += copy_len; + byte_id += copy_len; + len -= copy_len; + } +} + +/** + * Read from SPI hardware data buffer. + * + * @param hw Beginning address of the peripheral registers. + * @param buffer_to_rcv Address of a buffer to read data from hardware data buffer + * @param bitlen Length to read, in bits. + */ +static inline void spi_ll_read_buffer(spi_dev_t *hw, uint8_t *buffer_to_rcv, size_t bitlen) +{ + for (int x = 0; x < bitlen; x += 32) { + //Do a memcpy to get around possible alignment issues in rx_buffer + uint32_t word = hw->data_buf[x / 32].buf; + int len = bitlen - x; + if (len > 32) { + len = 32; + } + memcpy(&buffer_to_rcv[x / 8], &word, (len + 7) / 8); + } +} + +/** + * Read from SPI hardware data buffer by buffer ID (address) + * + * @param hw Beginning address of the peripheral registers + * @param byte_id Start ID (address) of the hardware buffer to be read + * @param data Address of a buffer to read data from hardware data buffer + * @param len Length to read, in bytes. + */ +static inline void spi_ll_read_buffer_byte(spi_dev_t *hw, int byte_id, uint8_t *out_data, int len) +{ + while (len > 0) { + uint32_t word = hw->data_buf[byte_id / 4].buf; + int offset = byte_id % 4; + int copy_len = 4 - offset; + if (copy_len > len) { + copy_len = len; + } + + memcpy(out_data, ((uint8_t *)&word) + offset, copy_len); + byte_id += copy_len; + out_data += copy_len; + len -= copy_len; + } +} + +/*------------------------------------------------------------------------------ + * Configs: mode + *----------------------------------------------------------------------------*/ +/** + * Enable/disable the postive-cs feature. + * + * @param hw Beginning address of the peripheral registers. + * @param cs One of the CS (0-2) to enable/disable the feature. + * @param pos_cs True to enable the feature, otherwise disable (default). + */ +static inline void spi_ll_master_set_pos_cs(spi_dev_t *hw, int cs, uint32_t pos_cs) +{ + if (pos_cs) { + hw->misc.master_cs_pol |= (1 << cs); + } else { + hw->misc.master_cs_pol &= ~(1 << cs); + } +} + +/** + * Enable/disable the LSBFIRST feature for TX data. + * + * @param hw Beginning address of the peripheral registers. + * @param lsbfirst True if LSB of TX data to be sent first, otherwise MSB is sent first (default). + */ +static inline void spi_ll_set_tx_lsbfirst(spi_dev_t *hw, bool lsbfirst) +{ + hw->ctrl.wr_bit_order = lsbfirst; +} + +/** + * Enable/disable the LSBFIRST feature for RX data. + * + * @param hw Beginning address of the peripheral registers. + * @param lsbfirst True if first bit received as LSB, otherwise as MSB (default). + */ +static inline void spi_ll_set_rx_lsbfirst(spi_dev_t *hw, bool lsbfirst) +{ + hw->ctrl.rd_bit_order = lsbfirst; +} + +/** + * Set SPI mode for the peripheral as master. + * + * @param hw Beginning address of the peripheral registers. + * @param mode SPI mode to work at, 0-3. + */ +static inline void spi_ll_master_set_mode(spi_dev_t *hw, uint8_t mode) +{ + //Configure polarity + if (mode == 0) { + hw->misc.ck_idle_edge = 0; + hw->user.ck_out_edge = 0; + } else if (mode == 1) { + hw->misc.ck_idle_edge = 0; + hw->user.ck_out_edge = 1; + } else if (mode == 2) { + hw->misc.ck_idle_edge = 1; + hw->user.ck_out_edge = 1; + } else if (mode == 3) { + hw->misc.ck_idle_edge = 1; + hw->user.ck_out_edge = 0; + } +} + +/** + * Set SPI mode for the peripheral as slave. + * + * @param hw Beginning address of the peripheral registers. + * @param mode SPI mode to work at, 0-3. + */ +static inline void spi_ll_slave_set_mode(spi_dev_t *hw, const int mode, bool dma_used) +{ + if (mode == 0) { + hw->misc.ck_idle_edge = 0; + hw->user.rsck_i_edge = 0; + hw->user.tsck_i_edge = 0; + hw->slave.clk_mode_13 = 0; + } else if (mode == 1) { + hw->misc.ck_idle_edge = 0; + hw->user.rsck_i_edge = 1; + hw->user.tsck_i_edge = 1; + hw->slave.clk_mode_13 = 1; + } else if (mode == 2) { + hw->misc.ck_idle_edge = 1; + hw->user.rsck_i_edge = 1; + hw->user.tsck_i_edge = 1; + hw->slave.clk_mode_13 = 0; + } else if (mode == 3) { + hw->misc.ck_idle_edge = 1; + hw->user.rsck_i_edge = 0; + hw->user.tsck_i_edge = 0; + hw->slave.clk_mode_13 = 1; + } + hw->slave.rsck_data_out = 0; +} + +/** + * Set SPI to work in full duplex or half duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * @param half_duplex True to work in half duplex mode, otherwise in full duplex mode. + */ +static inline void spi_ll_set_half_duplex(spi_dev_t *hw, bool half_duplex) +{ + hw->user.doutdin = !half_duplex; +} + +/** + * Set SPI to work in SIO mode or not. + * + * SIO is a mode which MOSI and MISO share a line. The device MUST work in half-duplexmode. + * + * @param hw Beginning address of the peripheral registers. + * @param sio_mode True to work in SIO mode, otherwise false. + */ +static inline void spi_ll_set_sio_mode(spi_dev_t *hw, int sio_mode) +{ + hw->user.sio = sio_mode; +} + +/** + * Configure the SPI transaction line mode for the master to use. + * + * @param hw Beginning address of the peripheral registers. + * @param line_mode SPI transaction line mode to use, see ``spi_line_mode_t``. + */ +static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t line_mode) +{ + hw->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK; + hw->user.val &= ~SPI_LL_ONE_LINE_USER_MASK; + hw->ctrl.fcmd_dual = (line_mode.cmd_lines == 2); + hw->ctrl.fcmd_quad = (line_mode.cmd_lines == 4); + hw->ctrl.faddr_dual = (line_mode.addr_lines == 2); + hw->ctrl.faddr_quad = (line_mode.addr_lines == 4); + hw->ctrl.fread_dual = (line_mode.data_lines == 2); + hw->user.fwrite_dual = (line_mode.data_lines == 2); + hw->ctrl.fread_quad = (line_mode.data_lines == 4); + hw->user.fwrite_quad = (line_mode.data_lines == 4); +} + +/** + * Set the SPI slave to work in segment transaction mode + * + * @param hw Beginning address of the peripheral registers. + * @param seg_trans True to work in seg mode, otherwise false. + */ +static inline void spi_ll_slave_set_seg_mode(spi_dev_t *hw, bool seg_trans) +{ + hw->dma_conf.dma_slv_seg_trans_en = seg_trans; +} + +/** + * Select one of the CS to use in current transaction. + * + * @param hw Beginning address of the peripheral registers. + * @param cs_id The cs to use, 0-2, otherwise none of them is used. + */ +static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id) +{ + hw->misc.cs0_dis = (cs_id == 0) ? 0 : 1; + hw->misc.cs1_dis = (cs_id == 1) ? 0 : 1; + hw->misc.cs2_dis = (cs_id == 2) ? 0 : 1; + hw->misc.cs3_dis = (cs_id == 3) ? 0 : 1; + hw->misc.cs4_dis = (cs_id == 4) ? 0 : 1; + hw->misc.cs5_dis = (cs_id == 5) ? 0 : 1; +} + +/** + * Keep Chip Select activated after the current transaction. + * + * @param hw Beginning address of the peripheral registers. + * @param keep_active if 0 don't keep CS activated, else keep CS activated + */ +static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active) +{ + hw->misc.cs_keep_active = (keep_active != 0) ? 1 : 0; +} + +/*------------------------------------------------------------------------------ + * Configs: parameters + *----------------------------------------------------------------------------*/ +/** + * Set the clock for master by stored value. + * + * @param hw Beginning address of the peripheral registers. + * @param val Stored clock configuration calculated before (by ``spi_ll_cal_clock``). + */ +static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_clock_val_t *val) +{ + hw->clock.val = *(uint32_t *)val; +} + +/** + * Get the frequency of given dividers. Don't use in app. + * + * @param fapb APB clock of the system. + * @param pre Pre devider. + * @param n Main divider. + * + * @return Frequency of given dividers. + */ +static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n) +{ + return (fapb / (pre * n)); +} + +/** + * Calculate the nearest frequency avaliable for master. + * + * @param fapb APB clock of the system. + * @param hz Frequncy desired. + * @param duty_cycle Duty cycle desired. + * @param out_reg Output address to store the calculated clock configurations for the return frequency. + * + * @return Actual (nearest) frequency. + */ +static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg) +{ + typeof(GPSPI2.clock) reg; + int eff_clk; + + //In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value. + if (hz > ((fapb / 4) * 3)) { + //Using Fapb directly will give us the best result here. + reg.clkcnt_l = 0; + reg.clkcnt_h = 0; + reg.clkcnt_n = 0; + reg.clkdiv_pre = 0; + reg.clk_equ_sysclk = 1; + eff_clk = fapb; + } else { + //For best duty cycle resolution, we want n to be as close to 32 as possible, but + //we also need a pre/n combo that gets us as close as possible to the intended freq. + //To do this, we bruteforce n and calculate the best pre to go along with that. + //If there's a choice between pre/n combos that give the same result, use the one + //with the higher n. + int pre, n, h, l; + int bestn = -1; + int bestpre = -1; + int besterr = 0; + int errval; + for (n = 2; n <= 64; n++) { //Start at 2: we need to be able to set h/l so we have at least one high and one low pulse. + //Effectively, this does pre=round((fapb/n)/hz). + pre = ((fapb / n) + (hz / 2)) / hz; + if (pre <= 0) { + pre = 1; + } + if (pre > 16) { + pre = 16; + } + errval = abs(spi_ll_freq_for_pre_n(fapb, pre, n) - hz); + if (bestn == -1 || errval <= besterr) { + besterr = errval; + bestn = n; + bestpre = pre; + } + } + + n = bestn; + pre = bestpre; + l = n; + //This effectively does round((duty_cycle*n)/256) + h = (duty_cycle * n + 127) / 256; + if (h <= 0) { + h = 1; + } + + reg.clk_equ_sysclk = 0; + reg.clkcnt_n = n - 1; + reg.clkdiv_pre = pre - 1; + reg.clkcnt_h = h - 1; + reg.clkcnt_l = l - 1; + eff_clk = spi_ll_freq_for_pre_n(fapb, pre, n); + } + if (out_reg != NULL) { + *(uint32_t *)out_reg = reg.val; + } + return eff_clk; +} + +/** + * Calculate and set clock for SPI master according to desired parameters. + * + * This takes long, suggest to calculate the configuration during + * initialization by ``spi_ll_master_cal_clock`` and store the result, then + * configure the clock by stored value when used by + * ``spi_ll_msater_set_clock_by_reg``. + * + * @param hw Beginning address of the peripheral registers. + * @param fapb APB clock of the system. + * @param hz Frequncy desired. + * @param duty_cycle Duty cycle desired. + * + * @return Actual frequency that is used. + */ +static inline int spi_ll_master_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) +{ + spi_ll_clock_val_t reg_val; + int freq = spi_ll_master_cal_clock(fapb, hz, duty_cycle, ®_val); + spi_ll_master_set_clock_by_reg(hw, ®_val); + return freq; +} + +/** + * Set the mosi delay after the output edge to the signal. (Preview) + * + * The delay mode/num is a Espressif conception, may change in the new chips. + * + * @param hw Beginning address of the peripheral registers. + * @param delay_mode Delay mode, see TRM. + * @param delay_num APB clocks to delay. + */ +static inline void spi_ll_set_mosi_delay(spi_dev_t *hw, int delay_mode, int delay_num) +{ +} + +/** + * Set the miso delay applied to the input signal before the internal peripheral. (Preview) + * + * The delay mode/num is a Espressif conception, may change in the new chips. + * + * @param hw Beginning address of the peripheral registers. + * @param delay_mode Delay mode, see TRM. + * @param delay_num APB clocks to delay. + */ +static inline void spi_ll_set_miso_delay(spi_dev_t *hw, int delay_mode, int delay_num) +{ +} + +/** + * Set the delay of SPI clocks before the CS inactive edge after the last SPI clock. + * + * @param hw Beginning address of the peripheral registers. + * @param hold Delay of SPI clocks after the last clock, 0 to disable the hold phase. + */ +static inline void spi_ll_master_set_cs_hold(spi_dev_t *hw, int hold) +{ + hw->user1.cs_hold_time = hold; + hw->user.cs_hold = hold ? 1 : 0; +} + +/** + * Set the delay of SPI clocks before the first SPI clock after the CS active edge. + * + * Note ESP32 doesn't support to use this feature when command/address phases + * are used in full duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * @param setup Delay of SPI clocks after the CS active edge, 0 to disable the setup phase. + */ +static inline void spi_ll_master_set_cs_setup(spi_dev_t *hw, uint8_t setup) +{ + hw->user1.cs_setup_time = setup - 1; + hw->user.cs_setup = setup ? 1 : 0; +} + +/*------------------------------------------------------------------------------ + * Configs: data + *----------------------------------------------------------------------------*/ +/** + * Set the output length (master). + * This should be called before master setting MISO(input) length + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen output length, in bits. + */ +static inline void spi_ll_set_mosi_bitlen(spi_dev_t *hw, size_t bitlen) +{ + if (bitlen > 0) { + hw->ms_dlen.ms_data_bitlen = bitlen - 1; + } +} + +/** + * Set the input length (master). + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen input length, in bits. + */ +static inline void spi_ll_set_miso_bitlen(spi_dev_t *hw, size_t bitlen) +{ + if (bitlen > 0) { + hw->ms_dlen.ms_data_bitlen = bitlen - 1; + } +} + +/** + * Set the maximum input length (slave). + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen Input length, in bits. + */ +static inline void spi_ll_slave_set_rx_bitlen(spi_dev_t *hw, size_t bitlen) +{ + //This is not used in P4 +} + +/** + * Set the maximum output length (slave). + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen Output length, in bits. + */ +static inline void spi_ll_slave_set_tx_bitlen(spi_dev_t *hw, size_t bitlen) +{ + //This is not used in P4 +} + +/** + * Set the length of command phase. + * + * When in 4-bit mode, the SPI cycles of the phase will be shorter. E.g. 16-bit + * command phases takes 4 cycles in 4-bit mode. + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen Length of command phase, in bits. 0 to disable the command phase. + */ +static inline void spi_ll_set_command_bitlen(spi_dev_t *hw, int bitlen) +{ + hw->user2.usr_command_bitlen = bitlen - 1; + hw->user.usr_command = bitlen ? 1 : 0; +} + +/** + * Set the length of address phase. + * + * When in 4-bit mode, the SPI cycles of the phase will be shorter. E.g. 16-bit + * address phases takes 4 cycles in 4-bit mode. + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen Length of address phase, in bits. 0 to disable the address phase. + */ +static inline void spi_ll_set_addr_bitlen(spi_dev_t *hw, int bitlen) +{ + hw->user1.usr_addr_bitlen = bitlen - 1; + hw->user.usr_addr = bitlen ? 1 : 0; +} + +/** + * Set the address value in an intuitive way. + * + * The length and lsbfirst is required to shift and swap the address to the right place. + * + * @param hw Beginning address of the peripheral registers. + * @param address Address to set + * @param addrlen Length of the address phase + * @param lsbfirst Whether the LSB first feature is enabled. + */ +static inline void spi_ll_set_address(spi_dev_t *hw, uint64_t addr, int addrlen, uint32_t lsbfirst) +{ + if (lsbfirst) { + /* The output address start from the LSB of the highest byte, i.e. + * addr[24] -> addr[31] + * ... + * addr[0] -> addr[7] + * So swap the byte order to let the LSB sent first. + */ + addr = HAL_SWAP32(addr); + //otherwise only addr register is sent + hw->addr.val = addr; + } else { + // shift the address to MSB of addr register. + // output address will be sent from MSB to LSB of addr register + hw->addr.val = addr << (32 - addrlen); + } +} + +/** + * Set the command value in an intuitive way. + * + * The length and lsbfirst is required to shift and swap the command to the right place. + * + * @param hw Beginning command of the peripheral registers. + * @param command Command to set + * @param addrlen Length of the command phase + * @param lsbfirst Whether the LSB first feature is enabled. + */ +static inline void spi_ll_set_command(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst) +{ + if (lsbfirst) { + // The output command start from bit0 to bit 15, kept as is. + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->user2, usr_command_value, cmd); + } else { + /* Output command will be sent from bit 7 to 0 of command_value, and + * then bit 15 to 8 of the same register field. Shift and swap to send + * more straightly. + */ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->user2, usr_command_value, HAL_SPI_SWAP_DATA_TX(cmd, cmdlen)); + } +} + +/** + * Set dummy clocks to output before RX phase (master), or clocks to skip + * before the data phase and after the address phase (slave). + * + * Note this phase is also used to compensate RX timing in half duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * @param dummy_n Dummy cycles used. 0 to disable the dummy phase. + */ +static inline void spi_ll_set_dummy(spi_dev_t *hw, int dummy_n) +{ + hw->user.usr_dummy = dummy_n ? 1 : 0; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->user1, usr_dummy_cyclelen, dummy_n - 1); +} + +/** + * Enable/disable the RX data phase. + * + * @param hw Beginning address of the peripheral registers. + * @param enable True if RX phase exist, otherwise false. + */ +static inline void spi_ll_enable_miso(spi_dev_t *hw, int enable) +{ + hw->user.usr_miso = enable; +} + +/** + * Enable/disable the TX data phase. + * + * @param hw Beginning address of the peripheral registers. + * @param enable True if TX phase exist, otherwise false. + */ +static inline void spi_ll_enable_mosi(spi_dev_t *hw, int enable) +{ + hw->user.usr_mosi = enable; +} + +/** + * Get the received bit length of the slave. + * + * @param hw Beginning address of the peripheral registers. + * + * @return Received bits of the slave. + */ +static inline uint32_t spi_ll_slave_get_rcv_bitlen(spi_dev_t *hw) +{ + return hw->slave1.slv_data_bitlen; +} + +/*------------------------------------------------------------------------------ + * Interrupts + *----------------------------------------------------------------------------*/ +//helper macros to generate code for each interrupts +#define FOR_EACH_ITEM(op, list) do { list(op) } while(0) +#define INTR_LIST(item) \ + item(SPI_LL_INTR_TRANS_DONE, dma_int_ena.trans_done_int, dma_int_raw.trans_done_int, dma_int_clr.trans_done_int, dma_int_set.trans_done_int) \ + item(SPI_LL_INTR_RDBUF, dma_int_ena.slv_rd_buf_done_int, dma_int_raw.slv_rd_buf_done_int, dma_int_clr.slv_rd_buf_done_int, dma_int_set.slv_rd_buf_done_int) \ + item(SPI_LL_INTR_WRBUF, dma_int_ena.slv_wr_buf_done_int, dma_int_raw.slv_wr_buf_done_int, dma_int_clr.slv_wr_buf_done_int, dma_int_set.slv_wr_buf_done_int) \ + item(SPI_LL_INTR_RDDMA, dma_int_ena.slv_rd_dma_done_int, dma_int_raw.slv_rd_dma_done_int, dma_int_clr.slv_rd_dma_done_int, dma_int_set.slv_rd_dma_done_int) \ + item(SPI_LL_INTR_WRDMA, dma_int_ena.slv_wr_dma_done_int, dma_int_raw.slv_wr_dma_done_int, dma_int_clr.slv_wr_dma_done_int, dma_int_set.slv_wr_dma_done_int) \ + item(SPI_LL_INTR_SEG_DONE, dma_int_ena.dma_seg_trans_done_int, dma_int_raw.dma_seg_trans_done_int, dma_int_clr.dma_seg_trans_done_int, dma_int_set.dma_seg_trans_done_int) \ + item(SPI_LL_INTR_CMD7, dma_int_ena.slv_cmd7_int, dma_int_raw.slv_cmd7_int, dma_int_clr.slv_cmd7_int, dma_int_set.slv_cmd7_int) \ + item(SPI_LL_INTR_CMD8, dma_int_ena.slv_cmd8_int, dma_int_raw.slv_cmd8_int, dma_int_clr.slv_cmd8_int, dma_int_set.slv_cmd8_int) \ + item(SPI_LL_INTR_CMD9, dma_int_ena.slv_cmd9_int, dma_int_raw.slv_cmd9_int, dma_int_clr.slv_cmd9_int, dma_int_set.slv_cmd9_int) \ + item(SPI_LL_INTR_CMDA, dma_int_ena.slv_cmda_int, dma_int_raw.slv_cmda_int, dma_int_clr.slv_cmda_int, dma_int_set.slv_cmda_int) + + +static inline void spi_ll_enable_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define ENA_INTR(intr_bit, en_reg, ...) if (intr_mask & (intr_bit)) hw->en_reg = 1; + FOR_EACH_ITEM(ENA_INTR, INTR_LIST); +#undef ENA_INTR +} + +static inline void spi_ll_disable_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define DIS_INTR(intr_bit, en_reg, ...) if (intr_mask & (intr_bit)) hw->en_reg = 0; + FOR_EACH_ITEM(DIS_INTR, INTR_LIST); +#undef DIS_INTR +} + +static inline void spi_ll_set_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define SET_INTR(intr_bit, _, __, ___, set_reg) if (intr_mask & (intr_bit)) hw->set_reg = 1; + FOR_EACH_ITEM(SET_INTR, INTR_LIST); +#undef SET_INTR +} + +static inline void spi_ll_clear_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define CLR_INTR(intr_bit, _, __, clr_reg, ...) if (intr_mask & (intr_bit)) hw->clr_reg = 1; + FOR_EACH_ITEM(CLR_INTR, INTR_LIST); +#undef CLR_INTR +} + +static inline bool spi_ll_get_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define GET_INTR(intr_bit, _, sta_reg, ...) if (intr_mask & (intr_bit) && hw->sta_reg) return true; + FOR_EACH_ITEM(GET_INTR, INTR_LIST); + return false; +#undef GET_INTR +} + +#undef FOR_EACH_ITEM +#undef INTR_LIST + +/** + * Disable the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_disable_int(spi_dev_t *hw) +{ + hw->dma_int_ena.trans_done_int = 0; +} + +/** + * Clear the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_clear_int_stat(spi_dev_t *hw) +{ + hw->dma_int_clr.trans_done_int = 1; +} + +/** + * Set the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_set_int_stat(spi_dev_t *hw) +{ + hw->dma_int_set.trans_done_int = 1; +} + +/** + * Enable the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_enable_int(spi_dev_t *hw) +{ + hw->dma_int_ena.trans_done_int = 1; +} + +/*------------------------------------------------------------------------------ + * Slave HD + *----------------------------------------------------------------------------*/ +static inline void spi_ll_slave_hd_set_len_cond(spi_dev_t *hw, spi_ll_trans_len_cond_t cond_mask) +{ + hw->slave.slv_rdbuf_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_RDBUF) ? 1 : 0; + hw->slave.slv_wrbuf_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_WRBUF) ? 1 : 0; + hw->slave.slv_rddma_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_RDDMA) ? 1 : 0; + hw->slave.slv_wrdma_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_WRDMA) ? 1 : 0; +} + +static inline int spi_ll_slave_get_rx_byte_len(spi_dev_t *hw) +{ + return hw->slave1.slv_data_bitlen / 8; +} + +static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw) +{ + return hw->slave1.slv_last_addr; +} + +#undef SPI_LL_RST_MASK +#undef SPI_LL_UNUSED_INT_MASK + +/** + * Get the base spi command + * + * @param cmd_t Command value + */ +static inline uint8_t spi_ll_get_slave_hd_base_command(spi_command_t cmd_t) +{ + uint8_t cmd_base = 0x00; + switch (cmd_t) + { + case SPI_CMD_HD_WRBUF: + cmd_base = SPI_LL_BASE_CMD_HD_WRBUF; + break; + case SPI_CMD_HD_RDBUF: + cmd_base = SPI_LL_BASE_CMD_HD_RDBUF; + break; + case SPI_CMD_HD_WRDMA: + cmd_base = SPI_LL_BASE_CMD_HD_WRDMA; + break; + case SPI_CMD_HD_RDDMA: + cmd_base = SPI_LL_BASE_CMD_HD_RDDMA; + break; + case SPI_CMD_HD_SEG_END: + cmd_base = SPI_LL_BASE_CMD_HD_SEG_END; + break; + case SPI_CMD_HD_EN_QPI: + cmd_base = SPI_LL_BASE_CMD_HD_EN_QPI; + break; + case SPI_CMD_HD_WR_END: + cmd_base = SPI_LL_BASE_CMD_HD_WR_END; + break; + case SPI_CMD_HD_INT0: + cmd_base = SPI_LL_BASE_CMD_HD_INT0; + break; + case SPI_CMD_HD_INT1: + cmd_base = SPI_LL_BASE_CMD_HD_INT1; + break; + case SPI_CMD_HD_INT2: + cmd_base = SPI_LL_BASE_CMD_HD_INT2; + break; + default: + HAL_ASSERT(cmd_base); + } + return cmd_base; +} + +/** + * Get the spi communication command + * + * @param cmd_t Base command value + * @param line_mode Line mode of SPI transaction phases: CMD, ADDR, DOUT/DIN. + */ +static inline uint16_t spi_ll_get_slave_hd_command(spi_command_t cmd_t, spi_line_mode_t line_mode) +{ + uint8_t cmd_base = spi_ll_get_slave_hd_base_command(cmd_t); + uint8_t cmd_mod = 0x00; //CMD:1-bit, ADDR:1-bit, DATA:1-bit + + if (line_mode.data_lines == 2) { + if (line_mode.addr_lines == 2) { + cmd_mod = 0x50; //CMD:1-bit, ADDR:2-bit, DATA:2-bit + } else { + cmd_mod = 0x10; //CMD:1-bit, ADDR:1-bit, DATA:2-bit + } + } else if (line_mode.data_lines == 4) { + if (line_mode.addr_lines == 4) { + cmd_mod = 0xA0; //CMD:1-bit, ADDR:4-bit, DATA:4-bit + } else { + cmd_mod = 0x20; //CMD:1-bit, ADDR:1-bit, DATA:4-bit + } + } + if (cmd_base == SPI_LL_BASE_CMD_HD_SEG_END || cmd_base == SPI_LL_BASE_CMD_HD_EN_QPI) { + cmd_mod = 0x00; + } + + return cmd_base | cmd_mod; +} + +/** + * Get the dummy bits + * + * @param line_mode Line mode of SPI transaction phases: CMD, ADDR, DOUT/DIN. + */ +static inline int spi_ll_get_slave_hd_dummy_bits(spi_line_mode_t line_mode) +{ + return 8; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32s2/include/hal/spi_ll.h b/components/hal/esp32s2/include/hal/spi_ll.h index ab78bf421b..8c525a05d1 100644 --- a/components/hal/esp32s2/include/hal/spi_ll.h +++ b/components/hal/esp32s2/include/hal/spi_ll.h @@ -107,6 +107,7 @@ typedef enum { * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source) { //empty, keep this for compatibility diff --git a/components/hal/esp32s3/include/hal/spi_ll.h b/components/hal/esp32s3/include/hal/spi_ll.h index 5d3e3ed17d..590198029c 100644 --- a/components/hal/esp32s3/include/hal/spi_ll.h +++ b/components/hal/esp32s3/include/hal/spi_ll.h @@ -99,6 +99,7 @@ typedef enum { * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source){ switch (clk_source) { diff --git a/components/hal/include/hal/spi_hal.h b/components/hal/include/hal/spi_hal.h index ad4ad8a319..b19d4ad446 100644 --- a/components/hal/include/hal/spi_hal.h +++ b/components/hal/include/hal/spi_hal.h @@ -29,9 +29,9 @@ #include "esp_err.h" #include "soc/soc_caps.h" #include "hal/spi_types.h" +#include "hal/dma_types.h" #if SOC_GPSPI_SUPPORTED #include "hal/spi_ll.h" -#include "soc/lldesc.h" #endif #ifdef __cplusplus @@ -40,6 +40,12 @@ extern "C" { #if SOC_GPSPI_SUPPORTED +#if SOC_GPSPI_SUPPORTED && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) +typedef dma_descriptor_align8_t spi_dma_desc_t; +#else +typedef dma_descriptor_align4_t spi_dma_desc_t; +#endif + /** * Input parameters to the ``spi_hal_cal_clock_conf`` to calculate the timing configuration */ @@ -76,11 +82,11 @@ typedef struct { spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization - lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA. + spi_dma_desc_t *dmadesc_tx; /**< 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_rx; /**< Array of DMA descriptor used by the RX DMA. + spi_dma_desc_t *dmadesc_rx; /**< 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. */ @@ -112,11 +118,11 @@ typedef struct { */ typedef struct { /* These two need to be malloced by the driver first */ - lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA. + spi_dma_desc_t *dmadesc_tx; /**< 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_rx; /**< Array of DMA descriptor used by the RX DMA. + spi_dma_desc_t *dmadesc_rx; /**< 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. */ diff --git a/components/hal/spi_hal.c b/components/hal/spi_hal.c index e5bddfdf87..d928fe997e 100644 --- a/components/hal/spi_hal.c +++ b/components/hal/spi_hal.c @@ -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 */ @@ -13,17 +13,27 @@ #include "soc/clk_tree_defs.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_rx_enable_burst_data(dev, chan, enable) gdma_ll_rx_enable_data_burst(&GDMA, chan, enable); #define spi_dma_ll_tx_enable_burst_data(dev, chan, enable) gdma_ll_tx_enable_data_burst(&GDMA, chan, enable); #define spi_dma_ll_rx_enable_burst_desc(dev, chan, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, chan, enable); #define spi_dma_ll_tx_enable_burst_desc(dev, chan, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, chan, enable); #define spi_dma_ll_enable_out_auto_wrback(dev, chan, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, chan, enable); #define spi_dma_ll_set_out_eof_generation(dev, chan, enable) gdma_ll_tx_set_eof_mode(&GDMA, chan, enable); + +#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) //TODO: IDF-6152, refactor spi hal layer +#include "hal/axi_dma_ll.h" +#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); #endif +#endif //SOC_GDMA_SUPPORTED /* The tag may be unused if log level is set to NONE */ static const __attribute__((unused)) char SPI_HAL_TAG[] = "spi_hal"; diff --git a/components/hal/spi_hal_iram.c b/components/hal/spi_hal_iram.c index b005f7943d..790cbc7ad0 100644 --- a/components/hal/spi_hal_iram.c +++ b/components/hal/spi_hal_iram.c @@ -9,13 +9,14 @@ #include "hal/spi_hal.h" #include "hal/assert.h" +#include "soc/ext_mem_defs.h" #include "soc/soc_caps.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_rx_reset(dev, chan) gdma_ll_rx_reset_channel(&GDMA, chan) #define spi_dma_ll_tx_reset(dev, chan) gdma_ll_tx_reset_channel(&GDMA, chan); #define spi_dma_ll_rx_start(dev, chan, addr) do {\ @@ -26,7 +27,21 @@ 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) //TODO: IDF-6152, refactor spi hal layer +#include "hal/axi_dma_ll.h" +#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_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 void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev) { @@ -37,7 +52,6 @@ void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *de #endif spi_ll_master_set_pos_cs(hw, dev->cs_pin_id, dev->positive_cs); spi_ll_master_set_clock_by_reg(hw, &dev->timing_conf.clock_reg); - spi_ll_set_clk_source(hw, dev->timing_conf.clock_source); //Configure bit order spi_ll_set_rx_lsbfirst(hw, dev->rx_lsbfirst); spi_ll_set_tx_lsbfirst(hw, dev->tx_lsbfirst); @@ -131,6 +145,43 @@ void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev memcpy(&hal->trans_config, trans, sizeof(spi_hal_trans_config_t)); } +#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 +//TODO: IDF-6152, refactor spi hal layer +static void s_spi_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); + 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; +} + void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev, const spi_hal_trans_config_t *trans) { spi_dev_t *hw = hal->hw; @@ -140,13 +191,13 @@ void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *de if (!hal->dma_enabled) { //No need to setup anything; we'll copy the result out of the work registers directly later. } else { - lldesc_setup_link(hal->dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true); + s_spi_hal_dma_desc_setup_link(hal->dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true); spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan); spi_ll_dma_rx_fifo_reset(hal->hw); 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); } } @@ -165,13 +216,13 @@ void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *de //Need to copy data to registers manually spi_ll_write_buffer(hw, trans->send_buffer, trans->tx_bitlen); } else { - lldesc_setup_link(hal->dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false); + s_spi_hal_dma_desc_setup_link(hal->dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false); spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan); spi_ll_dma_tx_fifo_reset(hal->hw); 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); } } diff --git a/components/hal/spi_slave_hal.c b/components/hal/spi_slave_hal.c index fd4297c21a..7c437a0b3f 100644 --- a/components/hal/spi_slave_hal.c +++ b/components/hal/spi_slave_hal.c @@ -3,17 +3,27 @@ #include "soc/soc_caps.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_rx_enable_burst_data(dev, chan, enable) gdma_ll_rx_enable_data_burst(&GDMA, chan, enable); #define spi_dma_ll_tx_enable_burst_data(dev, chan, enable) gdma_ll_tx_enable_data_burst(&GDMA, chan, enable); #define spi_dma_ll_rx_enable_burst_desc(dev, chan, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, chan, enable); #define spi_dma_ll_tx_enable_burst_desc(dev, chan, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, chan, enable); #define spi_dma_ll_enable_out_auto_wrback(dev, chan, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, chan, enable); #define spi_dma_ll_set_out_eof_generation(dev, chan, enable) gdma_ll_tx_set_eof_mode(&GDMA, chan, enable); + +#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) //TODO: IDF-6152, refactor spi hal layer +#include "hal/axi_dma_ll.h" +#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); #endif +#endif //SOC_GDMA_SUPPORTED static void s_spi_slave_hal_dma_init_config(const spi_slave_hal_context_t *hal) { diff --git a/components/hal/spi_slave_hal_iram.c b/components/hal/spi_slave_hal_iram.c index 473e147389..07c58d4045 100644 --- a/components/hal/spi_slave_hal_iram.c +++ b/components/hal/spi_slave_hal_iram.c @@ -1,12 +1,13 @@ #include "hal/spi_slave_hal.h" #include "hal/spi_ll.h" +#include "soc/ext_mem_defs.h" #include "soc/soc_caps.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_rx_reset(dev, chan) gdma_ll_rx_reset_channel(&GDMA, chan) #define spi_dma_ll_tx_reset(dev, chan) gdma_ll_tx_reset_channel(&GDMA, chan); #define spi_dma_ll_rx_start(dev, chan, addr) do {\ @@ -17,7 +18,21 @@ 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) //TODO: IDF-6152, refactor spi hal layer +#include "hal/axi_dma_ll.h" +#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_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 bool spi_slave_hal_usr_is_done(spi_slave_hal_context_t* hal) { @@ -45,10 +60,11 @@ 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[0]); + spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, hal->dmadesc_rx); } if (hal->tx_buffer) { lldesc_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); spi_ll_dma_tx_fifo_reset(hal->dma_out); @@ -56,7 +72,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[0])); + spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, hal->dmadesc_tx); } } else { //No DMA. Turn off SPI and copy data to transmit buffers. diff --git a/components/idf_test/include/esp32p4/idf_performance_target.h b/components/idf_test/include/esp32p4/idf_performance_target.h index f2c4877096..4dc137b1c1 100644 --- a/components/idf_test/include/esp32p4/idf_performance_target.h +++ b/components/idf_test/include/esp32p4/idf_performance_target.h @@ -3,3 +3,10 @@ * * SPDX-License-Identifier: Apache-2.0 */ + +//TODO: IDF-8313 update after chips back and PLL setup +#define IDF_PERFORMANCE_MAX_SPI_CLK_FREQ 10*1000*1000 +#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 1000 +#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING 1000 +#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 1000 +#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING_NO_DMA 1000 diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 58a223ffda..5e7f874cfc 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -71,6 +71,10 @@ config SOC_I2S_SUPPORTED bool default y +config SOC_GPSPI_SUPPORTED + bool + default y + config SOC_I2C_SUPPORTED bool default y @@ -801,25 +805,21 @@ config SOC_SDM_CLK_SUPPORT_XTAL config SOC_SPI_PERIPH_NUM int - default 2 + default 3 config SOC_SPI_MAX_CS_NUM int default 6 -config SOC_MEMSPI_IS_INDEPENDENT - bool - default y - config SOC_SPI_MAXIMUM_BUFFER_SIZE int default 64 -config SOC_SPI_SUPPORT_DDRCLK +config SOC_SPI_SLAVE_SUPPORT_SEG_TRANS bool default y -config SOC_SPI_SLAVE_SUPPORT_SEG_TRANS +config SOC_SPI_SUPPORT_DDRCLK bool default y @@ -827,23 +827,15 @@ config SOC_SPI_SUPPORT_CD_SIG bool default y -config SOC_SPI_SUPPORT_CONTINUOUS_TRANS +config SOC_SPI_SUPPORT_OCT bool default y -config SOC_SPI_SUPPORT_SLAVE_HD_VER2 - bool - default n - config SOC_SPI_SUPPORT_CLK_XTAL bool default y -config SOC_SPI_SUPPORT_CLK_PLL_F80M - bool - default y - -config SOC_SPI_SUPPORT_CLK_RC_FAST +config SOC_MEMSPI_IS_INDEPENDENT bool default y diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 7e9d7e61c9..5319a235dd 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -391,16 +391,20 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of SPI */ -#define SOC_SPI_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST} +#define SOC_SPI_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_SPLL} /** * @brief Type of SPI clock source. */ typedef enum { - SPI_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_80M as SPI source clock */ - SPI_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_80M as SPI source clock */ SPI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as SPI source clock */ - SPI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as SPI source clock */ +#if SOC_CLK_TREE_SUPPORTED + SPI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, + SPI_CLK_SRC_SPLL_480 = SOC_MOD_CLK_SPLL, + SPI_CLK_SRC_DEFAULT = SPI_CLK_SRC_SPLL_480, /*!< Select SPLL_480M as SPI source clock */ +#else + SPI_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as SPI source clock */ +#endif } soc_periph_spi_clk_src_t; /////////////////////////////////////////////////PSRAM//////////////////////////////////////////////////////////////////// diff --git a/components/soc/esp32p4/include/soc/ext_mem_defs.h b/components/soc/esp32p4/include/soc/ext_mem_defs.h index 0e428d116e..8f25270d19 100644 --- a/components/soc/esp32p4/include/soc/ext_mem_defs.h +++ b/components/soc/esp32p4/include/soc/ext_mem_defs.h @@ -57,6 +57,7 @@ extern "C" { #define SOC_MMU_FLASH_SENSITIVE BIT(13) #define SOC_MMU_PSRAM_SENSITIVE BIT(12) +#define SOC_NON_CACHEABLE_OFFSET 0x40000000 /** * MMU entry valid bit mask for mapping value. diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 4859f77986..7e26ff2db4 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -52,7 +52,7 @@ #define SOC_I2S_SUPPORTED 1 // #define SOC_RMT_SUPPORTED 1 //TODO: IDF-7476 // #define SOC_SDM_SUPPORTED 1 //TODO: IDF-7551 -// #define SOC_GPSPI_SUPPORTED 1 //TODO: IDF-7502, TODO: IDF-7503 +#define SOC_GPSPI_SUPPORTED 1 // #define SOC_LEDC_SUPPORTED 1 //TODO: IDF-6510 #define SOC_I2C_SUPPORTED 1 //TODO: IDF-6507, TODO: IDF-7491 #define SOC_SYSTIMER_SUPPORTED 1 @@ -378,29 +378,29 @@ #define SOC_SDM_CLK_SUPPORT_PLL_F80M 1 #define SOC_SDM_CLK_SUPPORT_XTAL 1 -// TODO: IDF-5334 (Copy from esp32c3, need check) /*-------------------------- SPI CAPS ----------------------------------------*/ -#define SOC_SPI_PERIPH_NUM 2 -#define SOC_SPI_PERIPH_CS_NUM(i) 6 -#define SOC_SPI_MAX_CS_NUM 6 - -#define SOC_MEMSPI_IS_INDEPENDENT 1 +#define SOC_SPI_PERIPH_NUM 3 +#define SOC_SPI_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3)) +#define SOC_SPI_MAX_CS_NUM 6 #define SOC_SPI_MAXIMUM_BUFFER_SIZE 64 -#define SOC_SPI_SUPPORT_DDRCLK 1 +// #define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1 //TODO: IDF-7505 #define SOC_SPI_SLAVE_SUPPORT_SEG_TRANS 1 +#define SOC_SPI_SUPPORT_DDRCLK 1 #define SOC_SPI_SUPPORT_CD_SIG 1 -#define SOC_SPI_SUPPORT_CONTINUOUS_TRANS 1 -#define SOC_SPI_SUPPORT_SLAVE_HD_VER2 0 +#define SOC_SPI_SUPPORT_OCT 1 #define SOC_SPI_SUPPORT_CLK_XTAL 1 -#define SOC_SPI_SUPPORT_CLK_PLL_F80M 1 -#define SOC_SPI_SUPPORT_CLK_RC_FAST 1 +// #define SOC_SPI_SUPPORT_CLK_RC_FAST 1 //bellow clks are waiting for clock tree +// #define SOC_SPI_SUPPORT_CLK_SPLL_F480M 1 //super pll +// #define SOC_SPI_SUPPORT_CLK_SDIO 1 //sdio pll +// #define SOC_SPI_SUPPORT_CLK_APLL 1 //audio pll // Peripheral supports DIO, DOUT, QIO, or QOUT // host_id = 0 -> SPI0/SPI1, host_id = 1 -> SPI2, #define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(host_id) ({(void)host_id; 1;}) -#define SOC_SPI_MAX_PRE_DIVIDER 16 +#define SOC_MEMSPI_IS_INDEPENDENT 1 +#define SOC_SPI_MAX_PRE_DIVIDER 16 /*-------------------------- SPI MEM CAPS ---------------------------------------*/ #define SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE (1) diff --git a/components/soc/esp32p4/include/soc/spi_pins.h b/components/soc/esp32p4/include/soc/spi_pins.h index d2aa55b41e..48b98b0169 100644 --- a/components/soc/esp32p4/include/soc/spi_pins.h +++ b/components/soc/esp32p4/include/soc/spi_pins.h @@ -5,3 +5,27 @@ */ #pragma once + +// Normal IOMUX pins +#define SPI2_FUNC_NUM 3 +#define SPI2_IOMUX_PIN_NUM_HD 6 +#define SPI2_IOMUX_PIN_NUM_CS 7 +#define SPI2_IOMUX_PIN_NUM_MOSI 8 +#define SPI2_IOMUX_PIN_NUM_CLK 9 +#define SPI2_IOMUX_PIN_NUM_MISO 10 +#define SPI2_IOMUX_PIN_NUM_WP 11 + +// When using Octal SPI, we make use of SPI2_FUNC_NUM_OCT to route them as follows. +#define SPI2_FUNC_NUM_OCT 2 +#define SPI2_IOMUX_PIN_NUM_HD_OCT 32 +#define SPI2_IOMUX_PIN_NUM_CS_OCT 28 +#define SPI2_IOMUX_PIN_NUM_MOSI_OCT 29 +#define SPI2_IOMUX_PIN_NUM_CLK_OCT 30 +#define SPI2_IOMUX_PIN_NUM_MISO_OCT 31 +#define SPI2_IOMUX_PIN_NUM_WP_OCT 33 +#define SPI2_IOMUX_PIN_NUM_IO4_OCT 34 +#define SPI2_IOMUX_PIN_NUM_IO5_OCT 35 +#define SPI2_IOMUX_PIN_NUM_IO6_OCT 36 +#define SPI2_IOMUX_PIN_NUM_IO7_OCT 37 + +//SPI3 have no iomux pins diff --git a/components/soc/esp32p4/include/soc/spi_struct.h b/components/soc/esp32p4/include/soc/spi_struct.h index 48d72046f2..66929cd3a0 100644 --- a/components/soc/esp32p4/include/soc/spi_struct.h +++ b/components/soc/esp32p4/include/soc/spi_struct.h @@ -839,198 +839,8 @@ typedef union { uint32_t val; } spi_dout_mode_reg_t; - -/** Group: Interrupt registers */ -/** Type of dma_int_ena register - * SPI interrupt enable register - */ -typedef union { - struct { - /** dma_infifo_full_err_int_ena : R/W; bitpos: [0]; default: 0; - * The enable bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt. - */ - uint32_t dma_infifo_full_err_int_ena:1; - /** dma_outfifo_empty_err_int_ena : R/W; bitpos: [1]; default: 0; - * The enable bit for SPI_DMA_OUTFIFO_EMPTY_ERR_INT interrupt. - */ - uint32_t dma_outfifo_empty_err_int_ena:1; - /** slv_ex_qpi_int_ena : R/W; bitpos: [2]; default: 0; - * The enable bit for SPI slave Ex_QPI interrupt. - */ - uint32_t slv_ex_qpi_int_ena:1; - /** slv_en_qpi_int_ena : R/W; bitpos: [3]; default: 0; - * The enable bit for SPI slave En_QPI interrupt. - */ - uint32_t slv_en_qpi_int_ena:1; - /** slv_cmd7_int_ena : R/W; bitpos: [4]; default: 0; - * The enable bit for SPI slave CMD7 interrupt. - */ - uint32_t slv_cmd7_int_ena:1; - /** slv_cmd8_int_ena : R/W; bitpos: [5]; default: 0; - * The enable bit for SPI slave CMD8 interrupt. - */ - uint32_t slv_cmd8_int_ena:1; - /** slv_cmd9_int_ena : R/W; bitpos: [6]; default: 0; - * The enable bit for SPI slave CMD9 interrupt. - */ - uint32_t slv_cmd9_int_ena:1; - /** slv_cmda_int_ena : R/W; bitpos: [7]; default: 0; - * The enable bit for SPI slave CMDA interrupt. - */ - uint32_t slv_cmda_int_ena:1; - /** slv_rd_dma_done_int_ena : R/W; bitpos: [8]; default: 0; - * The enable bit for SPI_SLV_RD_DMA_DONE_INT interrupt. - */ - uint32_t slv_rd_dma_done_int_ena:1; - /** slv_wr_dma_done_int_ena : R/W; bitpos: [9]; default: 0; - * The enable bit for SPI_SLV_WR_DMA_DONE_INT interrupt. - */ - uint32_t slv_wr_dma_done_int_ena:1; - /** slv_rd_buf_done_int_ena : R/W; bitpos: [10]; default: 0; - * The enable bit for SPI_SLV_RD_BUF_DONE_INT interrupt. - */ - uint32_t slv_rd_buf_done_int_ena:1; - /** slv_wr_buf_done_int_ena : R/W; bitpos: [11]; default: 0; - * The enable bit for SPI_SLV_WR_BUF_DONE_INT interrupt. - */ - uint32_t slv_wr_buf_done_int_ena:1; - /** trans_done_int_ena : R/W; bitpos: [12]; default: 0; - * The enable bit for SPI_TRANS_DONE_INT interrupt. - */ - uint32_t trans_done_int_ena:1; - /** dma_seg_trans_done_int_ena : R/W; bitpos: [13]; default: 0; - * The enable bit for SPI_DMA_SEG_TRANS_DONE_INT interrupt. - */ - uint32_t dma_seg_trans_done_int_ena:1; - /** seg_magic_err_int_ena : R/W; bitpos: [14]; default: 0; - * The enable bit for SPI_SEG_MAGIC_ERR_INT interrupt. - */ - uint32_t seg_magic_err_int_ena:1; //this field is only for GPSPI2 - /** slv_buf_addr_err_int_ena : R/W; bitpos: [15]; default: 0; - * The enable bit for SPI_SLV_BUF_ADDR_ERR_INT interrupt. - */ - uint32_t slv_buf_addr_err_int_ena:1; - /** slv_cmd_err_int_ena : R/W; bitpos: [16]; default: 0; - * The enable bit for SPI_SLV_CMD_ERR_INT interrupt. - */ - uint32_t slv_cmd_err_int_ena:1; - /** mst_rx_afifo_wfull_err_int_ena : R/W; bitpos: [17]; default: 0; - * The enable bit for SPI_MST_RX_AFIFO_WFULL_ERR_INT interrupt. - */ - uint32_t mst_rx_afifo_wfull_err_int_ena:1; - /** mst_tx_afifo_rempty_err_int_ena : R/W; bitpos: [18]; default: 0; - * The enable bit for SPI_MST_TX_AFIFO_REMPTY_ERR_INT interrupt. - */ - uint32_t mst_tx_afifo_rempty_err_int_ena:1; - /** app2_int_ena : R/W; bitpos: [19]; default: 0; - * The enable bit for SPI_APP2_INT interrupt. - */ - uint32_t app2_int_ena:1; - /** app1_int_ena : R/W; bitpos: [20]; default: 0; - * The enable bit for SPI_APP1_INT interrupt. - */ - uint32_t app1_int_ena:1; - uint32_t reserved_21:11; - }; - uint32_t val; -} spi_dma_int_ena_reg_t; - -/** Type of dma_int_clr register - * SPI interrupt clear register - */ -typedef union { - struct { - /** dma_infifo_full_err_int_clr : WT; bitpos: [0]; default: 0; - * The clear bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt. - */ - uint32_t dma_infifo_full_err_int_clr:1; - /** dma_outfifo_empty_err_int_clr : WT; bitpos: [1]; default: 0; - * The clear bit for SPI_DMA_OUTFIFO_EMPTY_ERR_INT interrupt. - */ - uint32_t dma_outfifo_empty_err_int_clr:1; - /** slv_ex_qpi_int_clr : WT; bitpos: [2]; default: 0; - * The clear bit for SPI slave Ex_QPI interrupt. - */ - uint32_t slv_ex_qpi_int_clr:1; - /** slv_en_qpi_int_clr : WT; bitpos: [3]; default: 0; - * The clear bit for SPI slave En_QPI interrupt. - */ - uint32_t slv_en_qpi_int_clr:1; - /** slv_cmd7_int_clr : WT; bitpos: [4]; default: 0; - * The clear bit for SPI slave CMD7 interrupt. - */ - uint32_t slv_cmd7_int_clr:1; - /** slv_cmd8_int_clr : WT; bitpos: [5]; default: 0; - * The clear bit for SPI slave CMD8 interrupt. - */ - uint32_t slv_cmd8_int_clr:1; - /** slv_cmd9_int_clr : WT; bitpos: [6]; default: 0; - * The clear bit for SPI slave CMD9 interrupt. - */ - uint32_t slv_cmd9_int_clr:1; - /** slv_cmda_int_clr : WT; bitpos: [7]; default: 0; - * The clear bit for SPI slave CMDA interrupt. - */ - uint32_t slv_cmda_int_clr:1; - /** slv_rd_dma_done_int_clr : WT; bitpos: [8]; default: 0; - * The clear bit for SPI_SLV_RD_DMA_DONE_INT interrupt. - */ - uint32_t slv_rd_dma_done_int_clr:1; - /** slv_wr_dma_done_int_clr : WT; bitpos: [9]; default: 0; - * The clear bit for SPI_SLV_WR_DMA_DONE_INT interrupt. - */ - uint32_t slv_wr_dma_done_int_clr:1; - /** slv_rd_buf_done_int_clr : WT; bitpos: [10]; default: 0; - * The clear bit for SPI_SLV_RD_BUF_DONE_INT interrupt. - */ - uint32_t slv_rd_buf_done_int_clr:1; - /** slv_wr_buf_done_int_clr : WT; bitpos: [11]; default: 0; - * The clear bit for SPI_SLV_WR_BUF_DONE_INT interrupt. - */ - uint32_t slv_wr_buf_done_int_clr:1; - /** trans_done_int_clr : WT; bitpos: [12]; default: 0; - * The clear bit for SPI_TRANS_DONE_INT interrupt. - */ - uint32_t trans_done_int_clr:1; - /** dma_seg_trans_done_int_clr : WT; bitpos: [13]; default: 0; - * The clear bit for SPI_DMA_SEG_TRANS_DONE_INT interrupt. - */ - uint32_t dma_seg_trans_done_int_clr:1; - /** seg_magic_err_int_clr : WT; bitpos: [14]; default: 0; - * The clear bit for SPI_SEG_MAGIC_ERR_INT interrupt. - */ - uint32_t seg_magic_err_int_clr:1; //this field is only for GPSPI2 - /** slv_buf_addr_err_int_clr : WT; bitpos: [15]; default: 0; - * The clear bit for SPI_SLV_BUF_ADDR_ERR_INT interrupt. - */ - uint32_t slv_buf_addr_err_int_clr:1; - /** slv_cmd_err_int_clr : WT; bitpos: [16]; default: 0; - * The clear bit for SPI_SLV_CMD_ERR_INT interrupt. - */ - uint32_t slv_cmd_err_int_clr:1; - /** mst_rx_afifo_wfull_err_int_clr : WT; bitpos: [17]; default: 0; - * The clear bit for SPI_MST_RX_AFIFO_WFULL_ERR_INT interrupt. - */ - uint32_t mst_rx_afifo_wfull_err_int_clr:1; - /** mst_tx_afifo_rempty_err_int_clr : WT; bitpos: [18]; default: 0; - * The clear bit for SPI_MST_TX_AFIFO_REMPTY_ERR_INT interrupt. - */ - uint32_t mst_tx_afifo_rempty_err_int_clr:1; - /** app2_int_clr : WT; bitpos: [19]; default: 0; - * The clear bit for SPI_APP2_INT interrupt. - */ - uint32_t app2_int_clr:1; - /** app1_int_clr : WT; bitpos: [20]; default: 0; - * The clear bit for SPI_APP1_INT interrupt. - */ - uint32_t app1_int_clr:1; - uint32_t reserved_21:11; - }; - uint32_t val; -} spi_dma_int_clr_reg_t; - -/** Type of dma_int_raw register - * SPI interrupt raw register +/** Type of dma_int register + * SPI interrupt raw/ena/clr/sta/set register */ typedef union { struct { @@ -1038,301 +848,112 @@ typedef union { * 1: The current data rate of DMA Rx is smaller than that of SPI, which will lose the * receive data. 0: Others. */ - uint32_t dma_infifo_full_err_int_raw:1; + uint32_t dma_infifo_full_err_int:1; /** dma_outfifo_empty_err_int_raw : R/WTC/SS; bitpos: [1]; default: 0; * 1: The current data rate of DMA TX is smaller than that of SPI. SPI will stop in * master mode and send out all 0 in slave mode. 0: Others. */ - uint32_t dma_outfifo_empty_err_int_raw:1; + uint32_t dma_outfifo_empty_err_int:1; /** slv_ex_qpi_int_raw : R/WTC/SS; bitpos: [2]; default: 0; * The raw bit for SPI slave Ex_QPI interrupt. 1: SPI slave mode Ex_QPI transmission * is ended. 0: Others. */ - uint32_t slv_ex_qpi_int_raw:1; + uint32_t slv_ex_qpi_int:1; /** slv_en_qpi_int_raw : R/WTC/SS; bitpos: [3]; default: 0; * The raw bit for SPI slave En_QPI interrupt. 1: SPI slave mode En_QPI transmission * is ended. 0: Others. */ - uint32_t slv_en_qpi_int_raw:1; + uint32_t slv_en_qpi_int:1; /** slv_cmd7_int_raw : R/WTC/SS; bitpos: [4]; default: 0; * The raw bit for SPI slave CMD7 interrupt. 1: SPI slave mode CMD7 transmission is * ended. 0: Others. */ - uint32_t slv_cmd7_int_raw:1; + uint32_t slv_cmd7_int:1; /** slv_cmd8_int_raw : R/WTC/SS; bitpos: [5]; default: 0; * The raw bit for SPI slave CMD8 interrupt. 1: SPI slave mode CMD8 transmission is * ended. 0: Others. */ - uint32_t slv_cmd8_int_raw:1; + uint32_t slv_cmd8_int:1; /** slv_cmd9_int_raw : R/WTC/SS; bitpos: [6]; default: 0; * The raw bit for SPI slave CMD9 interrupt. 1: SPI slave mode CMD9 transmission is * ended. 0: Others. */ - uint32_t slv_cmd9_int_raw:1; + uint32_t slv_cmd9_int:1; /** slv_cmda_int_raw : R/WTC/SS; bitpos: [7]; default: 0; * The raw bit for SPI slave CMDA interrupt. 1: SPI slave mode CMDA transmission is * ended. 0: Others. */ - uint32_t slv_cmda_int_raw:1; + uint32_t slv_cmda_int:1; /** slv_rd_dma_done_int_raw : R/WTC/SS; bitpos: [8]; default: 0; * The raw bit for SPI_SLV_RD_DMA_DONE_INT interrupt. 1: SPI slave mode Rd_DMA * transmission is ended. 0: Others. */ - uint32_t slv_rd_dma_done_int_raw:1; + uint32_t slv_rd_dma_done_int:1; /** slv_wr_dma_done_int_raw : R/WTC/SS; bitpos: [9]; default: 0; * The raw bit for SPI_SLV_WR_DMA_DONE_INT interrupt. 1: SPI slave mode Wr_DMA * transmission is ended. 0: Others. */ - uint32_t slv_wr_dma_done_int_raw:1; + uint32_t slv_wr_dma_done_int:1; /** slv_rd_buf_done_int_raw : R/WTC/SS; bitpos: [10]; default: 0; * The raw bit for SPI_SLV_RD_BUF_DONE_INT interrupt. 1: SPI slave mode Rd_BUF * transmission is ended. 0: Others. */ - uint32_t slv_rd_buf_done_int_raw:1; + uint32_t slv_rd_buf_done_int:1; /** slv_wr_buf_done_int_raw : R/WTC/SS; bitpos: [11]; default: 0; * The raw bit for SPI_SLV_WR_BUF_DONE_INT interrupt. 1: SPI slave mode Wr_BUF * transmission is ended. 0: Others. */ - uint32_t slv_wr_buf_done_int_raw:1; + uint32_t slv_wr_buf_done_int:1; /** trans_done_int_raw : R/WTC/SS; bitpos: [12]; default: 0; * The raw bit for SPI_TRANS_DONE_INT interrupt. 1: SPI master mode transmission is * ended. 0: others. */ - uint32_t trans_done_int_raw:1; + uint32_t trans_done_int:1; /** dma_seg_trans_done_int_raw : R/WTC/SS; bitpos: [13]; default: 0; * The raw bit for SPI_DMA_SEG_TRANS_DONE_INT interrupt. 1: spi master DMA * full-duplex/half-duplex seg-conf-trans ends or slave half-duplex seg-trans ends. * And data has been pushed to corresponding memory. 0: seg-conf-trans or seg-trans * is not ended or not occurred. */ - uint32_t dma_seg_trans_done_int_raw:1; + uint32_t dma_seg_trans_done_int:1; /** seg_magic_err_int_raw : R/WTC/SS; bitpos: [14]; default: 0; * The raw bit for SPI_SEG_MAGIC_ERR_INT interrupt. 1: The magic value in CONF buffer * is error in the DMA seg-conf-trans. 0: others. */ - uint32_t seg_magic_err_int_raw:1; //this field is only for GPSPI2 + uint32_t seg_magic_err_int_raw:1; //this field is only forPI2 /** slv_buf_addr_err_int_raw : R/WTC/SS; bitpos: [15]; default: 0; * The raw bit for SPI_SLV_BUF_ADDR_ERR_INT interrupt. 1: The accessing data address * of the current SPI slave mode CPU controlled FD, Wr_BUF or Rd_BUF transmission is * bigger than 63. 0: Others. */ - uint32_t slv_buf_addr_err_int_raw:1; + uint32_t slv_buf_addr_err_int:1; /** slv_cmd_err_int_raw : R/WTC/SS; bitpos: [16]; default: 0; * The raw bit for SPI_SLV_CMD_ERR_INT interrupt. 1: The slave command value in the * current SPI slave HD mode transmission is not supported. 0: Others. */ - uint32_t slv_cmd_err_int_raw:1; + uint32_t slv_cmd_err_int:1; /** mst_rx_afifo_wfull_err_int_raw : R/WTC/SS; bitpos: [17]; default: 0; * The raw bit for SPI_MST_RX_AFIFO_WFULL_ERR_INT interrupt. 1: There is a RX AFIFO * write-full error when SPI inputs data in master mode. 0: Others. */ - uint32_t mst_rx_afifo_wfull_err_int_raw:1; + uint32_t mst_rx_afifo_wfull_err_int:1; /** mst_tx_afifo_rempty_err_int_raw : R/WTC/SS; bitpos: [18]; default: 0; * The raw bit for SPI_MST_TX_AFIFO_REMPTY_ERR_INT interrupt. 1: There is a TX BUF * AFIFO read-empty error when SPI outputs data in master mode. 0: Others. */ - uint32_t mst_tx_afifo_rempty_err_int_raw:1; + uint32_t mst_tx_afifo_rempty_err_int:1; /** app2_int_raw : R/WTC/SS; bitpos: [19]; default: 0; * The raw bit for SPI_APP2_INT interrupt. The value is only controlled by software. */ - uint32_t app2_int_raw:1; + uint32_t app2_int:1; /** app1_int_raw : R/WTC/SS; bitpos: [20]; default: 0; * The raw bit for SPI_APP1_INT interrupt. The value is only controlled by software. */ - uint32_t app1_int_raw:1; + uint32_t app1_int:1; uint32_t reserved_21:11; }; uint32_t val; -} spi_dma_int_raw_reg_t; - -/** Type of dma_int_st register - * SPI interrupt status register - */ -typedef union { - struct { - /** dma_infifo_full_err_int_st : RO; bitpos: [0]; default: 0; - * The status bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt. - */ - uint32_t dma_infifo_full_err_int_st:1; - /** dma_outfifo_empty_err_int_st : RO; bitpos: [1]; default: 0; - * The status bit for SPI_DMA_OUTFIFO_EMPTY_ERR_INT interrupt. - */ - uint32_t dma_outfifo_empty_err_int_st:1; - /** slv_ex_qpi_int_st : RO; bitpos: [2]; default: 0; - * The status bit for SPI slave Ex_QPI interrupt. - */ - uint32_t slv_ex_qpi_int_st:1; - /** slv_en_qpi_int_st : RO; bitpos: [3]; default: 0; - * The status bit for SPI slave En_QPI interrupt. - */ - uint32_t slv_en_qpi_int_st:1; - /** slv_cmd7_int_st : RO; bitpos: [4]; default: 0; - * The status bit for SPI slave CMD7 interrupt. - */ - uint32_t slv_cmd7_int_st:1; - /** slv_cmd8_int_st : RO; bitpos: [5]; default: 0; - * The status bit for SPI slave CMD8 interrupt. - */ - uint32_t slv_cmd8_int_st:1; - /** slv_cmd9_int_st : RO; bitpos: [6]; default: 0; - * The status bit for SPI slave CMD9 interrupt. - */ - uint32_t slv_cmd9_int_st:1; - /** slv_cmda_int_st : RO; bitpos: [7]; default: 0; - * The status bit for SPI slave CMDA interrupt. - */ - uint32_t slv_cmda_int_st:1; - /** slv_rd_dma_done_int_st : RO; bitpos: [8]; default: 0; - * The status bit for SPI_SLV_RD_DMA_DONE_INT interrupt. - */ - uint32_t slv_rd_dma_done_int_st:1; - /** slv_wr_dma_done_int_st : RO; bitpos: [9]; default: 0; - * The status bit for SPI_SLV_WR_DMA_DONE_INT interrupt. - */ - uint32_t slv_wr_dma_done_int_st:1; - /** slv_rd_buf_done_int_st : RO; bitpos: [10]; default: 0; - * The status bit for SPI_SLV_RD_BUF_DONE_INT interrupt. - */ - uint32_t slv_rd_buf_done_int_st:1; - /** slv_wr_buf_done_int_st : RO; bitpos: [11]; default: 0; - * The status bit for SPI_SLV_WR_BUF_DONE_INT interrupt. - */ - uint32_t slv_wr_buf_done_int_st:1; - /** trans_done_int_st : RO; bitpos: [12]; default: 0; - * The status bit for SPI_TRANS_DONE_INT interrupt. - */ - uint32_t trans_done_int_st:1; - /** dma_seg_trans_done_int_st : RO; bitpos: [13]; default: 0; - * The status bit for SPI_DMA_SEG_TRANS_DONE_INT interrupt. - */ - uint32_t dma_seg_trans_done_int_st:1; - /** seg_magic_err_int_st : RO; bitpos: [14]; default: 0; - * The status bit for SPI_SEG_MAGIC_ERR_INT interrupt. - */ - uint32_t seg_magic_err_int_st:1; //this field is only for GPSPI2 - /** slv_buf_addr_err_int_st : RO; bitpos: [15]; default: 0; - * The status bit for SPI_SLV_BUF_ADDR_ERR_INT interrupt. - */ - uint32_t slv_buf_addr_err_int_st:1; - /** slv_cmd_err_int_st : RO; bitpos: [16]; default: 0; - * The status bit for SPI_SLV_CMD_ERR_INT interrupt. - */ - uint32_t slv_cmd_err_int_st:1; - /** mst_rx_afifo_wfull_err_int_st : RO; bitpos: [17]; default: 0; - * The status bit for SPI_MST_RX_AFIFO_WFULL_ERR_INT interrupt. - */ - uint32_t mst_rx_afifo_wfull_err_int_st:1; - /** mst_tx_afifo_rempty_err_int_st : RO; bitpos: [18]; default: 0; - * The status bit for SPI_MST_TX_AFIFO_REMPTY_ERR_INT interrupt. - */ - uint32_t mst_tx_afifo_rempty_err_int_st:1; - /** app2_int_st : RO; bitpos: [19]; default: 0; - * The status bit for SPI_APP2_INT interrupt. - */ - uint32_t app2_int_st:1; - /** app1_int_st : RO; bitpos: [20]; default: 0; - * The status bit for SPI_APP1_INT interrupt. - */ - uint32_t app1_int_st:1; - uint32_t reserved_21:11; - }; - uint32_t val; -} spi_dma_int_st_reg_t; - -/** Type of dma_int_set register - * SPI interrupt software set register - */ -typedef union { - struct { - /** dma_infifo_full_err_int_set : WT; bitpos: [0]; default: 0; - * The software set bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt. - */ - uint32_t dma_infifo_full_err_int_set:1; - /** dma_outfifo_empty_err_int_set : WT; bitpos: [1]; default: 0; - * The software set bit for SPI_DMA_OUTFIFO_EMPTY_ERR_INT interrupt. - */ - uint32_t dma_outfifo_empty_err_int_set:1; - /** slv_ex_qpi_int_set : WT; bitpos: [2]; default: 0; - * The software set bit for SPI slave Ex_QPI interrupt. - */ - uint32_t slv_ex_qpi_int_set:1; - /** slv_en_qpi_int_set : WT; bitpos: [3]; default: 0; - * The software set bit for SPI slave En_QPI interrupt. - */ - uint32_t slv_en_qpi_int_set:1; - /** slv_cmd7_int_set : WT; bitpos: [4]; default: 0; - * The software set bit for SPI slave CMD7 interrupt. - */ - uint32_t slv_cmd7_int_set:1; - /** slv_cmd8_int_set : WT; bitpos: [5]; default: 0; - * The software set bit for SPI slave CMD8 interrupt. - */ - uint32_t slv_cmd8_int_set:1; - /** slv_cmd9_int_set : WT; bitpos: [6]; default: 0; - * The software set bit for SPI slave CMD9 interrupt. - */ - uint32_t slv_cmd9_int_set:1; - /** slv_cmda_int_set : WT; bitpos: [7]; default: 0; - * The software set bit for SPI slave CMDA interrupt. - */ - uint32_t slv_cmda_int_set:1; - /** slv_rd_dma_done_int_set : WT; bitpos: [8]; default: 0; - * The software set bit for SPI_SLV_RD_DMA_DONE_INT interrupt. - */ - uint32_t slv_rd_dma_done_int_set:1; - /** slv_wr_dma_done_int_set : WT; bitpos: [9]; default: 0; - * The software set bit for SPI_SLV_WR_DMA_DONE_INT interrupt. - */ - uint32_t slv_wr_dma_done_int_set:1; - /** slv_rd_buf_done_int_set : WT; bitpos: [10]; default: 0; - * The software set bit for SPI_SLV_RD_BUF_DONE_INT interrupt. - */ - uint32_t slv_rd_buf_done_int_set:1; - /** slv_wr_buf_done_int_set : WT; bitpos: [11]; default: 0; - * The software set bit for SPI_SLV_WR_BUF_DONE_INT interrupt. - */ - uint32_t slv_wr_buf_done_int_set:1; - /** trans_done_int_set : WT; bitpos: [12]; default: 0; - * The software set bit for SPI_TRANS_DONE_INT interrupt. - */ - uint32_t trans_done_int_set:1; - /** dma_seg_trans_done_int_set : WT; bitpos: [13]; default: 0; - * The software set bit for SPI_DMA_SEG_TRANS_DONE_INT interrupt. - */ - uint32_t dma_seg_trans_done_int_set:1; - /** seg_magic_err_int_set : WT; bitpos: [14]; default: 0; - * The software set bit for SPI_SEG_MAGIC_ERR_INT interrupt. - */ - uint32_t seg_magic_err_int_set:1; //this field is only for GPSPI2 - /** slv_buf_addr_err_int_set : WT; bitpos: [15]; default: 0; - * The software set bit for SPI_SLV_BUF_ADDR_ERR_INT interrupt. - */ - uint32_t slv_buf_addr_err_int_set:1; - /** slv_cmd_err_int_set : WT; bitpos: [16]; default: 0; - * The software set bit for SPI_SLV_CMD_ERR_INT interrupt. - */ - uint32_t slv_cmd_err_int_set:1; - /** mst_rx_afifo_wfull_err_int_set : WT; bitpos: [17]; default: 0; - * The software set bit for SPI_MST_RX_AFIFO_WFULL_ERR_INT interrupt. - */ - uint32_t mst_rx_afifo_wfull_err_int_set:1; - /** mst_tx_afifo_rempty_err_int_set : WT; bitpos: [18]; default: 0; - * The software set bit for SPI_MST_TX_AFIFO_REMPTY_ERR_INT interrupt. - */ - uint32_t mst_tx_afifo_rempty_err_int_set:1; - /** app2_int_set : WT; bitpos: [19]; default: 0; - * The software set bit for SPI_APP2_INT interrupt. - */ - uint32_t app2_int_set:1; - /** app1_int_set : WT; bitpos: [20]; default: 0; - * The software set bit for SPI_APP1_INT interrupt. - */ - uint32_t app1_int_set:1; - uint32_t reserved_21:11; - }; - uint32_t val; -} spi_dma_int_set_reg_t; - +} spi_dma_int_reg_t; /** Type of wn register * SPI CPU-controlled buffer @@ -1378,11 +999,11 @@ typedef struct { volatile spi_din_num_reg_t din_num; volatile spi_dout_mode_reg_t dout_mode; volatile spi_dma_conf_reg_t dma_conf; - volatile spi_dma_int_ena_reg_t dma_int_ena; - volatile spi_dma_int_clr_reg_t dma_int_clr; - volatile spi_dma_int_raw_reg_t dma_int_raw; - volatile spi_dma_int_st_reg_t dma_int_st; - volatile spi_dma_int_set_reg_t dma_int_set; + volatile spi_dma_int_reg_t dma_int_ena; + volatile spi_dma_int_reg_t dma_int_clr; + volatile spi_dma_int_reg_t dma_int_raw; + volatile spi_dma_int_reg_t dma_int_sta; + volatile spi_dma_int_reg_t dma_int_set; uint32_t reserved_048[20]; volatile spi_wn_reg_t data_buf[16]; uint32_t reserved_0d8[2]; diff --git a/components/soc/esp32p4/spi_periph.c b/components/soc/esp32p4/spi_periph.c index 3534bb9428..90f30522d9 100644 --- a/components/soc/esp32p4/spi_periph.c +++ b/components/soc/esp32p4/spi_periph.c @@ -11,5 +11,88 @@ Bunch of constants for every SPI peripheral: GPIO signals, irqs, hw addr of registers etc */ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { - + { + // MSPI on P4 has dedicated iomux pins + .spiclk_out = -1, + .spiclk_in = -1, + .spid_out = -1, + .spiq_out = -1, + .spiwp_out = -1, + .spihd_out = -1, + .spid_in = -1, + .spiq_in = -1, + .spiwp_in = -1, + .spihd_in = -1, + .spics_out = {-1}, + .spics_in = -1, + .spiclk_iomux_pin = -1, + .spid_iomux_pin = -1, + .spiq_iomux_pin = -1, + .spiwp_iomux_pin = -1, + .spihd_iomux_pin = -1, + .spics0_iomux_pin = -1, + .irq = -1, + .irq_dma = -1, + .module = -1, + .hw = NULL, + .func = -1, + }, { + .spiclk_out = SPI2_CK_PAD_OUT_IDX, + .spiclk_in = SPI2_CK_PAD_IN_IDX, + .spid_out = SPI2_D_PAD_OUT_IDX, + .spiq_out = SPI2_Q_PAD_OUT_IDX, + .spiwp_out = SPI2_WP_PAD_OUT_IDX, + .spihd_out = SPI2_HOLD_PAD_OUT_IDX, + .spid4_out = SPI2_IO4_PAD_OUT_IDX, + .spid5_out = SPI2_IO5_PAD_OUT_IDX, + .spid6_out = SPI2_IO6_PAD_OUT_IDX, + .spid7_out = SPI2_IO7_PAD_OUT_IDX, + .spid_in = SPI2_D_PAD_IN_IDX, + .spiq_in = SPI2_Q_PAD_IN_IDX, + .spiwp_in = SPI2_WP_PAD_IN_IDX, + .spihd_in = SPI2_HOLD_PAD_IN_IDX, + .spid4_in = SPI2_IO4_PAD_IN_IDX, + .spid5_in = SPI2_IO5_PAD_IN_IDX, + .spid6_in = SPI2_IO6_PAD_IN_IDX, + .spid7_in = SPI2_IO7_PAD_IN_IDX, + .spics_out = {SPI2_CS_PAD_OUT_IDX, SPI2_CS1_PAD_OUT_IDX, SPI2_CS2_PAD_OUT_IDX, SPI2_CS3_PAD_OUT_IDX, SPI2_CS4_PAD_OUT_IDX, SPI2_CS5_PAD_OUT_IDX}, + .spics_in = SPI2_CS_PAD_IN_IDX, + .spiclk_iomux_pin = SPI2_IOMUX_PIN_NUM_CLK, + .spid_iomux_pin = SPI2_IOMUX_PIN_NUM_MOSI, + .spiq_iomux_pin = SPI2_IOMUX_PIN_NUM_MISO, + .spiwp_iomux_pin = SPI2_IOMUX_PIN_NUM_WP, + .spihd_iomux_pin = SPI2_IOMUX_PIN_NUM_HD, + .spics0_iomux_pin = SPI2_IOMUX_PIN_NUM_CS, + .irq = ETS_SPI2_INTR_SOURCE, + .irq_dma = -1, + .module = PERIPH_GPSPI2_MODULE, + .hw = &GPSPI2, + .func = SPI2_FUNC_NUM, + }, { + .spiclk_out = SPI3_CK_PAD_OUT_IDX, + .spiclk_in = SPI3_CK_PAD_IN_IDX, + .spid_out = SPI3_D_PAD_OUT_IDX, + .spiq_out = SPI3_QO_PAD_OUT_IDX, + //SPI3 doesn't have wp and hd signals + .spiwp_out = SPI3_WP_PAD_OUT_IDX, + .spihd_out = SPI3_HOLD_PAD_OUT_IDX, + .spid_in = SPI3_D_PAD_IN_IDX, + .spiq_in = SPI3_Q_PAD_IN_IDX, + .spiwp_in = SPI3_WP_PAD_IN_IDX, + .spihd_in = SPI3_HOLD_PAD_IN_IDX, + .spics_out = {SPI3_CS_PAD_OUT_IDX, SPI3_CS1_PAD_OUT_IDX, SPI3_CS2_PAD_OUT_IDX}, + .spics_in = SPI3_CS_PAD_IN_IDX, + //SPI3 doesn't have iomux pins + .spiclk_iomux_pin = -1, + .spid_iomux_pin = -1, + .spiq_iomux_pin = -1, + .spiwp_iomux_pin = -1, + .spihd_iomux_pin = -1, + .spics0_iomux_pin = -1, + .irq = ETS_SPI3_INTR_SOURCE, + .irq_dma = -1, + .module = PERIPH_GPSPI3_MODULE, + .hw = &GPSPI3, + .func = -1, + } }; diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index c4061400c6..6ed3f4c6fa 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -117,7 +117,6 @@ api-reference/peripherals/ana_cmpr.rst api-reference/peripherals/secure_element.rst api-reference/peripherals/ledc.rst api-reference/peripherals/temp_sensor.rst -api-reference/peripherals/spi_features.rst api-reference/peripherals/sdio_slave.rst api-reference/peripherals/clk_tree.rst api-reference/peripherals/spi_flash/xip_from_psram.inc @@ -136,7 +135,6 @@ api-reference/peripherals/ds.rst api-reference/peripherals/i2c.rst api-reference/peripherals/dedic_gpio.rst api-reference/peripherals/sd_pullup_requirements.rst -api-reference/peripherals/spi_master.rst api-reference/peripherals/index.rst api-reference/peripherals/sdmmc_host.rst api-reference/peripherals/uart.rst diff --git a/docs/en/api-reference/peripherals/spi_master.rst b/docs/en/api-reference/peripherals/spi_master.rst index 78773b390d..fadf01d781 100644 --- a/docs/en/api-reference/peripherals/spi_master.rst +++ b/docs/en/api-reference/peripherals/spi_master.rst @@ -8,7 +8,7 @@ SPI Master driver is a program that controls {IDF_TARGET_NAME}'s General Purpose .. only:: esp32 .. note:: - + SPI1 is not a GP-SPI. SPI Master driver also supports SPI1 but with quite a few limitations, see :ref:`spi_master_on_spi1_bus`. For more hardware information about the GP-SPI peripheral(s), see **{IDF_TARGET_NAME} Technical Reference Manual** > **SPI Controller** [`PDF <{IDF_TARGET_TRM_EN_URL}#spi>`__]. @@ -182,28 +182,28 @@ Supported line modes for {IDF_TARGET_NAME} are listed as follows, to make use of - 1 - 1 - 2 - - {SPI_TRANS_MODE_DIO} - - {SPICOMMON_BUSFLAG_DUAL} + - SPI_TRANS_MODE_DIO + - SPICOMMON_BUSFLAG_DUAL * - Dual I/O - 1 - 2 - 2 - - * {SPI_TRANS_MODE_DIO} - * {SPI_TRANS_MULTILINE_ADDR} - - + - SPI_TRANS_MODE_DIO + SPI_TRANS_MULTILINE_ADDR + - SPICOMMON_BUSFLAG_DUAL * - Quad Output - 1 - 1 - 4 - - {SPI_TRANS_MODE_QIO} - - {SPICOMMON_BUSFLAG_QUAD} + - SPI_TRANS_MODE_QIO + - SPICOMMON_BUSFLAG_QUAD * - Quad I/O - 1 - 4 - 4 - - * {SPI_TRANS_MODE_QIO} - * {SPI_TRANS_MULTILINE_ADDR} - - {SPICOMMON_BUSFLAG_QUAD} + - SPI_TRANS_MODE_QIO + SPI_TRANS_MULTILINE_ADDR + - SPICOMMON_BUSFLAG_QUAD .. only:: SOC_SPI_SUPPORT_OCT @@ -227,42 +227,42 @@ Supported line modes for {IDF_TARGET_NAME} are listed as follows, to make use of - 1 - 1 - 2 - - {SPI_TRANS_MODE_DIO} - - {SPICOMMON_BUSFLAG_DUAL} + - SPI_TRANS_MODE_DIO + - SPICOMMON_BUSFLAG_DUAL * - Dual I/O - 1 - 2 - 2 - - * {SPI_TRANS_MODE_DIO} - * {SPI_TRANS_MULTILINE_ADDR} - - + - SPI_TRANS_MODE_DIO + SPI_TRANS_MULTILINE_ADDR + - SPICOMMON_BUSFLAG_DUAL * - Quad Output - 1 - 1 - 4 - - {SPI_TRANS_MODE_QIO} - - {SPICOMMON_BUSFLAG_QUAD} + - SPI_TRANS_MODE_QIO + - SPICOMMON_BUSFLAG_QUAD * - Quad I/O - 1 - 4 - 4 - - * {SPI_TRANS_MODE_QIO} - * {SPI_TRANS_MULTILINE_ADDR} - - {SPICOMMON_BUSFLAG_QUAD} + - SPI_TRANS_MODE_QIO + SPI_TRANS_MULTILINE_ADDR + - SPICOMMON_BUSFLAG_QUAD * - Octal Output - 1 - 1 - 8 - - {SPI_TRANS_MODE_OCT} - - {SPICOMMON_BUSFLAG_OCTAL} + - SPI_TRANS_MODE_OCT + - SPICOMMON_BUSFLAG_OCTAL * - OPI - 8 - 8 - 8 - - * {SPI_TRANS_MODE_OCT} - * {SPI_TRANS_MULTILINE_ADDR} - * {SPI_TRANS_MULTILINE_CMD} - - {SPICOMMON_BUSFLAG_OCTAL} + - SPI_TRANS_MODE_OCT + SPI_TRANS_MULTILINE_ADDR + SPI_TRANS_MULTILINE_CMD + - SPICOMMON_BUSFLAG_OCTAL Command and Address Phases ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -292,7 +292,7 @@ If using more than one data line to transmit, please set ``SPI_DEVICE_HALFDUPLEX Half-duplex transactions with both Read and Write phases are not supported when using DMA. For details and workarounds, see :ref:`spi_known_issues`. -.. only:: esp32s3 or esp32c3 or esp32c2 or esp32c6 or esp32h2 +.. only:: not SOC_SPI_HD_BOTH_INOUT_SUPPORTED .. note:: @@ -455,7 +455,7 @@ GPIO Matrix and IO_MUX * - CS0 [1]_ - 15 - 5 - * - SCLK + * - SCLK - 14 - 18 * - MISO @@ -469,16 +469,16 @@ GPIO Matrix and IO_MUX - 22 * - QUADHD - 4 - - 21 + - 21 .. 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 the chip's peripheral signals have a 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. @@ -639,7 +639,7 @@ For an interrupt transaction, the overall cost is **20+8n/Fspi[MHz]** [µs] for - 25 - 128 - 153 - - 836.6 + - 836.6 When a transaction length is short, the cost of the transaction interval is high. If possible, try to squash several short transactions into one transaction to achieve a higher transfer speed. @@ -769,11 +769,9 @@ Please note that the ISR is disabled during flash operation by default. To keep - 11.43 * - 75 - 100 - - 8.89 + - 8.89 -.. only:: esp32 - .. _spi_known_issues: Known Issues @@ -802,6 +800,7 @@ Application Example The code example for using the SPI master half duplex mode to read/write an AT93C46D EEPROM (8-bit mode) can be found in the :example:`peripherals/spi_master/hd_eeprom` directory of ESP-IDF examples. +The code example for using the SPI master full duplex mode to drive a SPI_LCD (e.g. ST7789V or ILI9341) can be found in the :example:`peripherals/spi_master/lcd` directory of ESP-IDF examples. API Reference - SPI Common -------------------------- diff --git a/docs/zh_CN/api-reference/peripherals/spi_master.rst b/docs/zh_CN/api-reference/peripherals/spi_master.rst index 641d48b892..7589032e36 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_master.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_master.rst @@ -8,7 +8,7 @@ SPI 主机驱动程序是一个软件程序,用于在 {IDF_TARGET_NAME} 的通 .. only:: esp32 .. note:: - + SPI1 不属于 GP-SPI。SPI 主机驱动程序也支持 SPI1。但在 SPI1 总线上使用 SPI 主机驱动程序存在诸多限制,请参阅 :ref:`spi_master_on_spi1_bus`。 有关 GP-SPI 硬件相关信息,请参考 **{IDF_TARGET_NAME} 技术参考手册** > **SPI 控制器** [`PDF <{IDF_TARGET_TRM_CN_URL}#spi>`__]。 @@ -182,28 +182,28 @@ SPI 总线传输事务由五个阶段构成,详见下表(任意阶段均可 - 1 - 1 - 2 - - {SPI_TRANS_MODE_DIO} - - {SPICOMMON_BUSFLAG_DUAL} + - SPI_TRANS_MODE_DIO + - SPICOMMON_BUSFLAG_DUAL * - 双线 I/O 模式 - 1 - 2 - 2 - - * {SPI_TRANS_MODE_DIO} - * {SPI_TRANS_MULTILINE_ADDR} - - + - SPI_TRANS_MODE_DIO + SPI_TRANS_MULTILINE_ADDR + - SPICOMMON_BUSFLAG_DUAL * - 四线输出模式 - 1 - 1 - 4 - - {SPI_TRANS_MODE_QIO} - - {SPICOMMON_BUSFLAG_QUAD} + - SPI_TRANS_MODE_QIO + - SPICOMMON_BUSFLAG_QUAD * - 四线 I/O 模式 - 1 - 4 - 4 - - * {SPI_TRANS_MODE_QIO} - * {SPI_TRANS_MULTILINE_ADDR} - - {SPICOMMON_BUSFLAG_QUAD} + - SPI_TRANS_MODE_QIO + SPI_TRANS_MULTILINE_ADDR + - SPICOMMON_BUSFLAG_QUAD .. only:: SOC_SPI_SUPPORT_OCT @@ -227,42 +227,42 @@ SPI 总线传输事务由五个阶段构成,详见下表(任意阶段均可 - 1 - 1 - 2 - - {SPI_TRANS_MODE_DIO} - - {SPICOMMON_BUSFLAG_DUAL} + - SPI_TRANS_MODE_DIO + - SPICOMMON_BUSFLAG_DUAL * - 双线 I/O 模式 - 1 - 2 - 2 - - * {SPI_TRANS_MODE_DIO} - * {SPI_TRANS_MULTILINE_ADDR} - - + - SPI_TRANS_MODE_DIO + SPI_TRANS_MULTILINE_ADDR + - SPICOMMON_BUSFLAG_DUAL * - 四线输出模式 - 1 - 1 - 4 - - {SPI_TRANS_MODE_QIO} - - {SPICOMMON_BUSFLAG_QUAD} + - SPI_TRANS_MODE_QIO + - SPICOMMON_BUSFLAG_QUAD * - 四线 I/O 模式 - 1 - 4 - 4 - - * {SPI_TRANS_MODE_QIO} - * {SPI_TRANS_MULTILINE_ADDR} - - {SPICOMMON_BUSFLAG_QUAD} + - SPI_TRANS_MODE_QIO + SPI_TRANS_MULTILINE_ADDR + - SPICOMMON_BUSFLAG_QUAD * - 八线输出模式 - 1 - 1 - 8 - - {SPI_TRANS_MODE_OCT} - - {SPICOMMON_BUSFLAG_OCTAL} + - SPI_TRANS_MODE_OCT + - SPICOMMON_BUSFLAG_OCTAL * - OPI 模式 - 8 - 8 - 8 - - * {SPI_TRANS_MODE_OCT} - * {SPI_TRANS_MULTILINE_ADDR} - * {SPI_TRANS_MULTILINE_CMD} - - {SPICOMMON_BUSFLAG_OCTAL} + - SPI_TRANS_MODE_OCT + SPI_TRANS_MULTILINE_ADDR + SPI_TRANS_MULTILINE_CMD + - SPICOMMON_BUSFLAG_OCTAL 命令阶段和地址阶段 ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -292,7 +292,7 @@ SPI 总线传输事务由五个阶段构成,详见下表(任意阶段均可 当启用 DMA 时,不支持同时具有读取阶段和写入阶段的半双工传输事务。有关细节和解决方法,请参阅 :ref:`spi_known_issues`。 -.. only:: esp32s3 or esp32c3 or esp32c2 or esp32c6 or esp32h2 +.. only:: not SOC_SPI_HD_BOTH_INOUT_SUPPORTED .. note:: @@ -364,7 +364,7 @@ SPI 主机逐字节地将数据读入和写入内存。默认情况下,数据 在某些情况下,要传输的数据大小与 ``uint8_t`` 数组不同,可使用以下宏将数据转换为可由 SPI 驱动直接发送的格式: - 需传输的数据,使用 :c:macro:`SPI_SWAP_DATA_TX` -- 接收到的数据,使用 :c:macro:`SPI_SWAP_DATA_RX` +- 接收到的数据,使用 :c:macro:`SPI_SWAP_DATA_RX` .. _mixed_transactions: @@ -393,7 +393,7 @@ ISR 会干扰飞行中的轮询传输事务,以适应中断传输事务。在 因具备 :ref:`spi_bus_lock` 特性,SPI 主机驱动程序可在 SPI1 总线上运行,但该过程十分棘手,且需要许多特殊处理。这是一个适合高级开发者的功能。 - 要在 SPI1 总线上运行 SPI 主机驱动程序,需注意以下两个问题: + 要在 SPI1 总线上运行 SPI 主机驱动程序,需注意以下两个问题: 1. 当驱动在 SPI1 上运行时,代码和数据应在内部存储器中。 @@ -455,7 +455,7 @@ GPIO 矩阵与 IO_MUX 管脚 * - CS0 [1]_ - 15 - 5 - * - SCLK + * - SCLK - 14 - 18 * - MISO @@ -469,16 +469,16 @@ GPIO 矩阵与 IO_MUX 管脚 - 22 * - QUADHD - 4 - - 21 + - 21 .. 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"} 芯片的大多数外围信号都与之专用的 IO_MUX 管脚连接,但这些信号也可以通过较不直接的 GPIO 矩阵路由到任何其他可用的管脚。只要有一个信号是通过 GPIO 矩阵路由的,那么所有的信号都将通过它路由。 @@ -639,7 +639,7 @@ GPSPI 外设的时钟源可以通过设置 :cpp:member:`spi_device_handle_t::cfg - 25 - 128 - 153 - - 836.6 + - 836.6 传输事务长度较短时将提高传输事务间隔成本,因此应尽可能将几个短传输事务压缩成一个传输事务,以提升传输速度。 @@ -721,7 +721,7 @@ GPSPI 外设的时钟源可以通过设置 :cpp:member:`spi_device_handle_t::cfg * - 使用 IO_MUX 的 ESP32 从机设备 - 50 * - 使用 GPIO_MATRIX 的 ESP32 从机设备 - - 75 + - 75 MISO 路径延迟(有效时间)由从机的 **输入延迟** 与主机的 **GPIO 矩阵延迟** 组成。该延迟决定了频率限制,超过这个频率的全双工传输将无法如半双工交易中使用的 Dummy 位一样工作。该频率限制的计算方法为: @@ -769,11 +769,9 @@ GPSPI 外设的时钟源可以通过设置 :cpp:member:`spi_device_handle_t::cfg - 11.43 * - 75 - 100 - - 8.89 + - 8.89 -.. only:: esp32 - .. _spi_known_issues: 已知问题 @@ -802,6 +800,7 @@ GPSPI 外设的时钟源可以通过设置 :cpp:member:`spi_device_handle_t::cfg 查看使用 SPI 主机驱动程序在半双工模式下读取/写入 AT93C46D EEPROM(8 位模式)的示例代码,请前往 ESP-IDF 示例的 :example:`peripherals/spi_master/hd_eeprom` 目录。 +查看使用 SPI 主机驱动程序在全双工模式下驱动 LCD 屏幕(如 ST7789V 或 ILI9341)的示例代码,请前往 ESP-IDF 示例的 :example:`peripherals/spi_master/lcd` 目录。 API 参考 - SPI Common -------------------------- diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index d5bc6686d6..d7b9dd681c 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -232,13 +232,12 @@ examples/peripherals/spi_master/lcd: disable: - if: SOC_GPSPI_SUPPORTED != 1 -examples/peripherals/spi_slave/receiver: - disable: - - if: SOC_GPSPI_SUPPORTED != 1 - -examples/peripherals/spi_slave/sender: +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: @@ -255,10 +254,16 @@ examples/peripherals/spi_slave_hd/append_mode/slave: 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 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 examples/peripherals/temperature_sensor/temp_sensor: disable: diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md b/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md index 97254f4f6d..00f001896c 100644 --- a/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md +++ b/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | -------- | # I2S TDM Example -- ES7210 4-Ch ADC Codec diff --git a/examples/peripherals/lcd/spi_lcd_touch/README.md b/examples/peripherals/lcd/spi_lcd_touch/README.md index fec1348be3..b62637843b 100644 --- a/examples/peripherals/lcd/spi_lcd_touch/README.md +++ b/examples/peripherals/lcd/spi_lcd_touch/README.md @@ -1,5 +1,5 @@ -| 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 LCD and Touch Panel Example diff --git a/examples/peripherals/lcd/tjpgd/README.md b/examples/peripherals/lcd/tjpgd/README.md index 4f21901f16..780b4347d8 100644 --- a/examples/peripherals/lcd/tjpgd/README.md +++ b/examples/peripherals/lcd/tjpgd/README.md @@ -1,5 +1,5 @@ -| 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 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | ## LCD tjpgd example diff --git a/examples/peripherals/spi_master/hd_eeprom/README.md b/examples/peripherals/spi_master/hd_eeprom/README.md index 3a741b363e..bd63f023e7 100644 --- a/examples/peripherals/spi_master/hd_eeprom/README.md +++ b/examples/peripherals/spi_master/hd_eeprom/README.md @@ -1,5 +1,5 @@ -| 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 master half duplex EEPROM example diff --git a/examples/peripherals/spi_master/hd_eeprom/main/spi_eeprom_main.c b/examples/peripherals/spi_master/hd_eeprom/main/spi_eeprom_main.c index e9cdb5cc9c..2c9eaa1252 100644 --- a/examples/peripherals/spi_master/hd_eeprom/main/spi_eeprom_main.c +++ b/examples/peripherals/spi_master/hd_eeprom/main/spi_eeprom_main.c @@ -22,51 +22,29 @@ This code demonstrates how to use the SPI master half duplex mode to read/write a AT932C46D EEPROM (8-bit mode). */ -#ifdef CONFIG_IDF_TARGET_ESP32 -# ifdef CONFIG_EXAMPLE_USE_SPI1_PINS -# define EEPROM_HOST SPI1_HOST +////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////// Please update the following configuration according to your HardWare spec ///////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////// +#if CONFIG_IDF_TARGET_ESP32 +# if CONFIG_EXAMPLE_USE_SPI1_PINS +# define EEPROM_HOST SPI1_HOST // Use default pins, same as the flash chip. -# define PIN_NUM_MISO 7 -# define PIN_NUM_MOSI 8 -# define PIN_NUM_CLK 6 +# define PIN_NUM_MISO 7 +# define PIN_NUM_MOSI 8 +# define PIN_NUM_CLK 6 # else -# define EEPROM_HOST HSPI_HOST -# define PIN_NUM_MISO 18 -# define PIN_NUM_MOSI 23 -# define PIN_NUM_CLK 19 +# define EEPROM_HOST HSPI_HOST +# define PIN_NUM_MISO 18 +# define PIN_NUM_MOSI 23 +# define PIN_NUM_CLK 19 # endif - -# define PIN_NUM_CS 13 -#elif defined CONFIG_IDF_TARGET_ESP32S2 -# define EEPROM_HOST SPI2_HOST - -# define PIN_NUM_MISO 37 -# define PIN_NUM_MOSI 35 -# define PIN_NUM_CLK 36 -# define PIN_NUM_CS 34 -#elif defined CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 -# define EEPROM_HOST SPI2_HOST - -# define PIN_NUM_MISO 2 -# define PIN_NUM_MOSI 7 -# define PIN_NUM_CLK 6 -# define PIN_NUM_CS 10 - -#elif CONFIG_IDF_TARGET_ESP32S3 -# define EEPROM_HOST SPI2_HOST - -# define PIN_NUM_MISO 13 -# define PIN_NUM_MOSI 11 -# define PIN_NUM_CLK 12 -# define PIN_NUM_CS 10 - -#elif CONFIG_IDF_TARGET_ESP32H2 -# define EEPROM_HOST SPI2_HOST - -# define PIN_NUM_MISO 0 -# define PIN_NUM_MOSI 5 -# define PIN_NUM_CLK 4 -# define PIN_NUM_CS 1 +# define PIN_NUM_CS 13 +#else +# define EEPROM_HOST SPI2_HOST +# define PIN_NUM_MISO 13 +# define PIN_NUM_MOSI 12 +# define PIN_NUM_CLK 11 +# define PIN_NUM_CS 10 #endif static const char TAG[] = "main"; @@ -124,11 +102,10 @@ void app_main(void) ESP_ERROR_CHECK(ret); } ESP_LOGI(TAG, "Read: %s", test_buf); - ESP_LOGI(TAG, "Example finished."); while (1) { // Add your main loop handling code here. - vTaskDelay(1); + vTaskDelay(100); } } diff --git a/examples/peripherals/spi_master/lcd/README.md b/examples/peripherals/spi_master/lcd/README.md index bb4e802033..65ed7a367f 100644 --- a/examples/peripherals/spi_master/lcd/README.md +++ b/examples/peripherals/spi_master/lcd/README.md @@ -1,5 +1,5 @@ -| 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 Host Driver Example @@ -15,9 +15,11 @@ If you are looking for code to drive LCDs in general, rather than code that uses * An ESP development board, with SPI LCD -Connection : +**Connection** : -Depends on boards. Refer to `spi_master_example_main.c` No wiring is required on ESP-WROVER-KIT +Depends on boards. The GPIO number used by this example can be changed in `spi_master_example_main.c` No wiring is required on ESP-WROVER-KIT + +Especially, please pay attention to the level used to turn on the LCD backlight, some LCD module needs a low level to turn it on, while others take a high level. You can change the backlight level macro LCD_BK_LIGHT_ON_LEVEL in `spi_master_example_main.c`. ### Build and Flash diff --git a/examples/peripherals/spi_master/lcd/main/spi_master_example_main.c b/examples/peripherals/spi_master/lcd/main/spi_master_example_main.c index e2dca7e089..c07e3913a5 100644 --- a/examples/peripherals/spi_master/lcd/main/spi_master_example_main.c +++ b/examples/peripherals/spi_master/lcd/main/spi_master_example_main.c @@ -29,8 +29,10 @@ before the transaction is sent, the callback will set this line to the correct state. */ -#ifdef CONFIG_IDF_TARGET_ESP32 -#define LCD_HOST HSPI_HOST +////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////// Please update the following configuration according to your HardWare spec ///////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define LCD_HOST SPI2_HOST #define PIN_NUM_MISO 25 #define PIN_NUM_MOSI 23 @@ -40,41 +42,8 @@ #define PIN_NUM_DC 21 #define PIN_NUM_RST 18 #define PIN_NUM_BCKL 5 -#elif defined CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 -#define LCD_HOST SPI2_HOST -#define PIN_NUM_MISO 37 -#define PIN_NUM_MOSI 35 -#define PIN_NUM_CLK 36 -#define PIN_NUM_CS 45 - -#define PIN_NUM_DC 4 -#define PIN_NUM_RST 5 -#define PIN_NUM_BCKL 6 -#elif defined CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 -#define LCD_HOST SPI2_HOST - -#define PIN_NUM_MISO 2 -#define PIN_NUM_MOSI 7 -#define PIN_NUM_CLK 6 -#define PIN_NUM_CS 10 - -#define PIN_NUM_DC 9 -#define PIN_NUM_RST 4 -#define PIN_NUM_BCKL 5 - -#elif defined CONFIG_IDF_TARGET_ESP32H2 -#define LCD_HOST SPI2_HOST - -#define PIN_NUM_MISO 0 -#define PIN_NUM_MOSI 5 -#define PIN_NUM_CLK 4 -#define PIN_NUM_CS 1 - -#define PIN_NUM_DC 10 -#define PIN_NUM_RST 11 -#define PIN_NUM_BCKL 12 -#endif +#define LCD_BK_LIGHT_ON_LEVEL 0 //To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use, //but less overhead for setting up / finishing transfers. Make sure 240 is dividable by this. @@ -328,7 +297,7 @@ void lcd_init(spi_device_handle_t spi) } ///Enable backlight - gpio_set_level(PIN_NUM_BCKL, 0); + gpio_set_level(PIN_NUM_BCKL, LCD_BK_LIGHT_ON_LEVEL); } /* To send a set of lines we have to send a command, 2 data bytes, another command, 2 more data bytes and another command diff --git a/examples/peripherals/spi_slave/sender/main/app_main.c b/examples/peripherals/spi_slave/sender/main/app_main.c index 80147fdefd..fc8421109d 100644 --- a/examples/peripherals/spi_slave/sender/main/app_main.c +++ b/examples/peripherals/spi_slave/sender/main/app_main.c @@ -31,52 +31,19 @@ ready to receive/send data. This code connects this line to a GPIO interrupt whi task waits for this semaphore to be given before queueing a transmission. */ -/* -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 ///////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define GPIO_HANDSHAKE 2 +#define GPIO_MOSI 12 +#define GPIO_MISO 13 +#define GPIO_SCLK 15 +#define GPIO_CS 14 #ifdef CONFIG_IDF_TARGET_ESP32 #define SENDER_HOST HSPI_HOST - #else #define SENDER_HOST SPI2_HOST - #endif //The semaphore indicating the slave is ready to receive stuff.