Page 1 of 1

First SPI read successful, then fails after first SPI write - Logic Analyzer says both reads identical

Posted: Fri May 15, 2020 9:13 pm
by JeffCa
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 ?

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
Thanks for your help!

Re: First SPI read successful, then fails after first SPI write - Logic Analyzer says both reads identical

Posted: Mon May 18, 2020 11:54 am
by JeffCa
Stumbled across this 2017 bug https://github.com/espressif/esp-idf/issues/598 . The issue was closed, even though the comment section indicates it wasn't entirely fixed. If I follow the comments correctly, the user circumvented the problem by avoiding combined write/reads. Maybe the bug should be reopened ?