[已解决」C3 SPI 运行 DMA 功能是否有问题!

axwfae
Posts: 6
Joined: Wed Oct 13, 2021 8:34 am

[已解决」C3 SPI 运行 DMA 功能是否有问题!

Postby axwfae » Wed Oct 13, 2021 8:47 am

最近购买了 c3 进行测试,发现了一个奇怪的问题!

当 SPI 啟用的 DMA 功能之后, 此时 SPI 会以十分怪异的方式出错!

(1) 不使用 DMA , SPI 以长度 64byte 读写正常
(2) 啟用 DMA , 写入不限制大小, 读取使用 FIFO 一个 byte 读取,读写正常
(3) 啟用 DMA , 读取不限制大小, 写入使用 FIFO 一个 byte 读取,读写正常


(4) 啟用 DMA , 读写不限制大小,此时读取正常,但是写入的资料第一笔正常 (350byte) , 之后所有的资料,出现了错误 了。 但是此时若是有用 SPI FIFO 方式的写入 (一个 byte 写入)这样的操作是正常的!

也就是说当啟用了 DMA , SPI 只能啟用 上面 (2) 或 (3) 的方式才能正常工作, 但是这样就丧失了 DMA 加速的功能了。 运行起来还没有 (1 ) 快

同样的駆动方式,在 S2 上 SPI 啟用 DMA 是正常的。



备注: 我买到的 c3 是版本 2 的, 不知是否是 版本 2 芯片的问题! 因為买不到 版本 3 无法证实!
Last edited by axwfae on Fri Oct 15, 2021 7:09 am, edited 1 time in total.

axwfae
Posts: 6
Joined: Wed Oct 13, 2021 8:34 am

Re: C3 SPI 运行 DMA 功能是否有问题!

Postby axwfae » Thu Oct 14, 2021 3:29 am

参考资料! 使用 IDF v4.3.1

Code: Select all

--- idf_monitor on com3 115200 ---
--- 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=572f0h (357104) map
I (187) esp_image: segment 4: paddr=00087318 vaddr=4038a33c size=042ech ( 17132) load
I (191) esp_image: segment 5: paddr=0008b60c 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:  2658ee3667091e2d...
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 (301) 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  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

使用 esp-idf\examples\ethernet\iperf 修改测试 芯片使用 dm9051 当 SPI 读写测试芯片

修改 esp-idf\examples\ethernet\iperf \mani\cmd_ethernet.c

关闭 DMA

Code: Select all

    ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 0));
或 啟用 DMA

Code: Select all

    ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 3));
修改 esp-idf\components\esp_eth\src\esp_eth_mac_dm9051.c

SPI操作部分的驅動

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;
}
加入测试的代码运行

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;    
}

(1) 関闭 DMA 以 64byte 分批读写 , 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
(2) 啟用 DMA , 写以 byte 写入, 读取以 64byte 区块读出, 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
(3) 啟用 DMA , 读写以 64byte 区块写入读出, 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
Last edited by axwfae on Fri Oct 15, 2021 1:39 am, edited 1 time in total.

ESP_Yake
Posts: 109
Joined: Mon Mar 06, 2017 12:23 pm

Re: C3 SPI 运行 DMA 功能是否有问题!

Postby ESP_Yake » Fri Oct 15, 2021 1:12 am

Hi, 从观察到的情况看,似乎通过 DMA 读取 64bytes 数据出错时,只正确读到了第一个字节,后面的数据是重复的。从你的示例看是 SPI 与 网卡进行通信,你能否试一下两个 C3 进行通信,看看是否有问题,这样能确定问题是 SPI 驱动的问题还是网卡这边驱动的问题

axwfae
Posts: 6
Joined: Wed Oct 13, 2021 8:34 am

Re: C3 SPI 运行 DMA 功能是否有问题!

Postby axwfae » Fri Oct 15, 2021 1:34 am

ESP_Yake wrote:
Fri Oct 15, 2021 1:12 am
Hi, 从观察到的情况看,似乎通过 DMA 读取 64bytes 数据出错时,只正确读到了第一个字节,后面的数据是重复的。从你的示例看是 SPI 与 网卡进行通信,你能否试一下两个 C3 进行通信,看看是否有问题,这样能确定问题是 SPI 驱动的问题还是网卡这边驱动的问题
我手上只有一片 C3 ,此段代码是放在 dm9051 的 init 段之前,也就是把 dm9051 当做一个 ram 读写使用!
同样的代码在 S2 上运行是正常的,不管 DMA 长度為多少! (也使用 64byte 区块读写测试过)

我用 64byte 是因為 c3 非使用 dma 模式时,只能使用 64byte 最大长度来读写,為了避免环境不同,导致误判。所以我改成 2 种皆是使用 64byte 区块方式来读写!

而且就像我之前所述! 把 读改成 byte 读取, 写改成不限长度 dma , 运行也是正常的! 所以我才会认為是否 c3 的 spi 是否 dma 操作有啥问题!

或者是 c3 ver2 这个版本有问题!

axwfae
Posts: 6
Joined: Wed Oct 13, 2021 8:34 am

Re: C3 SPI 运行 DMA 功能是否有问题!

Postby axwfae » Fri Oct 15, 2021 7:08 am

ESP_Yake wrote:
Fri Oct 15, 2021 1:12 am
Hi, 从观察到的情况看,似乎通过 DMA 读取 64bytes 数据出错时,只正确读到了第一个字节,后面的数据是重复的。从你的示例看是 SPI 与 网卡进行通信,你能否试一下两个 C3 进行通信,看看是否有问题,这样能确定问题是 SPI 驱动的问题还是网卡这边驱动的问题
十分感谢你的回讯!

刚刚已解决问题了,问题是 SDK V4.3.1 的问题! 出错点不知在何处! 重新下载了 master 重新测试过,就一切正常了! 测试速度也由 10Mbps -> 15Mbps 以上了!

Code: Select all

mode=tcp-client sip=192.168.123.167:5001, dip=192.168.123.150:5001, interval=3, time=30
I (12646) iperf: Successfully connected

        Interval Bandwidth
   0-   3 sec       14.77 Mbits/sec
   3-   6 sec       15.38 Mbits/sec
  6-   9 sec       15.20 Mbits/sec
   9-  12 sec       15.42 Mbits/sec
  12-  15 sec       15.34 Mbits/sec
  15-  18 sec       15.34 Mbits/sec
  18-  21 sec       15.38 Mbits/sec
  21-  24 sec       15.34 Mbits/sec
  24-  27 sec       15.34 Mbits/sec
  27-  30 sec       15.38 Mbits/sec
   0-  30 sec       15.29 Mbits/sec
I (42656) iperf: TCP Socket client is closed.

再次感谢你!

Who is online

Users browsing this forum: No registered users and 57 guests