「solved」Is there any problem with ESP32-C3 SPI running DMA function!
Posted: Thu Oct 14, 2021 7:13 am
I recently purchased ESP32-c3 for testing and found a strange problem!
After the DMA function of SPI is enabled, SPI will go wrong in a very strange way at this time!
(1) Do not use DMA, SPI reads and writes normally with a length of 64 bytes
(2) DMA is enabled, there is no limit to the size of writing, one byte of FIFO is used for reading, and the reading and writing are normal
(3) DMA is enabled, the size of reading is not limited, writing uses FIFO and one byte is read, reading and writing are normal
(4) Enabling DMA, the size of reading and writing is not limited. At this time, the reading is normal, but the first data written is normal (350byte), and all the data after that have errors. But at this time, it is normal to write in SPI FIFO mode (a byte write)!
That is to say, when DMA is enabled, SPI can only work normally by enabling the method (2) or (3) above, but in this way the DMA acceleration function is lost. It's not running (1) fast
In the same way, it is normal for SPI to enable DMA on ESP32-S2.
Remarks: The c3 I bought is version 2. I don’t know if it’s the version 2 chip! Unable to confirm because version 3 is not available!
Use IDF version as v4.3.1
boot log
Test code :
esp-idf\examples\ethernet\iperf
Enable DMA
Disable DMA
Test using DM9051 as an external SPI read and write device
esp-idf\components\esp_eth\src\esp_eth_mac_dm9051.c
Driver for SPI operation part
Test function code
Disable dma, 64byte block read and write , Pass
Enable dma, 64byte block read , one byte write , Pass
Enable dma, 64byte block read and write , Fail
After the DMA function of SPI is enabled, SPI will go wrong in a very strange way at this time!
(1) Do not use DMA, SPI reads and writes normally with a length of 64 bytes
(2) DMA is enabled, there is no limit to the size of writing, one byte of FIFO is used for reading, and the reading and writing are normal
(3) DMA is enabled, the size of reading is not limited, writing uses FIFO and one byte is read, reading and writing are normal
(4) Enabling DMA, the size of reading and writing is not limited. At this time, the reading is normal, but the first data written is normal (350byte), and all the data after that have errors. But at this time, it is normal to write in SPI FIFO mode (a byte write)!
That is to say, when DMA is enabled, SPI can only work normally by enabling the method (2) or (3) above, but in this way the DMA acceleration function is lost. It's not running (1) fast
In the same way, it is normal for SPI to enable DMA on ESP32-S2.
Remarks: The c3 I bought is version 2. I don’t know if it’s the version 2 chip! Unable to confirm because version 3 is not available!
Use IDF version as v4.3.1
boot log
Code: Select all
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
ESP-ROM:esp32c3-20200918
Build:Sep 18 2020
rst:0x1 (POWERON),boot:0xd (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd6100,len:0x17c4
load:0x403ce000,len:0x8dc
load:0x403d0000,len:0x2984
entry 0x403ce000
I (32) boot: ESP-IDF v4.3.1-dirty 2nd stage bootloader
I (32) boot: compile time 16:15:06
I (32) boot: chip revision: 2
I (34) boot.esp32c3: SPI Speed : 80MHz
I (39) boot.esp32c3: SPI Mode : DIO
I (44) boot.esp32c3: SPI Flash Size : 2MB
I (49) boot: Enabling RNG early entropy source...
I (54) boot: Partition Table:
I (58) boot: ## Label Usage Type ST Offset Length
I (65) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (72) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (80) boot: 2 factory factory app 00 00 00010000 00080000
I (87) boot: 3 storage Unknown data 01 81 00090000 00020000
I (95) boot: End of partition table
I (99) esp_image: segment 0: paddr=00010020 vaddr=3c060020 size=13fc4h ( 81860) map
I (120) esp_image: segment 1: paddr=00023fec vaddr=3fc8e800 size=01ce8h ( 7400) load
I (121) esp_image: segment 2: paddr=00025cdc vaddr=40380000 size=0a33ch ( 41788) load
I (133) esp_image: segment 3: paddr=00030020 vaddr=42000020 size=572ach (357036) map
I (187) esp_image: segment 4: paddr=000872d4 vaddr=4038a33c size=042ech ( 17132) load
I (191) esp_image: segment 5: paddr=0008b5c8 vaddr=50000000 size=00010h ( 16) load
I (198) boot: Loaded app from partition at offset 0x10000
I (199) boot: Disabling RNG early entropy source...
I (216) cpu_start: Pro cpu up.
I (228) cpu_start: Pro cpu start user code
I (228) cpu_start: cpu freq: 160000000
I (228) cpu_start: Application information:
I (231) cpu_start: Project name: ethernet_iperf
I (237) cpu_start: App version: 1
I (241) cpu_start: Compile time: Oct 6 2021 16:11:07
I (247) cpu_start: ELF file SHA256: 4f5f21638fb8ac48...
I (253) cpu_start: ESP-IDF: v4.3.1-dirty
I (259) heap_init: Initializing. RAM available for dynamic allocation:
I (266) heap_init: At 3FC92550 len 0002DAB0 (182 KiB): DRAM
I (272) heap_init: At 3FCC0000 len 0001F260 (124 KiB): STACK/DRAM
I (279) heap_init: At 50000010 len 00001FF0 (7 KiB): RTCRAM
I (285) spi_flash: detected chip: generic
I (290) spi_flash: flash io: dio
I (294) sleep: Configure to isolate all GPIO pins in sleep state
I (300) sleep: Enable automatic switching of GPIO sleep configuration
I (308) cpu_start: Starting scheduler.
W (313) vfs_fat_spiflash: f_mount failed (13)
I (313) vfs_fat_spiflash: Formatting FATFS partition, allocation unit size=4096
E (323) vfs_fat_spiflash: f_mkfs failed (14)
E (323) eth_example: Failed to mount FATFS (ESP_FAIL)
Type 'help' to get the list of commands.
Use UP/DOWN arrows to navigate through command history.
Press TAB when typing command name to auto-complete.
Your terminal application does not support escape sequences.
Line editing and history features are disabled.
On Windows, try using Putty instead.
spi rw test 100byte 1 ==>
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
60 61 62 63
spi rw test 100byte 2 ==>
02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42
42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42
42 42 42 42
Test code :
esp-idf\examples\ethernet\iperf
Enable DMA
Code: Select all
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 3));
Code: Select all
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 0));
Test using DM9051 as an external SPI read and write device
esp-idf\components\esp_eth\src\esp_eth_mac_dm9051.c
Driver for SPI operation part
Code: Select all
/**
* @brief write value to dm9051 internal register
*/
static esp_err_t dm9051_register_write(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t value)
{
esp_err_t ret = ESP_OK;
spi_transaction_t trans = {
.cmd = DM9051_SPI_WR,
.addr = reg_addr,
.length = 8,
.flags = SPI_TRANS_USE_TXDATA
};
trans.tx_data[0] = value;
if (dm9051_lock(emac)) {
if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
ret = ESP_FAIL;
}
dm9051_unlock(emac);
} else {
ret = ESP_ERR_TIMEOUT;
}
return ret;
}
/**
* @brief write buffer to dm9051 internal memory
*/
static esp_err_t dm9051_memory_write(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len)
{
esp_err_t ret = ESP_OK;
spi_transaction_t trans = {
.cmd = DM9051_SPI_WR,
.addr = DM9051_MWCMD,
.length = len * 8,
.tx_buffer = buffer
};
if (dm9051_lock(emac)) {
if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
ret = ESP_FAIL;
}
dm9051_unlock(emac);
} else {
ret = ESP_ERR_TIMEOUT;
}
return ret;
}
/**
* @brief read buffer from dm9051 internal memory
*/
static esp_err_t dm9051_memory_read(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len)
{
esp_err_t ret = ESP_OK;
spi_transaction_t trans = {
.cmd = DM9051_SPI_RD,
.addr = DM9051_MRCMD,
.length = len * 8,
.rx_buffer = buffer
};
if (dm9051_lock(emac)) {
if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
ret = ESP_FAIL;
}
dm9051_unlock(emac);
} else {
ret = ESP_ERR_TIMEOUT;
}
return ret;
}
#define SPI_NO_DMA_LEN 64
/**
* @brief write buffer to dm9051 internal memory in no dma mode
*/
static esp_err_t dm9051_block_write(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len)
{
esp_err_t ret = ESP_OK;
uint32_t wlTx_cnt = 0;
for(wlTx_cnt = 0; wlTx_cnt < len; wlTx_cnt+= SPI_NO_DMA_LEN)
{
if(ESP_OK != dm9051_memory_write(emac,buffer+wlTx_cnt, ((len - wlTx_cnt) > SPI_NO_DMA_LEN) ? SPI_NO_DMA_LEN : (len - wlTx_cnt) ))
{
return ESP_FAIL;
}
}
return ret;
}
static esp_err_t dm9051_one_write(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len)
{
esp_err_t ret = ESP_OK;
uint32_t wlTx_cnt = 0;
for(wlTx_cnt = 0; wlTx_cnt < len; wlTx_cnt++)
{
if(ESP_OK != dm9051_register_write(emac, DM9051_MWCMD , buffer[wlTx_cnt]))
{
return ESP_FAIL;
}
}
return ret;
}
/**
* @brief read buffer from dm9051 internal memory in no dma mode
*/
static esp_err_t dm9051_block_read(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len)
{
esp_err_t ret = ESP_OK;
uint32_t wlRx_cnt = 0;
for(wlRx_cnt = 0; wlRx_cnt < len; wlRx_cnt+=SPI_NO_DMA_LEN)
{
if(ESP_OK != dm9051_memory_read(emac,buffer+wlRx_cnt, ((len - wlRx_cnt) > SPI_NO_DMA_LEN) ? SPI_NO_DMA_LEN : (len - wlRx_cnt) ))
{
return ESP_FAIL;
}
}
return ret;
}
Test function code
Code: Select all
static esp_err_t spi_rw_test(emac_dm9051_t *emac)
{
esp_err_t ret = ESP_OK;
uint8_t tx_value[100];
uint8_t rx_data[100];
uint8_t nCnt;
for(nCnt = 0; nCnt <100; nCnt++)
{
tx_value[nCnt] = nCnt;
rx_data[nCnt] = 0;
}
// MAC_CHECK(dm9051_block_write(emac, tx_value, 100) == ESP_OK, "write memory failed", err, ESP_FAIL);
MAC_CHECK(dm9051_one_write(emac, tx_value, 100) == ESP_OK, "write memory failed", err, ESP_FAIL);
MAC_CHECK(dm9051_block_read(emac, rx_data, 100) == ESP_OK, "read rx data failed", err, ESP_FAIL);
printf("\n spi rw test 100byte 1 ==>");
for(nCnt = 0; nCnt <100; nCnt++)
{
if(0 == (nCnt % 16)) printf("\n");
printf(" %02x ", rx_data[nCnt]);
rx_data[nCnt] = 0;
tx_value[nCnt] = nCnt + 2;
}
// MAC_CHECK(dm9051_block_write(emac, tx_value, 100) == ESP_OK, "write memory failed", err, ESP_FAIL);
MAC_CHECK(dm9051_one_write(emac, tx_value, 100) == ESP_OK, "write memory failed", err, ESP_FAIL);
MAC_CHECK(dm9051_block_read(emac, rx_data, 100) == ESP_OK, "read rx data failed", err, ESP_FAIL);
printf("\n spi rw test 100byte 2 ==>");
for(nCnt = 0; nCnt <100; nCnt++)
{
if(0 == (nCnt % 16)) printf("\n");
printf(" %02x ", rx_data[nCnt]);
// rx_data[nCnt] = 0;
// tx_value[nCnt] = nCnt + 2;
}
err:
return ret;
}
Disable dma, 64byte block read and write , Pass
Code: Select all
spi rw test 100byte 1 ==>
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
60 61 62 63
spi rw test 100byte 2 ==>
02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11
12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21
22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31
32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41
42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51
52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61
62 63 64 65
Enable dma, 64byte block read , one byte write , Pass
Code: Select all
spi rw test 100byte 1 ==>
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
60 61 62 63
spi rw test 100byte 2 ==>
02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11
12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21
22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31
32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41
42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51
52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61
62 63 64 65
Enable dma, 64byte block read and write , Fail
Code: Select all
spi rw test 100byte 1 ==>
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
60 61 62 63
spi rw test 100byte 2 ==>
02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42
42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42
42 42 42 42