I try to use the ESP32-WROVER-KIT as an SPI master and a STM32F746DISCO as an SPI slave and I am having some problems with the communication. I use the latest official release of the esp-idf, v3.0.
Below the ESP32 configuration and code snippets:
Code: Select all
#define SPI_CHANNEL HSPI_HOST
#define SPI_CLOCK 500000 // Default SPI clock 500KHz
/*
* SPI master modes for ESP32:
* - Mode 0: CPOL = 0, CPHA = 0
* - Mode 1: CPOL = 0, CPHA = 1
* - Mode 2: CPOL = 1, CPHA = 1
* - Mode 3: CPOL = 1, CPHA = 0
*/
#define SPI_MODE 2 // Default SPI mode 2
#define SPI_CLK_GPIO GPIO_NUM_14 // Shared with JTAG/MicroSD
#define SPI_CS_GPIO GPIO_NUM_15 // Shared with JTAG/MicroSD
#define SPI_MISO_GPIO GPIO_NUM_12 // Shared with JTAG/MicroSD
#define SPI_MOSI_GPIO GPIO_NUM_13 // Shared with JTAG/MicroSD
uint8_t myRxBuffer[SPI_MAX_DMA_LEN] = {};
uint8_t myTxBuffer[SPI_MAX_DMA_LEN] = {};
spi_device_handle_t spi_handle;
// Initialize the SPI2 device in master mode
void spi_master_config(void) {
// Configuration for the SPI bus
spi_bus_config_t buscfg = {
.mosi_io_num = SPI_MOSI_GPIO,
.miso_io_num = SPI_MISO_GPIO,
.sclk_io_num = SPI_CLK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = SPI_MAX_DMA_LEN,
};
// Configuration for the SPI master interface
spi_device_interface_config_t devcfg = {
.command_bits = 0,
.address_bits = 0,
.dummy_bits = 0,
.duty_cycle_pos = 128,
.cs_ena_pretrans = 0,
.cs_ena_posttrans = 3, // Keep the CS low 3 cycles after transaction, to stop the master from missing the last bit when CS has less propagation delay than CLK
.clock_speed_hz = SPI_CLOCK,
.mode = SPI_MODE,
.spics_io_num = SPI_CS_GPIO,
.queue_size = 1,
.flags = 0,
.pre_cb = NULL,
.post_cb = NULL,
};
// Initialize and enable SPI
spi_bus_initialize(SPI_CHANNEL, &buscfg, 1);
spi_bus_add_device(SPI_CHANNEL, &devcfg, &spi_handle);
}
// Full buffer DMA transfer
int32_t spi_dma_transfer_bytes(uint8_t *data, uint16_t size) {
esp_err_t trans_result = ESP_OK;
spi_transaction_t trans_t;
// Prepare transaction parameters
if (data == myRxBuffer) {
trans_t.rx_buffer = myRxBuffer;
trans_t.tx_buffer = NULL;
} else {
trans_t.rx_buffer = NULL;
trans_t.tx_buffer = myTxBuffer;
}
trans_t.rxlength = 0;
trans_t.length = 8 * size;
trans_t.flags = 0;
trans_t.cmd = 0;
trans_t.addr = 0;
trans_t.user = NULL;
// Perform transaction
trans_result = spi_device_transmit(spi_handle, &trans_t);
if (ESP_OK != trans_result) {
return SPI_TRANSFER_CANCELLED;
}
return size;
}
- On the slave side, SPI is initialized, then an echo loop is entered. The slave reads 1 byte then writes it back on the bus. Both reading and writing should be blocking, meaning the slave remains in the read/write code until it receives CS assertion + CLK.
- On the master side, SPI is initialized, then the master waits 5sec (to be sure the slave finished it's initialization), writes 0x55 on the bus, waits another 5sec (to be sure the slave is ready to send the return byte) and reads the byte back. All this inside a loop
Problems encountered and fixed (need confirmation from ESP32):
- The SPI modes on the esp-idf are not according to the standard, mode 2 and 3 are being swapped. Normally SPI mode 2 means CPOL = 1, CPHA = 0 but in esp-idf drivers I see mode 2 meaning CPOL = 1 and CPHA = 1 (same configuration set for the slave). So I use mode 2 for the master and mode 3 for the slave to be in sync
- The implementation of "miso_delay_mode" and "extra_dummy" are not correct in the spi driver code. Based on information found here http://esp-idf.readthedocs.io/en/latest ... aster.html, the configuration should be like this:
- if the GPIO matrix is not used, there should be no MISO delay introduced and also no extra dummy bit
- if the GPIO matrix is used, there should be a MISO delay introduced if the SPI clock is higher than 40MHz, and a extra dummy bit if the clock is higher than 8.8MHz
- Below the code I propose before configuring the SPI polarity (function spi_intr())
Code: Select all
nodelay=1;
extra_dummy=0;
if (!host->no_gpio_matrix) {
if (effclk >= apbclk/2) {
nodelay=0;
}
if (effclk >= (8800000)) {
extra_dummy=1; //Note: This only works on half-duplex connections. spi_bus_add_device checks for this.
}
}
Problems encountered and not solved
- When writing data on SPI, the slave does not read it correctly. See attached . Based on the CPHA = 1, latching the data by the slave should happen on the 2nd clk edge (rising edge). Instead of the correct 0x55, the slave reads random data. Shouldn't the MOSI data be shifted to the right by 1 cycle, so that the 01010101b pattern is more stable on the rising clk edge? In the picture I see the 1b on the MOSI rising at the same time as the CLK, on the same edge the slave reads data, so it will not be read correctly.
- When reading data on SPI, the master does not read it correctly. See attached . First of all I always see short pulses on CS line, which causes pulses on all the other lines, even CLK. See attached . Why are these pulses appearing and why does it influences the CLK, and therefore the transfer? I tried managing the CS from software, and the same pulses occur, so it may not be related to CS, but something else?
- During read, why do I see data on MOSI, as I set the "tx_buffer" to NULL in the read phase, MOSI should be unchanged...
Thanks in advance for anyone who can shed some light in these problems,
Valentin