diff --git a/components/driver/include/driver/spi_master.h b/components/driver/include/driver/spi_master.h index b2acee0d0e..143b4e1c06 100644 --- a/components/driver/include/driver/spi_master.h +++ b/components/driver/include/driver/spi_master.h @@ -109,6 +109,7 @@ typedef struct { #define SPI_TRANS_MODE_DIOQIO_ADDR (1<<4) ///< Also transmit address in mode selected by SPI_MODE_DIO/SPI_MODE_QIO #define SPI_TRANS_VARIABLE_CMD (1<<5) ///< Use the ``command_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``. #define SPI_TRANS_VARIABLE_ADDR (1<<6) ///< Use the ``address_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``. +#define SPI_TRANS_VARIABLE_DUMMY (1<<7) ///< Use the ``dummy_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``. /** * This structure describes one SPI transaction. The descriptor should not be modified until the transaction finishes. @@ -148,6 +149,7 @@ typedef struct { struct spi_transaction_t base; ///< Transaction data, so that pointer to spi_transaction_t can be converted into spi_transaction_ext_t uint8_t command_bits; ///< The command length in this transaction, in bits. uint8_t address_bits; ///< The address length in this transaction, in bits. + uint8_t dummy_bits; ///< The dummy length in this transaction, in bits. } spi_transaction_ext_t ; diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index 5976b008ff..872a22fb7a 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -871,8 +871,14 @@ static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_ //SPI iface needs to be configured for a delay in some cases. //configure dummy bits - host->hw->user.usr_dummy=(dev->cfg.dummy_bits+extra_dummy) ? 1 : 0; - host->hw->user1.usr_dummy_cyclelen=dev->cfg.dummy_bits+extra_dummy-1; + int base_dummy_bits; + if (trans->flags & SPI_TRANS_VARIABLE_DUMMY) { + base_dummy_bits = ((spi_transaction_ext_t *)trans)->dummy_bits; + } else { + base_dummy_bits = dev->cfg.dummy_bits; + } + host->hw->user.usr_dummy=(base_dummy_bits+extra_dummy) ? 1 : 0; + host->hw->user1.usr_dummy_cyclelen=base_dummy_bits+extra_dummy-1; int miso_long_delay = 0; if (dev->clk_cfg.miso_delay<0) { diff --git a/components/driver/test/test_spi_master.c b/components/driver/test/test_spi_master.c index 364dca75e0..4d7f8f50e4 100644 --- a/components/driver/test/test_spi_master.c +++ b/components/driver/test/test_spi_master.c @@ -855,6 +855,84 @@ TEST_CASE("SPI master variable cmd & addr test","[spi]") ESP_LOGI(MASTER_TAG, "test passed."); } +void test_dummy(spi_device_handle_t spi, int dummy_n, uint8_t* data_to_send, int len) +{ + ESP_LOGI(TAG, "testing dummy n=%d", dummy_n); + WORD_ALIGNED_ATTR uint8_t slave_buffer[len+(dummy_n+7)/8]; + spi_slave_transaction_t slave_t = { + .tx_buffer = slave_buffer, + .rx_buffer = slave_buffer, + .length = len*8+((dummy_n+7)&(~8))+32, //receive more bytes to avoid slave discarding data + }; + TEST_ESP_OK(spi_slave_queue_trans(TEST_SLAVE_HOST, &slave_t, portMAX_DELAY)); + + vTaskDelay(50); + + spi_transaction_ext_t t = { + .base = { + .tx_buffer = data_to_send, + .length = (len+1)*8, //send one more byte force slave receive all data + .flags = SPI_TRANS_VARIABLE_DUMMY, + }, + .dummy_bits = dummy_n, + }; + TEST_ESP_OK(spi_device_transmit(spi, (spi_transaction_t*)&t)); + + spi_slave_transaction_t *ret_slave; + TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &ret_slave, portMAX_DELAY)); + TEST_ASSERT(ret_slave == &slave_t); + + ESP_LOG_BUFFER_HEXDUMP("rcv", slave_buffer, len+4, ESP_LOG_INFO); + int skip_cnt = dummy_n/8; + int dummy_remain = dummy_n % 8; + uint8_t *slave_ptr = slave_buffer; + if (dummy_remain > 0) { + for (int i = 0; i < len; i++) { + slave_ptr[0] = (slave_ptr[skip_cnt] << dummy_remain) | (slave_ptr[skip_cnt+1] >> (8-dummy_remain)); + slave_ptr++; + } + } else { + for (int i = 0; i < len; i++) { + slave_ptr[0] = slave_ptr[skip_cnt]; + slave_ptr++; + } + } + TEST_ASSERT_EQUAL_HEX8_ARRAY(data_to_send, slave_buffer, len); +} + +TEST_CASE("SPI master variable dummy test", "[spi]") +{ + spi_device_handle_t spi; + spi_bus_config_t bus_cfg = SPI_BUS_TEST_DEFAULT_CONFIG(); + spi_device_interface_config_t dev_cfg = SPI_DEVICE_TEST_DEFAULT_CONFIG(); + dev_cfg.flags = SPI_DEVICE_HALFDUPLEX; + + TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &bus_cfg, 0)); + TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &dev_cfg, &spi)); + + spi_slave_interface_config_t slave_cfg =SPI_SLAVE_TEST_DEFAULT_CONFIG(); + TEST_ESP_OK(spi_slave_initialize(TEST_SLAVE_HOST, &bus_cfg, &slave_cfg, 0)); + + spitest_gpio_output_sel(bus_cfg.mosi_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_out); + spitest_gpio_output_sel(bus_cfg.miso_io_num, FUNC_GPIO, spi_periph_signal[TEST_SLAVE_HOST].spiq_out); + spitest_gpio_output_sel(dev_cfg.spics_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spics_out[0]); + spitest_gpio_output_sel(bus_cfg.sclk_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spiclk_out); + + uint8_t data_to_send[] = {0x12, 0x34, 0x56, 0x78}; + + test_dummy(spi, 0, data_to_send, sizeof(data_to_send)); + test_dummy(spi, 1, data_to_send, sizeof(data_to_send)); + test_dummy(spi, 2, data_to_send, sizeof(data_to_send)); + test_dummy(spi, 3, data_to_send, sizeof(data_to_send)); + test_dummy(spi, 4, data_to_send, sizeof(data_to_send)); + test_dummy(spi, 8, data_to_send, sizeof(data_to_send)); + test_dummy(spi, 12, data_to_send, sizeof(data_to_send)); + test_dummy(spi, 16, data_to_send, sizeof(data_to_send)); + + spi_slave_free(TEST_SLAVE_HOST); + master_free_device_bus(spi); +} + /******************************************************************************** * Test SPI transaction interval ********************************************************************************/