Open zavovi opened 5 years ago
And the speed from master is 500Kb.
@zavovi Thanks for reporting the issue. Would you please help provide more details as suggested in the issue template? Information like elf, sdk configuration, backtrace, log outputs, commit ID, hardware and etc. would help us debug further. Thanks.
Environment Development Kit: ESP32-DevKit Kit version (DevKit): v1 Module or chip used: ESP32-WROOM-32 IDF version (run git describe --tags to find it): v3.3-beta3-181-g70ecb7ec9 Build System: Make Compiler version (run xtensa-esp32-elf-gcc --version to find it): (crosstool-NG crosstool-ng-1.22.0-80-g6c4433a5) 5.2.0 Operating System: Windows Power Supply: USB
Make command: make flash ESPPORT=COM10 -j4 monitor
Note: This kit is connected to FRDM-K64 development kit for communication over SPI. It was tested on wire connection and on the my own board, where is connection between both MCUs on the board.
Problem Description
Expected Behavior: Receiving all SPI packets. Actual Behavior: Lost each second SPI packet.
I am attaching my ELF (bin) file, sdkconfig, logs and readme. I haven't got two ESP32 modules, but I can try to describe, which data you should send via SPI. This example is SPI slave. ESP-SPI-issue.zip
/ SPI SETTINGS on ESP32 side /
SPI data protocol: 1 byte - 0x88 2 bytes - length x bytes - data
Maximum length of data is 64 with header (0x88 + length).
The ESP32 send response only, when the data is ok for tha protocol above. I don't want share the other protocols in my device.
This is my test on the FRDM kinetis side:
//TODO: START TEST!
uint8_t data[256];
uint32_t sent = 0;
uint32_t sent_all = 0;
for(int i=0; i<256; i++)
data[i] = i;
tcs_esp32_connection_hw_reset();
tcs_timer_wait_ms(10000);
while(256-sent_all)
{
if(comm_ctx.ready_to_send)
{
tcs_spi_send(data+sent_all, 256-sent_all, &sent);
sent_all += sent;
}
/* Dummy recv for read data if possible */
else if(comm_ctx.ready_to_recv)
{
printf("r\n");
tcs_spi_recv();
}
}
while(1){};
//TODO: END TEST!
static tcs_err_t tcs_spi_send(const uint8_t * data, uint32_t len, uint32_t * sent)
{
dspi_status_t dspiResult;
uint32_t wordsTransfer = 0;
uint16_t tx_size = 0;
uint8_t rx_tmp_buff[TCS_COMM_RX_TX_SIZE];
uint8_t tx_tmp_buff[TCS_COMM_RX_TX_SIZE];
*sent = 0;
printf(".");
/* Wait for interrupt, that tells all data received in slave */
if(!comm_ctx.ready_to_send)
return TCS_OK;
printf("-");
/* Not yet done latest operation. */
if(DSPI_DRV_MasterGetTransferStatus(TCS_WIFI_DSPI_MASTER_INSTANCE, &wordsTransfer) != kStatus_DSPI_Success)
return TCS_OK;
printf("-");
/* Sending, wait! */
comm_ctx.ready_to_send = TCS_FALSE;
tcs_memset(rx_tmp_buff, 0, TCS_COMM_RX_TX_SIZE);
tcs_memset(tx_tmp_buff, 0, TCS_COMM_RX_TX_SIZE);
tx_size = len;
if(tx_size > TCS_COMM_RX_TX_SIZE-3)
tx_size = TCS_COMM_RX_TX_SIZE-3;
tcs_memcpy(tx_tmp_buff+3, data, tx_size);
/* START byte */
tx_tmp_buff[0] = 0x88;
/* TX len */
tx_tmp_buff[1] = TCS_LOBYTE(tx_size);
tx_tmp_buff[2] = TCS_HIBYTE(tx_size);
TCS_DEBUG_PRINTHEX(TCS_LOG_CATEGORY, "SPI sending data", tx_tmp_buff, TCS_COMM_RX_TX_SIZE );
/* Send the data. */
dspiResult = DSPI_DRV_MasterTransfer(TCS_WIFI_DSPI_MASTER_INSTANCE, NULL, tx_tmp_buff, rx_tmp_buff, TCS_COMM_RX_TX_SIZE);
if (dspiResult != kStatus_DSPI_Success)
{
TCS_ERROR_PRINTF(TCS_LOG_CATEGORY, "SPI send error!");
comm_ctx.ready_to_send = TCS_TRUE;
return TCS_ERR_FAIL;
}
/* Wait for SPI transfer done (Because it can receive any data when sending! - This must be changed to non-blocking mode!) */
while((dspiResult = DSPI_DRV_MasterGetTransferStatus(TCS_WIFI_DSPI_MASTER_INSTANCE, &wordsTransfer)) == kStatus_DSPI_Busy);
if(dspiResult != kStatus_DSPI_Success)
TCS_ERROR_PRINTF(TCS_LOG_CATEGORY, "SPI send/recv error (%d)!", dspiResult);
else
TCS_INFO_PRINTF(TCS_LOG_CATEGORY, "==SPI sent %d.", tx_size);
/* If anything received when sending */
if(/*wordsTransfer != 0 &&*/ rx_tmp_buff[0] == 0x88)
{
uint16_t rxlen = TCS_UINT16(rx_tmp_buff[1], rx_tmp_buff[2]);
if(rxlen <= (TCS_COMM_RX_TX_SIZE-3) )
{
TCS_INFO_PRINTF(TCS_LOG_CATEGORY, "==SPI received %d in send.", rxlen);
TCS_DEBUG_PRINTHEX(TCS_LOG_CATEGORY, "SPI received data", rx_tmp_buff, rxlen+3 );
tcs_buffer_add(&comm_ctx.rx, rx_tmp_buff+3, rxlen, TCS_TRUE);
}
}
*sent = tx_size;
return TCS_OK;
}
static tcs_err_t tcs_spi_recv(void)
{
dspi_status_t dspiResult;
uint32_t wordsTransfer = 0;
uint8_t rx_tmp_buff[TCS_COMM_RX_TX_SIZE];
uint8_t tx_tmp_buff[TCS_COMM_RX_TX_SIZE];
/* Wait for interrupt, that tells any data is pending in slave */
if(!comm_ctx.ready_to_recv)
return TCS_OK;
/* Not yet done latest operation. */
if(DSPI_DRV_MasterGetTransferStatus(TCS_WIFI_DSPI_MASTER_INSTANCE, &wordsTransfer) != kStatus_DSPI_Success /*kStatus_DSPI_Busy*/)
return TCS_OK;
tcs_memset(rx_tmp_buff, 0, TCS_COMM_RX_TX_SIZE);
tcs_memset(tx_tmp_buff, 0, TCS_COMM_RX_TX_SIZE);
/* Receive data. */
dspiResult = DSPI_DRV_MasterTransfer(TCS_WIFI_DSPI_MASTER_INSTANCE, NULL, tx_tmp_buff, rx_tmp_buff, TCS_COMM_RX_TX_SIZE);
if (dspiResult != kStatus_DSPI_Success)
{
TCS_ERROR_PRINTF(TCS_LOG_CATEGORY, "SPI send error!");
return TCS_ERR_FAIL;
}
printf("rx\n");
/* Receiving */
comm_ctx.ready_to_recv = TCS_FALSE;
/* Wait for SPI transfer done */
while((dspiResult = DSPI_DRV_MasterGetTransferStatus(TCS_WIFI_DSPI_MASTER_INSTANCE, &wordsTransfer)) == kStatus_DSPI_Busy);
if(dspiResult != kStatus_DSPI_Success)
TCS_ERROR_PRINTF(TCS_LOG_CATEGORY, "SPI recv error (%d)!", dspiResult);
/* Check first byte of received data, must be 0x88 */
if(rx_tmp_buff[0] == 0x88)
{
uint16_t rxlen = TCS_UINT16(rx_tmp_buff[1], rx_tmp_buff[2]);
TCS_INFO_PRINTF(TCS_LOG_CATEGORY, "==SPI received %d.", rxlen);
if(rxlen <= (TCS_COMM_RX_TX_SIZE-3) )
{
TCS_INFO_PRINTF(TCS_LOG_CATEGORY, "==SPI received %d.", rxlen);
TCS_DEBUG_PRINTHEX(TCS_LOG_CATEGORY, "SPI received data", rx_tmp_buff, rxlen+3 );
tcs_buffer_add(&comm_ctx.rx, rx_tmp_buff+3, rxlen, TCS_TRUE);
}
}
return TCS_OK;
}
Hi, I am working on it and debugging and I changed handling of the handshake pin into main communication task and it seems, that it is working now.
This is my communication task now:
static void tcs_communication_rx_tx_task(void *pvParameter)
{
tcs_err_t err;
uint8_t * rx_data;
uint8_t * tx_data;
uint32_t tx_size = 0;
comm_ctx.events = xEventGroupCreate();
ESP_LOGI(TAG, "Starting RX/TX task...");
if(comm_ctx.type == COMM_TYPE_UART)
{
/* Initialize UART */
err = tcs_uart_init();
}
else if(comm_ctx.type == COMM_TYPE_SPI)
{
/* Initialize SPI */
err = tcs_spi_init();
}
else
{
ESP_LOGE(TAG, "Bad communication type!\n");
err = TCS_ERR_BADPARAM;
}
if(TCS_FAILED(err))
goto ERROR;
/* Prepare buffers */
tcs_buffer_prepare(&comm_ctx.rx, TCS_COMM_RX_TX_SIZE);
tcs_buffer_prepare(&comm_ctx.tx, TCS_COMM_RX_TX_SIZE);
/* Prepare RX buffer */
rx_data = heap_caps_malloc(TCS_COMM_RX_TX_SIZE+1, MALLOC_CAP_DMA);
if(rx_data == NULL)
{
ESP_LOGE(TAG, "Error in malloc receive buffer.\n");
err = TCS_ERR_NOMEM;
goto ERROR;
}
/* Prepare TX buffer */
tx_data = heap_caps_malloc(TCS_COMM_RX_TX_SIZE+1, MALLOC_CAP_DMA);
if(tx_data == NULL)
{
ESP_LOGE(TAG, "Error in malloc transmit buffer.\n");
err = TCS_ERR_NOMEM;
goto ERROR;
}
memset(rx_data, 0, TCS_COMM_RX_TX_SIZE+1);
memset(tx_data, 0, TCS_COMM_RX_TX_SIZE+1);
comm_ctx.initialized = true;
while(1)
{
if(comm_ctx.type == COMM_TYPE_UART)
{
int received = uart_read_bytes(COMM_UART_NUM, rx_data, TCS_COMM_RX_TX_SIZE, 10 / portTICK_RATE_MS);
if(received < 0)
{
ESP_LOGE(TAG, "UART read bytes failed!\n");
err = TCS_ERR_COMM;
}
else
{
/* Wait for not locked */
while(tcs_buffer_is_locked(&comm_ctx.rx));
/* Lock buffer */
tcs_buffer_lock(&comm_ctx.rx);
tcs_buffer_add(&comm_ctx.rx, rx_data, received, true);
/* Unlock buffer */
tcs_buffer_unlock(&comm_ctx.rx);
/* set event for receive task */
xEventGroupSetBits(comm_ctx.events, COMM_EVENT_RX);
}
}
else if(comm_ctx.type == COMM_TYPE_SPI)
{
spi_slave_transaction_t t;
if(comm_ctx.spi_pending)
continue;
memset(&t, 0, sizeof(t));
memset(rx_data, 0, TCS_COMM_RX_TX_SIZE+1);
memset(tx_data, 0, TCS_COMM_RX_TX_SIZE+1);
tx_size = 0;
t.length = TCS_COMM_RX_TX_SIZE*8;
t.rx_buffer = rx_data;
t.trans_len = 0;
t.tx_buffer = NULL;
/* Wait for not locked */
while(tcs_buffer_is_locked(&comm_ctx.tx));
/* Lock buffer */
tcs_buffer_lock(&comm_ctx.tx);
tx_size = tcs_buffer_get_used(&comm_ctx.tx);
//tx_data[0] = 0;
/* Copy TX data from context to transmit buffer */
if(tx_size > 0)
{
#if TCS_COMM_DEBUG_PRINT
printf("TX%d\n", tx_size);
#endif
if(tx_size > TCS_COMM_RX_TX_SIZE-3)
tx_size = TCS_COMM_RX_TX_SIZE-3;
memcpy(tx_data+3, comm_ctx.tx.buffer, tx_size);
/* START byte */
tx_data[0] = 0x88;
/* TX len */
tx_data[1] = TCS_LOBYTE(tx_size);
tx_data[2] = TCS_HIBYTE(tx_size);
/* Consume buffer */
tcs_buffer_consume(&comm_ctx.tx, tx_size);
#if TCS_COMM_DEBUG_PRINT
//ESP_LOGI(TAG, "Transmit SPI data %d", tx_size);
ESP_LOG_BUFFER_HEX(TAG, tx_data, tx_size+3);
#endif
t.trans_len = (tx_size+3)*8;
t.tx_buffer = tx_data;
}
/* Unlock buffer */
tcs_buffer_unlock(&comm_ctx.tx);
WRITE_PERI_REG(GPIO_OUT_W1TS_REG, (1<<COMM_SPI_GPIO_HANDSHAKE));
comm_ctx.spi_pending = true;
esp_err_t ret = spi_slave_transmit(COMM_SPI_HOST, &t,/* 100 / portTICK_RATE_MS*/portMAX_DELAY);
if(ret == ESP_ERR_TIMEOUT)
{
ESP_LOGE(TAG, "SPI RX/TX timeout (0x%02x)!\n", ret);
comm_ctx.spi_pending = false;
/* Do nothing */
continue;
}
else if(ret != ESP_OK)
{
comm_ctx.spi_pending = false;
ESP_LOGE(TAG, "SPI RX/TX failed (0x%02x)!\n", ret);
err = TCS_ERR_COMM;
}
else
{
/* Wait for not locked */
while(tcs_buffer_is_locked(&comm_ctx.rx));
/* Lock buffer */
tcs_buffer_lock(&comm_ctx.rx);
uint16_t rxlen = 0;
if((t.trans_len/8) > 3 && rx_data[0] == 0x88)
{
rxlen = TCS_UINT16(rx_data[1], rx_data[2]);
#if TCS_COMM_DEBUG_PRINT
ESP_LOGW(TAG, "SPI RX - %d.", t.trans_len/8);
#endif
//if(rxlen <= (t.trans_len-3) )
{
#if TCS_COMM_DEBUG_PRINT
//ESP_LOGI(TAG, "Received SPI data %d/%d", t.trans_len/8, TCS_COMM_RX_TX_SIZE);
ESP_LOG_BUFFER_HEX(TAG, rx_data, t.trans_len/8);
ESP_LOGW(TAG, "SPI RX (%d).", rxlen);
#endif
tcs_buffer_add(&comm_ctx.rx, rx_data+3, rxlen, true);
}
}
/* Unlock buffer */
tcs_buffer_unlock(&comm_ctx.rx);
/* set event for receive task */
//if(rxlen > 0)
xEventGroupSetBits(comm_ctx.events, COMM_EVENT_RX);
}
WRITE_PERI_REG(GPIO_OUT_W1TC_REG, (1<<COMM_SPI_GPIO_HANDSHAKE));
//rx_data[0] = 0;
}
}
ERROR:
vTaskDelay(1000 / portTICK_PERIOD_MS);
esp_restart();
}
And I removed handshake pin handling from the SPI callbacks. Now, I will try the maximum speed of the SPI.
@zavovi One thing you need to know is that, the SPI slave inside ESP32 is a totally Software-controlled one. Which means, the slave SW needs to configure the HW before the transaction actually happens, no matter sending or receiving.
If the master send at wrong time (when the slave HW is not ready), the master will not receive correct data from the slave, and no way to know it's incorrect. At the same the slave may not know the master has sent anything, and there's also no guarantee whats being sent to master/received from the master.
In short, a handshake line should always be used to ensure the slave is ready for next transaction.
Sorry for late reply, hope you have solved your issue...
About the requirement of coordinating the sending direction, we havn't come up with a simple solution. If you want to have a try, maybe you can try to use two transactions in a pair (both of them needs one handshake signal), and use the first transaction to indicate the direction...
Hello, please, I am working on SPI slave node with ESP32 and esp-idf and I have one issue. I am transmitting blocks with 64 bytes and when I transmit all 64 bytes and I want transmit next and next, then some blocks are missing there. I tried check the line on scope and I see all data, but not received in ESP32 module. Please, could you help me or check, if is it the issue in esp-idf?
This is my communication task:
The communication is controlled by master, which is waiting for interrupts from COMM_SPI_GPIO_HANDSHAKE. When the COMM_SPI_GPIO_HANDSHAKE is low -> It is ready to receive data, when it is high --> It is ready to send data.
Please, could you help me? Thank you very much!