硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1866|回复: 10
收起左侧

[SPI/QSPI] SPI DMA 方式的疑惑

[复制链接]

25

主题

233

回帖

308

积分

高级会员

积分
308
QQ
发表于 2024-12-21 14:45:30 | 显示全部楼层 |阅读模式
最近想用 armink 的 SFUD 库代替原本自己写的 SPI FLASH 驱动库,他的支持似乎更全面更标准。
驱动 SPI 时有如下两种方式连续收发数据



[C] 纯文本查看 复制代码
HAL_SPI_Transmit_DMA(spi_dev->spix, (uint8_t *)write_buf, write_size); // SPI发送data中的数据
HAL_SPI_Receive_DMA(spi_dev->spix, (uint8_t *)read_buf, read_size); // SPI读取data中的数据



[C] 纯文本查看 复制代码
HAL_SPI_Transmit(spi_dev->spix, (uint8_t *)write_buf, write_size, 1000); // SPI发送data中的数据
HAL_SPI_Receive(spi_dev->spix, (uint8_t *)read_buf, read_size, 1000);    // SPI读取data中的数据


因为 hal 库的限制,使用 DMA 方式时,发送通道还没有完成,调用接收通道时会报 HAL_BUSY,无法及时打开接收通道。
如果 while 死等发送通道完毕,那似乎用不用 DMA 也没有太大区别。
这个地方有没有比较好的方法进行处理呢?
想到一个解决方法是利用 RTOS 的信号量,发送 DMA 的结束回调可以给出这个信号量,再立即开启接收通道。但是这样做,是否给出信号量、是否后续还有接收,是不同的处理,导致发送 DMA 的结束回调并不一致。

因为原本自己的库是开通了足够大的全局 buffer 以供发送通道填充 DUMMY 也就是 0xFF,可以直接使用 TransmitReceive_DMA ,而 SFUD 到处都是临时数组,不敢直接开 TransmitReceive_DMA 。

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117546
QQ
发表于 2024-12-21 15:39:32 | 显示全部楼层
死等就行,安全可靠稳定, 设置复杂度低,适合SPI Flash场景。

但不可以让他一直占着CPU不放,死等里面加个osDelay(1)
回复

使用道具 举报

25

主题

233

回帖

308

积分

高级会员

积分
308
QQ
 楼主| 发表于 2024-12-21 16:06:33 | 显示全部楼层
eric2013 发表于 2024-12-21 15:39
死等就行,安全可靠稳定, 设置复杂度低,适合SPI Flash场景。

但不可以让他一直占着CPU不放,死等里面加 ...

DMA这里的话,死等就得占着CPU不放,不然会丢数据

例如读 SFUD 头部这里,与 flash 的整个通信流是

MOSI 5A 00 00 00 FF XX XX XX XX XX XX XX
MISO XX XX XX XX XX 'S' 'F' 'U' 'D' [小版号] [修订号]

也就是开完5个字节的发送通道,发出 CMD ,需要立即开接收通道,不然就错过字符了。

osDelay用不了,我觉得最合适 DMA 的还是同时开收发通道,再从有效信息的开始处提取数据。他这个库跟DMA天生就不太兼容。
回复

使用道具 举报

25

主题

233

回帖

308

积分

高级会员

积分
308
QQ
 楼主| 发表于 2024-12-21 16:16:33 | 显示全部楼层
还是算了,他这个没有库的可控内存区的概念,到处都是局部 buffer ,用起来比较危险,针对收发区域 MPU 属性也不好配置,感觉后期可能会给别人带来麻烦,还是用自己的吧。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117546
QQ
发表于 2024-12-21 16:34:04 | 显示全部楼层
yono 发表于 2024-12-21 16:06
DMA这里的话,死等就得占着CPU不放,不然会丢数据

例如读 SFUD 头部这里,与 flash 的整个通信流是

不影响,全双工打开,这个进入的RxTxCplt回调,你等待这个发送和接受都完成的回调即可,期间可以执行osDelay
回复

使用道具 举报

25

主题

233

回帖

308

积分

高级会员

积分
308
QQ
 楼主| 发表于 2024-12-21 16:40:32 | 显示全部楼层
eric2013 发表于 2024-12-21 16:34
不影响,这个进入的RxTxCplt回调,你等待这个发送和接受都完成的回调即可

开 收发双向通道当然可以,但是 SFUD 这个库,对于收发 port 是这样调用的。有四个重要传参

发送 buffer 头指针、发送 buffer 长度、接收 buffer 头指针、接收 buffer 长度。

针对上述的那个情况,他内部函数调用的传参是
1.[5A 00 00 00 FF] 长度为5的临时buffer
2.5
3.[] 长度为8的临时buffer
4.8

实际上进行了总长13的通信
回复

使用道具 举报

25

主题

233

回帖

308

积分

高级会员

积分
308
QQ
 楼主| 发表于 2024-12-21 16:57:27 | 显示全部楼层
eric2013 发表于 2024-12-21 16:34
不影响,全双工打开,这个进入的RxTxCplt回调,你等待这个发送和接受都完成的回调即可,期间可以执行osDe ...

这个库的局部 buffer 太多了。
之前弄 modbus 库也是看到这个家伙做的 FreeModbus_Slave-Master-RTT-STM32 ,移着移着觉得他写的太恶心,勉励自己弄了一个。
这次恐怕又要勉励自己弄一个 sfudX。
回复

使用道具 举报

5

主题

162

回帖

177

积分

初级会员

积分
177
发表于 2024-12-21 22:45:45 | 显示全部楼层
不是有个api边发边收吗?HAL_SPI_TransmitReceive_DMA
回复

使用道具 举报

25

主题

233

回帖

308

积分

高级会员

积分
308
QQ
 楼主| 发表于 2024-12-22 15:09:08 | 显示全部楼层
2859932063 发表于 2024-12-21 22:45
不是有个api边发边收吗?HAL_SPI_TransmitReceive_DMA

这个API得发送和接收 buffer 足够大,这个库用临时 buffer 的,这个API很危险
回复

使用道具 举报

5

主题

162

回帖

177

积分

初级会员

积分
177
发表于 2024-12-22 18:06:05 | 显示全部楼层
yono 发表于 2024-12-22 15:09
这个API得发送和接收 buffer 足够大,这个库用临时 buffer 的,这个API很危险

使用可变长数组动态申请内存
回复

使用道具 举报

4

主题

81

回帖

93

积分

初级会员

积分
93
发表于 2024-12-23 10:30:52 | 显示全部楼层
这应该不是hal的限制,是spi的限制吧,毕竟是spi没办法收发分开。hal只是硬件抽象层,也不应该改变外设本来的特性。假设允许你这样操作,你的buffer内存hal库要怎么存放呢?
而且你还是在操作flash,这种情况就好像你说的,给个信号量或者event group出去,等callback的时候唤醒等待的task继续执行,把异步变同步
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-14 03:36 , Processed in 0.054662 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表