Open jankens opened 3 months ago
请问有人能回答我的问题吗?
@jankens 感谢你的提问
硬件设计上为了实现不间断的发送以提高吞率,采用了这种递增计数器的方式。这个计数器无需复位,否则每次复位都需要传输暂停,引入复杂的同步机制,会降低吞吐率。计数中显示的值是历史上曾经挂载过的buffer数量,减去host端已经消耗的数量可以得到剩余数量。
出于硬件成本考量,这个计数器被设计为 12 位 [27:16],因此同一寄存器的其他 20 位与此问题无关,可忽略( https://github.com/espressif/esp-idf/blob/master/components/soc/esp32/include/soc/host_struct.h#L77 )。如果阅读代码你可以看到代码中 >> 16 的那一行就是在取出这有效的 12 bit。
每当计数器溢出 4096 的边界,需要一个溢出的处理,如下:
已消耗: 8000 当前值: 100 (历史曾经挂载 4096 2 + 100=8292) 实际剩余可用: 292 = 4096 2 + 100 - 8000
公式中 (x + MAX - y) % MAX 是为了避免 x - y 出现负数而做的操作。不过这里有个要求是 0 <= y < MAX+1。你使用的这个仓库并不是 IDF 中的代码,它的出处可能是这里: https://github.com/espressif/idf-extra-components/blob/master/esp_serial_slave_link/essl_sdio.c#L373 在这个原始代码中,当 y > MAX时,似乎是有点问题的。在你的情况中你可以把 tx_buffer_count 先跟 MAX 取余之后再减,看看是否有改善:
*len = (*len + MAX - (count % MAX)) % MAX
但这段代码并不在 IDF 仓库里面,所以我没有办法直接修复。你可以把问题提交给对应仓库的作者。如果他是乐鑫官方提供的代码,请提供出处,我们会转交给对应的同事处理。
Dear Michael, 非常感谢你的回复! 我的这个代码是来源于君正X2100官方的 linux (版本是4.4.94+)。据他们说也是得到乐鑫的支持开发出来的。 根据你的说法我做了改动,但是还是不能通过(计算出来的*len == 0)。看起来是不是你提到的 “已消耗(context->tx_buffer_count)” 已经消耗完了? 下图为kernel driver 修改及打印结果。(附件有整个driver的代码,麻烦你再帮我确认一下,感谢感谢!!)
BR Jankens
Jankens
Sender: Michael Send Time: 2024-09-02 18:15 Receiver: espressif/esp-idf cc: jankens; Mention Subject: Re: [espressif/esp-idf] SDIO 通讯到一定数量后会卡住 (IDFGH-13436) (Issue #14342) @jankens 感谢你的提问 硬件设计上为了实现不间断的发送以提高吞率,采用了这种递增计数器的方式。这个计数器无需复位,否则每次复位都需要传输暂停,引入复杂的同步机制,会降低吞吐率。计数中显示的值是历史上曾经挂载过的buffer数量,减去host端已经消耗的数量可以得到剩余数量。 出于硬件成本考量,这个计数器被设计为 12 位 [27:16],因此同一寄存器的其他 20 位与此问题无关,可忽略(https://github.com/espressif/esp-idf/blob/master/components/soc/esp32/include/soc/host_struct.h#L77)。如果阅读代码你可以看到代码中 >> 16 的那一行就是在取出这有效的 12 bit。 每当计数器溢出 4096 的边界,需要一个溢出的处理,如下: 已消耗: 8000 当前值: 100 (历史曾经挂载 40962 + 100) 实际剩余可用: 292 = 40962 + 100 - 8000 公式中 (x + MAX - y) % MAX 是为了避免 x - y 出现负数而做的操作。不过这里有个要求是 0 <= y < MAX+1。你使用的这个仓库并不是 IDF 中的代码,它的出处可能是这里: https://github.com/espressif/idf-extra-components/blob/master/esp_serial_slave_link/essl_sdio.c#L373 在这个原始代码中,当 y > MAX时,似乎是有点问题的。在你的情况中你可以把 tx_buffer_count 先跟 MAX 取余之后再减,看看是否有改善: len = (len + MAX - (count % MAX)) % MAX 但这段代码并不在 IDF 仓库里面,所以我没有办法直接修复。你可以把问题提交给对应仓库的作者。如果他是乐鑫官方提供的代码,请提供出处,我们会转交给对应的同事处理。 — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>
@ginkgm @ 请问我的问题是否清晰,是否需要我提供更多资料? 这个问题一直没解决,没法出货啊!
@jankens 我现在能想到的一点是,你上面提到的“超过4096以后变为0”这个指的是remain的数量对吗?
由于我们的计数器只有12位,4096 种数值状态表示剩下buffer = 0~4095 的4096种情况,无法表示超过4095的情况。所以不允许slave端同时挂载超过4095个 buffer。请确认slave端挂载的buffer数量不要超过限制。
另外,允许同时挂载的主要目的是提高吞率,避免软件处理buffer时硬件无buffer可用。但挂这么多个明显超出了正常需求,少挂一点不会影响性能的。
@ginkgm 我不认为这个问题是这里的代码处理不严谨导致的,应该也不是 slave 挂载多的问题,因为 esp-hosted 方案大多不会用带 PSRAM 的芯片,不会有这么多内存挂载。 我认为这个问题是 slave 侧可能出现某些异常导致计数器没有递增(也就是没有释放出来buffer),表现为host侧 len 一直为0。 但是 esp-hosted 代码我们压力测试过的,而且大量客户已经量产使用,这里应该不会是溢出导致的异常。想要debug这个问题,我给你们的建议是:
@ginkgm @Jacques-Zhao 按照@ginkgm的意思,ESP_SLAVE_TOKEN_RDATA应该是一个counter, 从打印结果看,应该是因为ESP_RX_BUFFER_SIZE == 2048,所以每发送一次,这个counter就会+4(由esp module修改)。 但是从上面的代码看,每发送一次,tx_buffer_counter += buf_needed,会让tx_buffer_counter增加1。 那么这就造成在某一个数字上(当ESP_SLAVE_TOKEN_RDATA正好等于tx_buffer_counter的时候),*len == 0 计算出来的buf_available(0) 会小于 buf_needed(1). 但是如果我稍加改变,硬使这个时候的buf_avaliable != 0, 还是会出现esp module报错。 所以我认为应该是esp 那边需要做1个reset的动作,reset这个 ESP_SLAVE_TOKEN_RDATA.就有点像 ring buffer回到开头一样。 不知道2位有什么看法。
@jankens 先确认一点,你们使用的是 esp-hosted 方案吗?我感觉你们 ESP 侧并不是我们 hosted 的代码。这里你看到计数器返回4 ,感觉是 slave 默认用 512 作为buffer 大小挂载的,这样你要发送 1536字节就需要 slave 有 4 个空闲的 buffer, 而我们 ESP 侧原始代码里面 Buffer 大小是 1536(https://github.com/espressif/esp-hosted/blob/master/esp_hosted_fg/esp/esp_driver/network_adapter/main/sdio_slave_api.c#L210, 所以每次发送只需要一个空闲buffer,linux这里就可以匹配上了
@Jacques-Zhao 哦,因为我们esp module里的功能合并在一起比较多,所以内存没有那么多,我把BUFFER_SIZE 和 BUFFER_NUM都改掉了(参见下图)。所以1次传送512bytes,确实是分成4个buffer。 请问这样会影响到什么呢?
我用的esp-idf版本是5.1.3.
@jankens 就像我说的,你这个 BUFFER_SIZE 是 128,BUFFER_NUM 是18,这样你在初始化时 SDIO 申请内存就需要 128 * 16 的空间,这其中,每个buffer接收 128字节,如果你发 512,我这边就会认为用了 4 个 buffer 去接受,那么计数器会累加4,但是 linux那边并不认为每个 buffer 接收128字节,那边只会累加1,这就导致两方不匹配,从而通信一段时间后触发异常。 这里建议你把 BUFFER_SIZE 改成和 linux一致的,然后 buffer_num 改小一些,就可以解决你们的问题,也不会有其他影响。 另外,我看你使用的是sdio slave 的demo,这个demo只是演示各个接口的用法,在实际使用中你们是需要根据需求更改的,在你们linux使用了hosted接口的前提下,更建议你们 slave 侧也基于 hosted 里面 esp sdio的实现来改
@Jacques-Zhao 非常感谢你的回复,我大概明白你的意思了。我会做相应的修改。后续如果有问题再向你请教。
@Jacques-Zhao 我用一个与STM32 Pin2Pin兼容的MCU (Artery),透过SDIO连接ESP32 module的时候遇到回复data CRC error的问题 传输设置:
异常情况描述:
怀疑是esp32出现状态异常,没有完成写操作
结论:Artery已经发送了正确的frame及CRC,但是ESP32没有给出相应的回应。
附件: 2024-09-19_11-17-34.kvdata : LA 保存的数据文件。
@jankens 从逻辑分析仪上面这种无法确定问题, ESP32 没有给出来回应一般是波形有问题,如果好复现的话,应该用示波器抓一下异常时的波形。不过在此之前,我建议你们先改成1线测试,这个更少有信号完整性问题。
Answers checklist.
General issue report
我们在使用 sdio 连接esp32 模块的时候遇到一个传送数据卡主的问题。具体情况如下,请帮忙澄清。非常感谢!! 以下是host cpu sdio driver的代码: 上图打印的结果是: 当 *len达到4096以后,就会变成0,导致 buf_available < buf_needed