mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 11:03:11 +00:00
Merge branch 'fix/spi_master_bit_trans_add_check_v5.5' into 'release/v5.5'
fix(driver_spi): spi master bit length check, dma internal align check and set idle level for all data pin (v5.5) See merge request espressif/esp-idf!45134
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2010-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2010-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -9,17 +9,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <esp_intr_alloc.h>
|
||||
#include "esp_pm.h"
|
||||
#include "driver/spi_common.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "hal/spi_types.h"
|
||||
#include "hal/dma_types.h"
|
||||
#include "soc/ext_mem_defs.h" //for SOC_NON_CACHEABLE_OFFSET
|
||||
#include "esp_private/spi_dma.h"
|
||||
#include "esp_pm.h"
|
||||
#include "esp_private/spi_share_hw_ctrl.h"
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
#include "esp_private/gdma.h"
|
||||
#endif
|
||||
#include "esp_private/spi_share_hw_ctrl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -339,7 +339,7 @@ static esp_err_t spi_master_init_driver(spi_host_device_t host_id)
|
||||
spi_ll_enable_clock(host_id, true);
|
||||
}
|
||||
spi_hal_init(&host->hal, host_id);
|
||||
spi_hal_config_io_default_level(&host->hal, bus_attr->bus_cfg.data_io_default_level);
|
||||
spi_hal_set_data_pin_idle_level(&host->hal, bus_attr->bus_cfg.data_io_default_level);
|
||||
|
||||
if (host_id != SPI1_HOST) {
|
||||
//SPI1 attributes are already initialized at start up.
|
||||
@@ -1110,6 +1110,8 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl
|
||||
const spi_bus_attr_t* bus_attr = host->bus_attr;
|
||||
bool tx_enabled = (trans_desc->flags & SPI_TRANS_USE_TXDATA) || (trans_desc->tx_buffer);
|
||||
bool rx_enabled = (trans_desc->flags & SPI_TRANS_USE_RXDATA) || (trans_desc->rx_buffer);
|
||||
uint8_t txlen_extra = trans_desc->length % 8;
|
||||
uint8_t rxlen_extra = trans_desc->rxlength % 8;
|
||||
spi_transaction_ext_t *t_ext = (spi_transaction_ext_t *)trans_desc;
|
||||
bool dummy_enabled = (((trans_desc->flags & SPI_TRANS_VARIABLE_DUMMY) ? t_ext->dummy_bits : handle->cfg.dummy_bits) != 0);
|
||||
bool extra_dummy_enabled = handle->hal_dev.timing_conf.timing_dummy;
|
||||
@@ -1131,6 +1133,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl
|
||||
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO | SPI_TRANS_MODE_QIO)) && !is_half_duplex), "Incompatible when setting to both multi-line mode and half duplex mode", ESP_ERR_INVALID_ARG);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
SPI_CHECK(!is_half_duplex || !bus_attr->dma_enabled || !rx_enabled || !tx_enabled, "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(!bus_attr->dma_enabled || !rxlen_extra, "rx unaligned byte with DMA is not supported", ESP_ERR_NOT_SUPPORTED);
|
||||
#endif
|
||||
#if !SOC_SPI_HD_BOTH_INOUT_SUPPORTED
|
||||
//On these chips, HW doesn't support using both TX and RX phases when in halfduplex mode
|
||||
@@ -1150,6 +1153,8 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl
|
||||
//Dummy phase is not available when both data out and in are enabled, regardless of FD or HD mode.
|
||||
SPI_CHECK(!tx_enabled || !rx_enabled || !dummy_enabled || !extra_dummy_enabled, "Dummy phase is not available when both data out and in are enabled", ESP_ERR_INVALID_ARG);
|
||||
|
||||
SPI_CHECK(!txlen_extra || (txlen_extra >= SPI_LL_TX_MINI_EXTRA_BITS), "tx %d-bit is not supported on this(or this version) chip", ESP_ERR_NOT_SUPPORTED, trans_desc->length);
|
||||
SPI_CHECK(!rxlen_extra || (rxlen_extra >= SPI_LL_RX_MINI_EXTRA_BITS), "rx %d-bit is not supported on this chip", ESP_ERR_NOT_SUPPORTED, trans_desc->rxlength);
|
||||
if (bus_attr->dma_enabled) {
|
||||
SPI_CHECK(trans_desc->length <= SPI_LL_DMA_MAX_BIT_LEN, "txdata transfer > hardware max supported len", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(trans_desc->rxlength <= SPI_LL_DMA_MAX_BIT_LEN, "rxdata transfer > hardware max supported len", ESP_ERR_INVALID_ARG);
|
||||
@@ -1199,12 +1204,13 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_dma_priv_buffer(spi_host_t *host, uin
|
||||
alignment = MAX(host->dma_ctx->dma_align_rx_int, host->bus_attr->cache_align_int);
|
||||
}
|
||||
}
|
||||
need_malloc |= (((uint32_t)buffer | len) & (alignment - 1));
|
||||
// length also must be aligned if cache sync is required, otherwise don't need
|
||||
need_malloc |= (use_psram || host->bus_attr->cache_align_int > 1) ? (((uint32_t)buffer | len) & (alignment - 1)) : (((uint32_t)buffer) & (alignment - 1));
|
||||
ESP_EARLY_LOGV(SPI_TAG, "%s %p, len %d, is_ptr_ext %d, use_psram: %d, alignment: %d, need_malloc: %d from %s", is_tx ? "TX" : "RX", buffer, len, is_ptr_ext, use_psram, alignment, need_malloc, (mem_cap & MALLOC_CAP_SPIRAM) ? "psram" : "internal");
|
||||
uint32_t align_len = (len + alignment - 1) & (~(alignment - 1)); // up align alignment
|
||||
if (need_malloc) {
|
||||
ESP_RETURN_ON_FALSE_ISR(!(flags & SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL), ESP_ERR_INVALID_ARG, SPI_TAG, "Set flag SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL but %s addr&len not align to %d, or not dma_capable", is_tx ? "TX" : "RX", alignment);
|
||||
len = (len + alignment - 1) & (~(alignment - 1)); // up align alignment
|
||||
uint32_t *temp = heap_caps_aligned_alloc(alignment, len, mem_cap);
|
||||
uint32_t *temp = heap_caps_aligned_alloc(alignment, align_len, mem_cap);
|
||||
ESP_RETURN_ON_FALSE_ISR(temp != NULL, ESP_ERR_NO_MEM, SPI_TAG, "Failed to allocate priv %s buffer", is_tx ? "TX" : "RX");
|
||||
|
||||
if (is_tx) {
|
||||
@@ -1214,7 +1220,8 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_dma_priv_buffer(spi_host_t *host, uin
|
||||
}
|
||||
*ret_buffer = buffer;
|
||||
if (use_psram || (host->bus_attr->cache_align_int > 1)) {
|
||||
esp_err_t ret = esp_cache_msync((void *)buffer, len, is_tx ? (ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED) : ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
||||
uint32_t sync_flags = is_tx ? (ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED) : ESP_CACHE_MSYNC_FLAG_DIR_M2C;
|
||||
esp_err_t ret = esp_cache_msync((void *)buffer, need_malloc ? align_len : len, sync_flags);
|
||||
ESP_RETURN_ON_FALSE_ISR(ret == ESP_OK, ESP_ERR_INVALID_ARG, SPI_TAG, "sync failed for %s buffer", is_tx ? "TX" : "RX");
|
||||
}
|
||||
return ESP_OK;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -36,6 +36,19 @@ const static char TAG[] = "test_spi";
|
||||
// There is no input-only pin except on esp32 and esp32s2
|
||||
#define TEST_SOC_HAS_INPUT_ONLY_PINS (CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2)
|
||||
|
||||
static uint8_t bitswap(uint8_t in)
|
||||
{
|
||||
uint8_t out = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
out = out >> 1;
|
||||
if (in & 0x80) {
|
||||
out |= 0x80;
|
||||
}
|
||||
in = in << 1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static void check_spi_pre_n_for(int clk, int pre, int n)
|
||||
{
|
||||
spi_device_handle_t handle;
|
||||
@@ -124,7 +137,7 @@ TEST_CASE("SPI Master clockdiv calculation routines", "[spi]")
|
||||
|
||||
// Test All clock source
|
||||
#define TEST_CLK_BYTE_LEN 10000
|
||||
#define TEST_TRANS_TIME_BIAS_RATIO (float)8.0/100 // think 8% transfer time bias as acceptable
|
||||
#define TEST_TRANS_TIME_BIAS_RATIO (float)10.0/100 // think 8% transfer time bias as acceptable
|
||||
TEST_CASE("SPI Master clk_source and divider accuracy", "[spi]")
|
||||
{
|
||||
int64_t start = 0, end = 0;
|
||||
@@ -880,22 +893,40 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
|
||||
TEST_ASSERT(spi_bus_free(TEST_SPI_HOST) == ESP_OK);
|
||||
}
|
||||
|
||||
#if !SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE // targets who need cache sync don't support unaligned trans
|
||||
TEST_CASE("SPI Master DMA manually unaligned RX test", "[spi]")
|
||||
{
|
||||
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
|
||||
buscfg.miso_io_num = buscfg.mosi_io_num;
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
|
||||
spi_device_handle_t dev0;
|
||||
spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
|
||||
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &dev0));
|
||||
|
||||
WORD_ALIGNED_ATTR uint8_t tx_data[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||||
WORD_ALIGNED_ATTR uint8_t rx_data[8] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
||||
spi_transaction_t trans_cfg = {
|
||||
.tx_buffer = tx_data,
|
||||
.rx_buffer = rx_data,
|
||||
.length = 5 * 8,
|
||||
.flags = SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL,
|
||||
};
|
||||
printf("Sending %d bytes\n", trans_cfg.length / 8);
|
||||
TEST_ESP_OK(spi_device_transmit(dev0, &trans_cfg));
|
||||
ESP_LOG_BUFFER_HEX("rx", rx_data, 8);
|
||||
#if !CONFIG_IDF_TARGET_ESP32 // esp32 dma not work with unaligned RX
|
||||
TEST_ASSERT_EQUAL(rx_data[6], 0xAA);
|
||||
#endif
|
||||
|
||||
TEST_ESP_OK(spi_bus_remove_device(dev0));
|
||||
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (TEST_SPI_PERIPH_NUM >= 2)
|
||||
//These will only be enabled on chips with 2 or more SPI peripherals
|
||||
|
||||
static uint8_t bitswap(uint8_t in)
|
||||
{
|
||||
uint8_t out = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
out = out >> 1;
|
||||
if (in & 0x80) {
|
||||
out |= 0x80;
|
||||
}
|
||||
in = in << 1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void test_cmd_addr(spi_slave_task_context_t *slave_context, bool lsb_first)
|
||||
{
|
||||
spi_device_handle_t spi;
|
||||
@@ -1843,6 +1874,90 @@ TEST_CASE("test_bus_free_safty_to_remain_devices", "[spi]")
|
||||
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST));
|
||||
}
|
||||
|
||||
TEST_CASE("Test master 1-9 bits tx/rx", "[spi]")
|
||||
{
|
||||
spi_device_handle_t dev0;
|
||||
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
|
||||
spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
|
||||
buscfg.miso_io_num = buscfg.mosi_io_num;
|
||||
|
||||
spi_transaction_t trans_cfg = {
|
||||
.tx_data[0] = 0xc9,
|
||||
.tx_data[1] = 0xad,
|
||||
.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA,
|
||||
};
|
||||
uint8_t exp[2], reversed[2] = {bitswap(trans_cfg.tx_data[0]), bitswap(trans_cfg.tx_data[1])};
|
||||
|
||||
for (int dma = 0; dma < 2; dma++) {
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED));
|
||||
for (int cfg = 0; cfg < 2; cfg++) {
|
||||
printf("Test %s with DMA: %s\n", cfg ? "LSB" : "MSB", dma ? "AUTO" : "DISABLED");
|
||||
devcfg.flags = cfg ? SPI_DEVICE_RXBIT_LSBFIRST : 0;
|
||||
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &dev0));
|
||||
|
||||
for (int i = 1; i <= 9; i++) {
|
||||
trans_cfg.length = i;
|
||||
trans_cfg.rxlength = i;
|
||||
if (i <= 8) {
|
||||
exp[0] = devcfg.flags & SPI_DEVICE_RXBIT_LSBFIRST ? reversed[0] & (0xff >> (8 - i)) : trans_cfg.tx_data[0] & (0xff << (8 - i));
|
||||
}
|
||||
exp[1] = devcfg.flags & SPI_DEVICE_RXBIT_LSBFIRST ? reversed[1] & (0xff >> (16 - i)) : trans_cfg.tx_data[1] & (0xff << (16 - i));
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if ((i % 8) && dma) {
|
||||
#else
|
||||
if ((i % 8) && ((i % 8 < SPI_LL_TX_MINI_EXTRA_BITS) || (i % 8 < SPI_LL_RX_MINI_EXTRA_BITS))) {
|
||||
#endif
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, spi_device_transmit(dev0, &trans_cfg));
|
||||
continue;
|
||||
}
|
||||
TEST_ESP_OK(spi_device_transmit(dev0, &trans_cfg));
|
||||
printf("len %d bits tx %x %x reversed %x %x exp %2x %2x rx %2x %2x\n", i, trans_cfg.tx_data[0], trans_cfg.tx_data[1], reversed[0], reversed[1], exp[0], exp[1], trans_cfg.rx_data[0], trans_cfg.rx_data[1]);
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(exp, trans_cfg.rx_data, 2);
|
||||
memset(trans_cfg.rx_data, 0, sizeof(trans_cfg.rx_data));
|
||||
}
|
||||
TEST_ESP_OK(spi_bus_remove_device(dev0));
|
||||
printf("--------------------------------\n");
|
||||
}
|
||||
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test master 1-9 bits rx only", "[spi]")
|
||||
{
|
||||
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
|
||||
buscfg.flags |= SPICOMMON_BUSFLAG_GPIO_PINS;
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_DISABLED));
|
||||
|
||||
spi_device_handle_t dev0;
|
||||
spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
|
||||
devcfg.flags |= SPI_DEVICE_HALFDUPLEX;
|
||||
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &dev0));
|
||||
|
||||
spi_transaction_t trans_cfg = {
|
||||
.flags = SPI_TRANS_USE_RXDATA,
|
||||
};
|
||||
|
||||
gpio_set_level(buscfg.miso_io_num, 1);
|
||||
spitest_gpio_output_sel(buscfg.miso_io_num, FUNC_GPIO, SIG_GPIO_OUT_IDX);
|
||||
for (int i = 1; i <= 9; i++) {
|
||||
trans_cfg.rxlength = i;
|
||||
if ((i % 8) && (i % 8 < SPI_LL_RX_MINI_EXTRA_BITS)) {
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, spi_device_transmit(dev0, &trans_cfg));
|
||||
continue;
|
||||
}
|
||||
TEST_ESP_OK(spi_device_transmit(dev0, &trans_cfg));
|
||||
printf("len %d bits rx %2x %2x\n", i, trans_cfg.rx_data[0], trans_cfg.rx_data[1]);
|
||||
if (i <= 8) {
|
||||
TEST_ASSERT_EQUAL_HEX8((0xff << (8 - i)), trans_cfg.rx_data[0]);
|
||||
}
|
||||
TEST_ASSERT_EQUAL_HEX8((0xff << (16 - i)), trans_cfg.rx_data[1]);
|
||||
memset(trans_cfg.rx_data, 0, sizeof(trans_cfg.rx_data));
|
||||
}
|
||||
|
||||
TEST_ESP_OK(spi_bus_remove_device(dev0));
|
||||
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST));
|
||||
}
|
||||
|
||||
#if SOC_LIGHT_SLEEP_SUPPORTED
|
||||
TEST_CASE("test_spi_master_sleep_retention", "[spi]")
|
||||
{
|
||||
|
||||
@@ -42,6 +42,8 @@ extern "C" {
|
||||
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 24) //reg len: 24 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 0 //Default level after bus initialized
|
||||
|
||||
// CS_WORKAROUND: SPI slave with using DMA, the rx dma suffers from unexpected transactions
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -41,6 +41,8 @@ extern "C" {
|
||||
|
||||
#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
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 2 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
|
||||
/**
|
||||
@@ -245,13 +247,16 @@ static inline void spi_ll_slave_hd_init(spi_dev_t *hw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and unify the default level of mosi line when bus free
|
||||
* Determine and unify the default level of data line when bus idle
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_set_mosi_free_level(spi_dev_t *hw, bool level)
|
||||
static inline void spi_ll_set_data_pin_idle_level(spi_dev_t *hw, bool level)
|
||||
{
|
||||
hw->ctrl.d_pol = level; //set default level for MOSI only on IDLE state
|
||||
hw->ctrl.d_pol = level;
|
||||
hw->ctrl.q_pol = level;
|
||||
hw->ctrl.wp_pol = level;
|
||||
hw->ctrl.hold_pol = level;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -41,6 +41,8 @@ extern "C" {
|
||||
|
||||
#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
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 2 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
|
||||
/**
|
||||
@@ -247,13 +249,16 @@ static inline void spi_ll_slave_hd_init(spi_dev_t *hw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and unify the default level of mosi line when bus free
|
||||
* Determine and unify the default level of data line when bus idle
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_set_mosi_free_level(spi_dev_t *hw, bool level)
|
||||
static inline void spi_ll_set_data_pin_idle_level(spi_dev_t *hw, bool level)
|
||||
{
|
||||
hw->ctrl.d_pol = level; //set default level for MOSI only on IDLE state
|
||||
hw->ctrl.d_pol = level;
|
||||
hw->ctrl.q_pol = level;
|
||||
hw->ctrl.wp_pol = level;
|
||||
hw->ctrl.hold_pol = level;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -798,6 +798,19 @@ static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en)
|
||||
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pcm2pdm_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S RX PDM mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param pdm2pcm_en Set true to enable RX PDM to PCM filter
|
||||
*/
|
||||
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm_en)
|
||||
{
|
||||
(void)pdm2pcm_en;
|
||||
hw->rx_conf.rx_pdm_en = true;
|
||||
hw->rx_conf.rx_tdm_en = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S TX PDM prescale
|
||||
*
|
||||
@@ -957,19 +970,6 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw)
|
||||
return hw->tx_pcm2pdm_conf1.tx_pdm_fs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable RX PDM mode.
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param pdm_enable Set true to RX enable PDM mode (ignored)
|
||||
*/
|
||||
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable)
|
||||
{
|
||||
(void)pdm_enable;
|
||||
hw->rx_conf.rx_pdm_en = 0;
|
||||
hw->rx_conf.rx_tdm_en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configura TX a/u-law decompress or compress
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -39,6 +39,8 @@ extern "C" {
|
||||
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN SPI_MS_DATA_BITLEN
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_SUPPORT_CLK_SRC_PRE_DIV 1 //clock source have divider before peripheral
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
@@ -898,13 +900,16 @@ static inline void spi_ll_master_set_cs_setup(spi_dev_t *hw, uint8_t setup)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and unify the default level of mosi line when bus free
|
||||
* Determine and unify the default level of data line when bus idle
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_set_mosi_free_level(spi_dev_t *hw, bool level)
|
||||
static inline void spi_ll_set_data_pin_idle_level(spi_dev_t *hw, bool level)
|
||||
{
|
||||
hw->ctrl.d_pol = level; //set default level for MOSI only on IDLE state
|
||||
hw->ctrl.d_pol = level;
|
||||
hw->ctrl.q_pol = level;
|
||||
hw->ctrl.wp_pol = level;
|
||||
hw->ctrl.hold_pol = level;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -41,6 +41,8 @@ extern "C" {
|
||||
|
||||
#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
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 2 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
|
||||
/**
|
||||
@@ -238,13 +240,16 @@ static inline void spi_ll_slave_hd_init(spi_dev_t *hw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and unify the default level of mosi line when bus free
|
||||
* Determine and unify the default level of data line when bus idle
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_set_mosi_free_level(spi_dev_t *hw, bool level)
|
||||
static inline void spi_ll_set_data_pin_idle_level(spi_dev_t *hw, bool level)
|
||||
{
|
||||
hw->ctrl.d_pol = level; //set default level for MOSI only on IDLE state
|
||||
hw->ctrl.d_pol = level;
|
||||
hw->ctrl.q_pol = level;
|
||||
hw->ctrl.wp_pol = level;
|
||||
hw->ctrl.hold_pol = level;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -798,6 +798,19 @@ static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en)
|
||||
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pcm2pdm_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S RX PDM mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param pdm2pcm_en Set true to enable RX PDM to PCM filter
|
||||
*/
|
||||
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm_en)
|
||||
{
|
||||
(void)pdm2pcm_en;
|
||||
hw->rx_conf.rx_pdm_en = true;
|
||||
hw->rx_conf.rx_tdm_en = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S TX PDM prescale
|
||||
*
|
||||
@@ -957,19 +970,6 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw)
|
||||
return hw->tx_pcm2pdm_conf1.tx_pdm_fs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable RX PDM mode.
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param pdm2pcm Set true to RX enable PDM mode (ignored)
|
||||
*/
|
||||
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm)
|
||||
{
|
||||
(void)pdm2pcm;
|
||||
hw->rx_conf.rx_pdm_en = 0;
|
||||
hw->rx_conf.rx_tdm_en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configura TX a/u-law decompress or compress
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -39,6 +39,8 @@ extern "C" {
|
||||
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN SPI_MS_DATA_BITLEN
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_SUPPORT_CLK_SRC_PRE_DIV 1 //clock source have divider before peripheral
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
@@ -262,13 +264,16 @@ static inline void spi_ll_slave_hd_init(spi_dev_t *hw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and unify the default level of mosi line when bus free
|
||||
* Determine and unify the default level of data line when bus idle
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_set_mosi_free_level(spi_dev_t *hw, bool level)
|
||||
static inline void spi_ll_set_data_pin_idle_level(spi_dev_t *hw, bool level)
|
||||
{
|
||||
hw->ctrl.d_pol = level; //set default level for MOSI only on IDLE state
|
||||
hw->ctrl.d_pol = level;
|
||||
hw->ctrl.q_pol = level;
|
||||
hw->ctrl.wp_pol = level;
|
||||
hw->ctrl.hold_pol = level;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -43,6 +43,8 @@ extern "C" {
|
||||
|
||||
#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
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 102) ? 1 : 2) //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
|
||||
/**
|
||||
@@ -239,13 +241,16 @@ static inline void spi_ll_slave_hd_init(spi_dev_t *hw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and unify the default level of mosi line when bus free
|
||||
* Determine and unify the default level of data line when bus idle
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_set_mosi_free_level(spi_dev_t *hw, bool level)
|
||||
static inline void spi_ll_set_data_pin_idle_level(spi_dev_t *hw, bool level)
|
||||
{
|
||||
hw->ctrl.d_pol = level; //set default level for MOSI only on IDLE state
|
||||
hw->ctrl.d_pol = level;
|
||||
hw->ctrl.q_pol = level;
|
||||
hw->ctrl.wp_pol = level;
|
||||
hw->ctrl.hold_pol = level;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -40,8 +40,9 @@ extern "C" {
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
#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
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
* calculation needs long time, it should be calculated during initialization and
|
||||
@@ -225,13 +226,16 @@ static inline void spi_ll_slave_hd_init(spi_dev_t *hw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and unify the default level of mosi line when bus free
|
||||
* Determine and unify the default level of data line when bus idle
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_set_mosi_free_level(spi_dev_t *hw, bool level)
|
||||
static inline void spi_ll_set_data_pin_idle_level(spi_dev_t *hw, bool level)
|
||||
{
|
||||
hw->ctrl.d_pol = level; //set default level for MOSI only on IDLE state
|
||||
hw->ctrl.d_pol = level;
|
||||
hw->ctrl.q_pol = level;
|
||||
hw->ctrl.wp_pol = level;
|
||||
hw->ctrl.hold_pol = level;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -41,6 +41,8 @@ extern "C" {
|
||||
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN SPI_MS_DATA_BITLEN
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_SUPPORT_CLK_SRC_PRE_DIV 1 //clock source have divider before peripheral
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
@@ -916,13 +918,16 @@ static inline void spi_ll_set_mosi_delay(spi_dev_t *hw, int delay_mode, int dela
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and unify the default level of mosi line when bus free
|
||||
* Determine and unify the default level of data line when bus idle
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_set_mosi_free_level(spi_dev_t *hw, bool level)
|
||||
static inline void spi_ll_set_data_pin_idle_level(spi_dev_t *hw, bool level)
|
||||
{
|
||||
hw->ctrl.d_pol = level; //set default level for MOSI only on IDLE state
|
||||
hw->ctrl.d_pol = level;
|
||||
hw->ctrl.q_pol = level;
|
||||
hw->ctrl.wp_pol = level;
|
||||
hw->ctrl.hold_pol = level;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -48,6 +48,8 @@ extern "C" {
|
||||
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 23) //reg len: 23 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (18 * 32) //Fifo len: 18 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 8 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_DMA_SHARED 1 //spi_dma shared with adc and dac on S2
|
||||
|
||||
@@ -263,13 +265,14 @@ static inline void spi_ll_slave_hd_init(spi_dev_t *hw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and unify the default level of mosi line when bus free
|
||||
* Determine and unify the default level of data line when bus idle
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_set_mosi_free_level(spi_dev_t *hw, bool level)
|
||||
static inline void spi_ll_set_data_pin_idle_level(spi_dev_t *hw, bool level)
|
||||
{
|
||||
hw->ctrl.d_pol = level; //set default level for MOSI only on IDLE state
|
||||
hw->ctrl.d_pol = level;
|
||||
hw->ctrl.q_pol = level;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -43,6 +43,8 @@ extern "C" {
|
||||
|
||||
#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
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 2 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
|
||||
/**
|
||||
@@ -256,13 +258,16 @@ static inline void spi_ll_slave_hd_init(spi_dev_t *hw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and unify the default level of mosi line when bus free
|
||||
* Determine and unify the default level of data line when bus idle
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_set_mosi_free_level(spi_dev_t *hw, bool level)
|
||||
static inline void spi_ll_set_data_pin_idle_level(spi_dev_t *hw, bool level)
|
||||
{
|
||||
hw->ctrl.d_pol = level; //set default level for MOSI only on IDLE state
|
||||
hw->ctrl.d_pol = level;
|
||||
hw->ctrl.q_pol = level;
|
||||
hw->ctrl.wp_pol = level;
|
||||
hw->ctrl.hold_pol = level;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -172,12 +172,12 @@ typedef struct {
|
||||
void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id);
|
||||
|
||||
/**
|
||||
* Config default output IO level when don't have transaction
|
||||
* Config default output data IO level when bus idle
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param level IO level to config
|
||||
*/
|
||||
void spi_hal_config_io_default_level(spi_hal_context_t *hal, bool level);
|
||||
void spi_hal_set_data_pin_idle_level(spi_hal_context_t *hal, bool level);
|
||||
|
||||
/**
|
||||
* Deinit the peripheral (and the context if needed).
|
||||
|
||||
@@ -27,11 +27,11 @@ void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id)
|
||||
spi_ll_apply_config(hw);
|
||||
}
|
||||
|
||||
void spi_hal_config_io_default_level(spi_hal_context_t *hal, bool level)
|
||||
void spi_hal_set_data_pin_idle_level(spi_hal_context_t *hal, bool level)
|
||||
{
|
||||
#if SPI_LL_MOSI_FREE_LEVEL
|
||||
// Config default output data line level when don't have transaction
|
||||
spi_ll_set_mosi_free_level(hal->hw, level);
|
||||
spi_ll_set_data_pin_idle_level(hal->hw, level);
|
||||
spi_ll_apply_config(hal->hw);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -375,6 +375,25 @@ An SPI Host reads and writes data into memory byte by byte. By default, data is
|
||||
|
||||
For example, if ``0b00010`` needs to be sent, it should be written into a ``uint8_t`` variable, and the length for reading should be set to 5 bits. The Device will still receive 8 bits with 3 additional "random" bits, so the reading must be performed correctly.
|
||||
|
||||
Not all chips support data transmission with any bit lengths. Sending or receiving unsupported bit lengths will return :c:macro:`ESP_ERR_NOT_SUPPORTED` error. The supported lengths are shown in the table below (**YES** means support any bits length, **NO** means bytes (8 bits) only):
|
||||
|
||||
+------+--------+-------+----------+--------------------+---------------------+
|
||||
| | ESP32 | ESP32-S2 | ESP32-S3/C2/C3/C6 | ESP32-H2/P4/C5/C61 |
|
||||
+======+========+=======+==========+====================+=====================+
|
||||
| TX | DMA | YES | YES | (bit_len % 8) != 1 | YES |
|
||||
+ +--------+-------+----------+--------------------+---------------------+
|
||||
| | NO DMA | YES | YES | (bit_len % 8) != 1 | YES |
|
||||
+------+--------+-------+----------+--------------------+---------------------+
|
||||
| RX | DMA | NO | NO | YES | YES |
|
||||
+ +--------+-------+----------+--------------------+---------------------+
|
||||
| | NO DMA | YES | NO | YES | YES |
|
||||
+------+--------+-------+----------+--------------------+---------------------+
|
||||
|
||||
If you still need to use unsupported bit lengths, you can use the following alternatives:
|
||||
|
||||
1. Use :cpp:member:`spi_transaction_t::cmd` and :cpp:member:`spi_transaction_t::addr` and data phase combination. The drawback is that the command and address phases do not receive data from the slave device.
|
||||
2. Use two supported length transmissions combination, like ``2+7`` to implement ``9 bit`` transmission, while keeping the CS line valid. The drawback is that there is a minimum time interval between two transmissions (see :ref:`transaction_time_cost`), and the overall transfer rate is lower.
|
||||
|
||||
On top of that, {IDF_TARGET_NAME} is a little-endian chip, which means that the least significant byte of ``uint16_t`` and ``uint32_t`` variables is stored at the smallest address. Hence, if ``uint16_t`` is stored in memory, bits [7:0] are sent first, followed by bits [15:8].
|
||||
|
||||
For cases when the data to be transmitted has a size differing from ``uint8_t`` arrays, the following macros can be used to transform data to the format that can be sent by the SPI driver directly:
|
||||
@@ -536,6 +555,7 @@ There are three factors limiting the transfer speed:
|
||||
|
||||
The main parameter that determines the transfer speed for large transactions is clock frequency. For multiple small transactions, the transfer speed is mostly determined by the length of transaction intervals.
|
||||
|
||||
.. _transaction_time_cost:
|
||||
|
||||
Transaction Duration
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -832,6 +852,10 @@ Please note that the ISR is disabled during flash operation by default. To keep
|
||||
|
||||
4. ``cs_ena_pretrans`` is not compatible with the Command and Address phases of full-duplex transactions.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
5. If DMA is enabled, the RX buffer should be word-aligned (starting from a 32-bit boundary and having a length of multiples of 4 bytes). Otherwise, DMA may overwrite the data in the unaligned part.
|
||||
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
@@ -375,6 +375,25 @@ SPI 主机逐字节地将数据读入和写入内存。默认情况下,数据
|
||||
|
||||
例如,如果需要发送 ``0b00010``,则应将其写成 ``uint8_t`` 变量,读取长度设置为 5 位。此时,设备仍然会收到 8 位数据,并另有 3 个“随机”位,所以读取过程必须准确。
|
||||
|
||||
不是所有芯片都支持任意位长度的数据传输,发送或接收不支持的位长度时会返回 :c:macro:`ESP_ERR_NOT_SUPPORTED` 错误。支持的长度如下表所示(**YES** 表示支持任意长度,**NO** 表示只支持整字节 8 bits 长度):
|
||||
|
||||
+------+--------+-------+----------+--------------------+---------------------+
|
||||
| | ESP32 | ESP32-S2 | ESP32-S3/C2/C3/C6 | ESP32-H2/P4/C5/C61 |
|
||||
+======+========+=======+==========+====================+=====================+
|
||||
| TX | DMA | YES | YES | (bit_len % 8) != 1 | YES |
|
||||
+ +--------+-------+----------+--------------------+---------------------+
|
||||
| | NO DMA | YES | YES | (bit_len % 8) != 1 | YES |
|
||||
+------+--------+-------+----------+--------------------+---------------------+
|
||||
| RX | DMA | NO | NO | YES | YES |
|
||||
+ +--------+-------+----------+--------------------+---------------------+
|
||||
| | NO DMA | YES | NO | YES | YES |
|
||||
+------+--------+-------+----------+--------------------+---------------------+
|
||||
|
||||
如仍需使用不支持的长度传输,根据表格可以有以下替代方法:
|
||||
|
||||
1. 使用 :cpp:member:`spi_transaction_t::cmd` 和 :cpp:member:`spi_transaction_t::addr` 和数据阶段组合。缺点:命令和地址阶段不接收从机数据。
|
||||
2. 使用两次支持长度的传输组合,比如 ``2+7`` 实现 ``9 bit`` 传输,期间保持 CS 线有效。缺点:两次传输之间有最小时间间隔(见 :ref:`transaction_time_cost`),整体速率较低。
|
||||
|
||||
此外,{IDF_TARGET_NAME} 属于小端芯片,即 ``uint16_t`` 和 ``uint32_t`` 变量的最低有效位存储在最小的地址。因此,如果 ``uint16_t`` 存储在内存中,则首先发送位 [7:0],其次是位 [15:8]。
|
||||
|
||||
在某些情况下,要传输的数据大小与 ``uint8_t`` 数组不同,可使用以下宏将数据转换为可由 SPI 驱动直接发送的格式:
|
||||
@@ -536,6 +555,7 @@ GPIO 矩阵与 IO_MUX 管脚
|
||||
|
||||
影响大传输事务传输速度的主要参数是时钟频率。而多个小传输事务的传输速度主要由传输事务间隔时长决定。
|
||||
|
||||
.. _transaction_time_cost:
|
||||
|
||||
传输事务持续时间
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -832,6 +852,10 @@ GPSPI 外设的时钟源可以通过设置 :cpp:member:`spi_device_interface_con
|
||||
|
||||
4. 全双工传输事务模式中,命令阶段和地址阶段与 ``cs_ena_pretrans`` 不兼容。
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
5. 若启用了 DMA,则 RX 缓冲区应该以字对齐(从 32 位边界开始,字节长度为 4 的倍数)。否则 DMA 可能覆盖未对齐部分的数据。
|
||||
|
||||
|
||||
应用示例
|
||||
-------------------
|
||||
|
||||
Reference in New Issue
Block a user