First SPI read successful, then fails after first SPI write - Logic Analyzer says both reads identical
Posted: Fri May 15, 2020 9:13 pm
I am interfacing via SPI to a graphics chip. Reading the chip ID succeeds, but after the first SPI write, the exact same read as before now fails. I see the identical slave response on the logic analyzer, though.
Completely removing the device from the bus (spi_bus_remove_device() ) AND re-initializing the SPI bus (spi_bus_free() then spi_bus_initialize() ) results in successful reads again. In other words, it is not that the SPI write resulted in a lock up of the slave.
I am using IDF, and the SPI bus uses DMA and a 24bit address field. I have demonstrated that the SPI transactions from above succeed if I don't use 24bit address fields and no DMA. So again, it doesn't point to a lock up in the slave. But no DMA is not really an option in my case.
Could you review this code ?
Thanks for your help!
Completely removing the device from the bus (spi_bus_remove_device() ) AND re-initializing the SPI bus (spi_bus_free() then spi_bus_initialize() ) results in successful reads again. In other words, it is not that the SPI write resulted in a lock up of the slave.
I am using IDF, and the SPI bus uses DMA and a 24bit address field. I have demonstrated that the SPI transactions from above succeed if I don't use 24bit address fields and no DMA. So again, it doesn't point to a lock up in the slave. But no DMA is not really an option in my case.
Could you review this code ?
Code: Select all
spi_bus_config_t buscfg={
.mosi_io_num=PIN_NUM_MOSI,
.miso_io_num=PIN_NUM_MISO,
.sclk_io_num=PIN_NUM_CLK,
.quadwp_io_num=-1,
.quadhd_io_num=-1,
.max_transfer_sz= 2048,
.flags=SPICOMMON_BUSFLAG_MASTER,
.intr_flags=0
};
ret=spi_bus_initialize(VSPI_HOST, &buscfg, /* using DMA channel */ 1);
ESP_ERROR_CHECK(ret);
spi_device_interface_config_t devcfg={
.command_bits=0,
.address_bits=24,
.dummy_bits=0,
.mode=0,
.duty_cycle_pos=0, // defaults to 50%
.cs_ena_pretrans=0,
.cs_ena_posttrans=0,
.clock_speed_hz=2*1000000,
.input_delay_ns=0,
.spics_io_num=PIN_NUM_CS,
.flags=SPI_DEVICE_HALFDUPLEX,
.queue_size=1,
.pre_cb=NULL,
.post_cb=NULL, // no pre/post callbacks
};
ret=spi_bus_add_device(VSPI_HOST, &devcfg, &myDisplay);
ESP_ERROR_CHECK(ret);
spi_transaction_t t;
// transaction 1 of 3: read chip ID
memset(&t, 0, sizeof(t));
t.addr = 0xc0000UL;
t.length=0; // bits
t.rxlength=24; // bits
t.flags = SPI_TRANS_USE_RXDATA;
assert( spi_device_transmit(myDisplay, &t)==ESP_OK );
printf( "chip ID %X\n", t.rx_data[2] );
// ^^^ this will be correct and as expected
// host commands don't use an address but happened to be three
// bytes long also. place command into the address field, with no tx length.
memset(&t, 0, sizeof(t));
t.addr = 0; // it so happens that 0 is a command to this slave
t.length=0; // bits
assert( spi_device_transmit(myDisplay, &t)==ESP_OK );
// ( i tried using spi_transaction_ext_t to avoid tx length of zero
// and instead disable address bits for this transaction, but no difference)
// same transaction as the first one
memset(&t, 0, sizeof(t));
t.addr = 0xc0000UL;
t.length=0; // bits
t.rxlength=24; // bits
t.flags = SPI_TRANS_USE_RXDATA;
assert( spi_device_transmit(myDisplay, &t)==ESP_OK );
printf( "chip ID %X\n", t.rx_data[2] );
// ^^^ this will be WRONG even though a logic analyzer shows same data
// * removing device from bus and re-adding does NOT result in successful read
// * re-initialising the entire SPI bs WILL result in successful read