Page 1 of 1

SPI Master, two busses, deadlock?

Posted: Thu Jan 25, 2018 10:07 pm
by vonnieda
Hi all,

I am experiencing a deadlock somewhere in the SPI Master code. I believe this is due to two transactions running at the same time, but on different busses.

I am using the SPI Master driver with both VSPI_HOST and HSPI_HOST. HSPI is running an LCD and VSPI is running a SPI flash. HSPI is not using DMA (0) and VSPI is using DMA channel 2.

My initialization code for the two busses looks like this:

LCD:

Code: Select all

	// Configure the SPI bus
	spi_bus_config_t bus_config = {
			.mosi_io_num = LCD_IO_MOSI,
			.miso_io_num = -1,
			.sclk_io_num = LCD_IO_SCK
	};
	err = spi_bus_initialize(HSPI_HOST, &bus_config, 0);
	if (err != ESP_OK) {
		FB_LOG_ERROR(err, "fb_hal_lcd_initialize spi_bus_initialize");
		return err;
	}

	// Configure the LCD SPI device
    spi_device_interface_config_t dev_config = {
        .clock_speed_hz = LCD_SPI_SPEED_HZ,
		.mode = 0,
        .spics_io_num = LCD_IO_CS,
        .queue_size = 7,
    };
	err = spi_bus_add_device(HSPI_HOST, &dev_config, &lcd_spi_device);
	if (err != ESP_OK) {
		FB_LOG_ERROR(err, "fb_hal_lcd_initialize spi_bus_add_device");
		return err;
	}
SPI Flash:

Code: Select all

	spi_bus_config_t bus_config = {
		.mosi_io_num = BULK_STORAGE_IO_SPI_MOSI,
		.miso_io_num = BULK_STORAGE_IO_SPI_MISO,
		.sclk_io_num = BULK_STORAGE_IO_SPI_SCLK,
		.quadwp_io_num = BULK_STORAGE_IO_SPI_QWP,
		.quadhd_io_num = BULK_STORAGE_IO_SPI_QHD,
		.max_transfer_sz = BULK_STORAGE_SPI_MAX_TRANSFER_BYTES,
	};

	esp_err_t err;

	err = spi_bus_initialize(VSPI_HOST, &bus_config, BULK_STORAGE_SPI_DMA_CHANNEL);
	if (err != ESP_OK) {
		FB_LOG_ERROR(err, "fb_hal_bulk_storage_initialize spi_bus_initialize");
		return err;
	}

	spi_device_interface_config_t dev_config = {
		.clock_speed_hz = BULK_STORAGE_SPI_SPEED_HZ,
		.mode = 0,
		.spics_io_num = BULK_STORAGE_IO_SPI_CS,
		.queue_size = 7,
	};

	err = spi_bus_add_device(VSPI_HOST, &dev_config, &bulk_storage_spi_device);
	if (err != ESP_OK) {
		FB_LOG_ERROR(err, "fb_hal_bulk_storage_initialize spi_bus_add_device");
		return err;
	}
The problems seems to occur when the LCD is running a transaction and I then start a transaction to the SPI flash. The LCD becomes blocked in spi_device_transmit() and never returns, while the SPI Flash transaction finished fine, and I send additional transactions on it just fine.

So, my question is: Are there any limitations I should be aware of using the SPI Master driver with two busses at the same time? From the docs it seems this should be completely fine. And if not, and my code up there looks fine, any ideas on what could be causing this?

Thanks,
Jason

Re: SPI Master, two busses, deadlock?

Posted: Thu Jan 25, 2018 10:16 pm
by vonnieda
Quick update to this: Problem still persists, but wrapping every call to spi_device_transmit (for both devices) with a mutex fixes it. This will get me by for now, but it's a bad solution as it limits me to using one bus at a time.

Re: SPI Master, two busses, deadlock?

Posted: Thu Jan 25, 2018 10:32 pm
by vonnieda
One more quick note. In the code for spi_device_transmit I found a TODO that worries me:

//ToDo: check if any spi transfers in flight

Code: Select all

//Porcelain to do one blocking transmission.
esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc)
{
    esp_err_t ret;
    spi_transaction_t *ret_trans;
    //ToDo: check if any spi transfers in flight
    ret=spi_device_queue_trans(handle, trans_desc, portMAX_DELAY);
    if (ret!=ESP_OK) return ret;
    ret=spi_device_get_trans_result(handle, &ret_trans, portMAX_DELAY);
    if (ret!=ESP_OK) return ret;
    assert(ret_trans==trans_desc);
    return ESP_OK;
}
Could this be related?

Thanks,
Jason

Re: SPI Master, two busses, deadlock?

Posted: Fri Jan 26, 2018 4:14 am
by ESP_Sprite
Fyi, that comment is mine. It relates to a situation where you already queued a transaction for a device using spi_device_queue_trans, then use spi_device_transmit to send something to the same device. In this case, spi_device_get_trans_result gets the result for that first transfer, not for the transfer sent with spi_device_transmit. This is more-or-less abuse of the API, and will trigger the assert underneath. The ToDo essentially is because I thought a check before sending might be more appropriate. All in all, it has nothing to do with the issue seen here.

Re: SPI Master, two busses, deadlock?

Posted: Fri Jan 26, 2018 2:32 pm
by vonnieda
ESP_Sprite wrote:Fyi, that comment is mine. It relates to a situation where you already queued a transaction for a device using spi_device_queue_trans, then use spi_device_transmit to send something to the same device. In this case, spi_device_get_trans_result gets the result for that first transfer, not for the transfer sent with spi_device_transmit. This is more-or-less abuse of the API, and will trigger the assert underneath. The ToDo essentially is because I thought a check before sending might be more appropriate. All in all, it has nothing to do with the issue seen here.
Thank you for your response ESP_Sprite. Glad to hear that's not related. Do you have any ideas as to what might be going on with this issue?

Thanks,
Jason