diff --git a/components/esp_driver_spi/src/gpspi/spi_master.c b/components/esp_driver_spi/src/gpspi/spi_master.c index b9e655ff29..e6e096152e 100644 --- a/components/esp_driver_spi/src/gpspi/spi_master.c +++ b/components/esp_driver_spi/src/gpspi/spi_master.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 */ @@ -1103,6 +1103,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; @@ -1124,6 +1126,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 @@ -1143,6 +1146,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); diff --git a/components/esp_driver_spi/test_apps/master/main/test_spi_master.c b/components/esp_driver_spi/test_apps/master/main/test_spi_master.c index 0caa001d7a..401b9bec69 100644 --- a/components/esp_driver_spi/test_apps/master/main/test_spi_master.c +++ b/components/esp_driver_spi/test_apps/master/main/test_spi_master.c @@ -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 */ @@ -35,6 +35,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; @@ -881,19 +894,6 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]") #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; @@ -1842,6 +1842,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]") { diff --git a/components/esp_hal_gpspi/esp32/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32/include/hal/spi_ll.h index 9f89c03d34..54fea8f0a1 100644 --- a/components/esp_hal_gpspi/esp32/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32/include/hal/spi_ll.h @@ -41,6 +41,8 @@ extern "C" { #define SPI_LL_DMA_CHANNEL_NUM (2) #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_MAX_PRE_DIV_NUM (8192) #define SPI_LL_SUPPORT_CLK_AS_CS 1 //Output clock on CS line if CS is active #define SPI_LL_MOSI_FREE_LEVEL 0 //Default level after bus initialized diff --git a/components/esp_hal_gpspi/esp32c2/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32c2/include/hal/spi_ll.h index 9304a96c42..6311945610 100644 --- a/components/esp_hal_gpspi/esp32c2/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32c2/include/hal/spi_ll.h @@ -38,6 +38,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 #define SPI_LL_MAX_PRE_DIV_NUM (16) #define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg diff --git a/components/esp_hal_gpspi/esp32c3/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32c3/include/hal/spi_ll.h index ff45716121..f6958ac183 100644 --- a/components/esp_hal_gpspi/esp32c3/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32c3/include/hal/spi_ll.h @@ -38,6 +38,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_MAX_PRE_DIV_NUM (16) #define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg #define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM diff --git a/components/esp_hal_gpspi/esp32c5/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32c5/include/hal/spi_ll.h index 51c43be5f4..617176baa2 100644 --- a/components/esp_hal_gpspi/esp32c5/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32c5/include/hal/spi_ll.h @@ -40,6 +40,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_MAX_PRE_DIV_NUM (16) +#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_SRC_PRE_DIV_MAX (PCR_SPI2_CLKM_DIV_NUM + 1) //source pre divider max diff --git a/components/esp_hal_gpspi/esp32c6/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32c6/include/hal/spi_ll.h index 9abd1590bc..0d0eeb3127 100644 --- a/components/esp_hal_gpspi/esp32c6/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32c6/include/hal/spi_ll.h @@ -38,6 +38,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_MAX_PRE_DIV_NUM (16) #define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg #define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM diff --git a/components/esp_hal_gpspi/esp32c61/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32c61/include/hal/spi_ll.h index dd857b183f..4cf7f99baf 100644 --- a/components/esp_hal_gpspi/esp32c61/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32c61/include/hal/spi_ll.h @@ -40,6 +40,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_MAX_PRE_DIV_NUM (16) +#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_SRC_PRE_DIV_MAX (PCR_SPI2_CLKM_DIV_NUM + 1) //source pre divider max diff --git a/components/esp_hal_gpspi/esp32h2/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32h2/include/hal/spi_ll.h index b2d4fb9f6b..7f59061638 100644 --- a/components/esp_hal_gpspi/esp32h2/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32h2/include/hal/spi_ll.h @@ -40,6 +40,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_MAX_PRE_DIV_NUM (16) #define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg #define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM diff --git a/components/esp_hal_gpspi/esp32h21/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32h21/include/hal/spi_ll.h index a850b44931..b5ce3b3388 100644 --- a/components/esp_hal_gpspi/esp32h21/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32h21/include/hal/spi_ll.h @@ -39,11 +39,12 @@ 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_MAX_PRE_DIV_NUM (16) #define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg #define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM #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 diff --git a/components/esp_hal_gpspi/esp32h4/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32h4/include/hal/spi_ll.h index a8477871a1..679417f841 100644 --- a/components/esp_hal_gpspi/esp32h4/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32h4/include/hal/spi_ll.h @@ -39,12 +39,13 @@ 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_MAX_PRE_DIV_NUM (16) #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_SRC_PRE_DIV_MAX (PCR_SPI2_CLKM_DIV_NUM + 1) //source pre divider max #define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider - /** * The data structure holding calculated clock configuration. Since the * calculation needs long time, it should be calculated during initialization and diff --git a/components/esp_hal_gpspi/esp32p4/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32p4/include/hal/spi_ll.h index a3b65fbb13..1f4984bc78 100644 --- a/components/esp_hal_gpspi/esp32p4/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32p4/include/hal/spi_ll.h @@ -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_MAX_PRE_DIV_NUM (16) #define SPI_LL_SUPPORT_CLK_SRC_PRE_DIV 1 //clock source have divider before peripheral #define SPI_LL_SRC_PRE_DIV_MAX (HP_SYS_CLKRST_REG_GPSPI2_MST_CLK_DIV_NUM + 1) //source pre divider max diff --git a/components/esp_hal_gpspi/esp32s2/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32s2/include/hal/spi_ll.h index 8159861503..88ad203d4b 100644 --- a/components/esp_hal_gpspi/esp32s2/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32s2/include/hal/spi_ll.h @@ -46,8 +46,10 @@ extern "C" { #define SPI_LL_DMA_CHANNEL_NUM (3) #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_MAX_PRE_DIV_NUM (8192) -#define SPI_LL_MAX_SCT_CONF_LEN 0x7FFFFD //23 bit wide reg +#define SPI_LL_MAX_SCT_CONF_LEN 0x7FFFFD //23 bit wide reg #define SPI_LL_SCT_CONF_BUF_NUM (1 + 27) //1-word-bitmap + 27-word-regs according to TRM #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 diff --git a/components/esp_hal_gpspi/esp32s3/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32s3/include/hal/spi_ll.h index b40a1e27c0..086626e713 100644 --- a/components/esp_hal_gpspi/esp32s3/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32s3/include/hal/spi_ll.h @@ -40,6 +40,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_MAX_PRE_DIV_NUM (16) #define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg #define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM diff --git a/docs/en/api-reference/peripherals/spi_master.rst b/docs/en/api-reference/peripherals/spi_master.rst index 37b45a9264..1b1d54dae0 100644 --- a/docs/en/api-reference/peripherals/spi_master.rst +++ b/docs/en/api-reference/peripherals/spi_master.rst @@ -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 ^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/zh_CN/api-reference/peripherals/spi_master.rst b/docs/zh_CN/api-reference/peripherals/spi_master.rst index 74c29fc196..8016d58ff7 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_master.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_master.rst @@ -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: 传输事务持续时间 ^^^^^^^^^^^^^^^^^^^^