打印
[AT32F403/403A]

SPI全双工DMA方式读取时,前面总会多读几个字节

[复制链接]
1880|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dopod577w|  楼主 | 2022-6-1 10:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
例如,用全双工DMA模式读SPI Flash芯片的数据,首先要发送2个命令字节,然后再读回3个数据字节。
但是,你必须读5个字节才行,前面2个字节是无用数据,因为发送前面2个字节时,SPI的接收电路也在工作。

处理的方法也比较简单,去掉前面2个字节,只保留后面3个字节就行了。
但是这样很不通用,每次读取时,前面的命令字节数是不定长的,后面的接收缓冲区也可能指向不同的数组,总不能为每个接收数组预留几个空字节吧。

但是ST的HAL库函数HAL_SPI_Receive_DMA就没有这个烦恼,直接指定接收缓冲区的地址就行,用不着手工去掉前面的无用字节

不知道AT32里面该怎么实现?

我的代码大概如此:
void spi_read(uint8_t *addr, uint32_t len)
{
//1. 配置RX DMA
        //禁用DMA通道,否则不能改参数
        dma_channel_enable(DMA2_CHANNEL1, FALSE);

        //改参数后打开DMA
        DMA2_CHANNEL1->dtcnt = len;
        DMA2_CHANNEL1->maddr = (uint32_t)addr;
        dma_channel_enable(DMA2_CHANNEL1, TRUE);

//2. 配置TX DMA,输出dummy数据,否则没有CLK
        //禁用DMA通道,否则不能改参数
        dma_channel_enable(DMA2_CHANNEL2, FALSE);

        //改参数后打开DMA
        DMA2_CHANNEL2->dtcnt = len;
        DMA2_CHANNEL2->maddr = (uint32_t)addr;
        dma_channel_enable(DMA2_CHANNEL2, TRUE);

//3. 等到传输完成标志=1
        while (dma_flag_get(DMA2_FDT1_FLAG)==RESET){};
}
上面只是SPI DMA读取的代码。该代码执行前,先用spi_send发送N个字节,器件会返回M个字节,而spi_read的len必须等于N+M。
我希望,器件返回M个字节,那么spi_read的len就设置为M,不要再费劲从*addr指向的缓冲区里抠掉N个字节。

使用特权

评论回复
沙发
carpsnow| | 2022-6-1 20:58 | 只看该作者
每次都这样?

使用特权

评论回复
板凳
dopod577w|  楼主 | 2022-6-2 21:10 | 只看该作者

是的,原理上就是这样
以前用ST的,最开始HAL库也是这样
后来不知哪个版本HAL库,就不用自己抠字节了

前两天有事没继续研究,我这两天试试

使用特权

评论回复
地板
carpsnow| | 2022-6-2 22:08 | 只看该作者
半双工试试

使用特权

评论回复
5
hoop| | 2022-6-5 13:24 | 只看该作者
这只是应用层逻辑。
AT demo的做法是命令通过轮训的方式发送,随后数据收发的时候切换使用DMA。

使用特权

评论回复
6
CosOxygen| | 2022-7-10 11:32 | 只看该作者
楼主你好,你的问题现在解决了吗?
我这几天也遇到了这样的问题,我给dma 传输使能之后delay 5us好像就好了(不这样做dma就无法正确搬运数据到内存),读一个字节,
如果读多个字节读出来的数据不是0x00,就是0xFF很奇怪,偶尔出现其他数据

使用特权

评论回复
7
CosOxygen| | 2022-7-10 11:36 | 只看该作者
CosOxygen 发表于 2022-7-10 11:32
楼主你好,你的问题现在解决了吗?
我这几天也遇到了这样的问题,我给dma 传输使能之后delay 5us好像就好了 ...

补充一下,发送没有发现问题

使用特权

评论回复
评论
CosOxygen 2022-7-27 23:10 回复TA
每次发送接收复位dma寄存器重新配置就好了。 
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

25

帖子

2

粉丝