spi_master: add support for variable dummy length in a same device

Resolves https://github.com/espressif/esp-idf/issues/2741
This commit is contained in:
michael 2019-02-27 02:09:36 +08:00
parent 140b6e3893
commit b812520b19
3 changed files with 88 additions and 2 deletions

View file

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

View file

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

View file

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