收发两个DMA通道的配置
主程序中收发控制程序如下:
文章插图
文章插图
1 SPIx_Init();//SPI初始化 2 DMA_Config(256);//配置DMA对应的两个通道,数据深度设为256 3 SPI_I2S_DMACmd(SPI1 , SPI_I2S_DMAReq_Rx , ENABLE); 4 SPI_I2S_DMACmd(SPI1 , SPI_I2S_DMAReq_Tx , ENABLE); 5 while(1) 6 { 7DMA_SetCurrDataCounter(DMA1_Channel2,256);//必须在每次启动DMA之前设置 8DMA_SetCurrDataCounter(DMA1_Channel3,256);//必须在每次启动DMA之前设置 9DMA_Cmd(DMA1_Channel2, ENABLE);//使能DMA所指示的通道10DMA_Cmd(DMA1_Channel3, ENABLE);//使能DMA所指示的通道11while(1)12{13if(DMA_GetFlagStatus(DMA1_FLAG_TC2) != RESET)//判断通道2传输完成14{15DMA_ClearFlag(DMA1_FLAG_TC2);//清除通道2传输完成标志16break;17}18}19DMA_Cmd(DMA1_Channel2, DISABLE);//禁止DMA20DMA_Cmd(DMA1_Channel3, DISABLE);//禁止DMA21delay_ms(1);22 }SPI主机DMA使用流程
这里我没有使用DMA中断 , 为的是验证代码的简单易懂;在实际使用时,建议读者使用中断以提高数据读写效率 。另外,代码中值得注意的地方有:
1、 使用DMA传输之前,必须使能SPI发送和接收触发DAM传输请求,官方固件库中的函数分别为:SPI_I2S_DMACmd(SPI1 , SPI_I2S_DMAReq_Rx , ENABLE);和SPI_I2S_DMACmd(SPI1 , SPI_I2S_DMAReq_Tx , ENABLE);
2、 每轮DMA传输完成后,需在次启动一轮DMA传输之前,需要重新设置传输数据计数器:DMA_SetCurrDataCounter(DMA1_Channel2,256);和DMA_SetCurrDataCounter(DMA1_Channel3,256);
另外 , 我在使用上述方法的时候,忽然发现一个致命的问题:如果使用DMA控制STM32作为SPI主机输出数据,那么谁来产生片选信号CS呢?后来尝试过将NSS(PA4——SPI1或PB12——SPI2)管脚配置给SPI口 , 并改由硬件来控制该管脚: SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;结果发现均不奏效,也就是说:在SPI主模式下使用DMA发送,无法产生有效的片选CS信号!这无疑是致命的缺陷!——也许是我的理解不到位,请各位知道怎么解决这个问题的大神一定要高速我一下 。(当然这一缺陷,对于无需在单次发送字节/半字之后给出片选CS信号的应用——如大容量SPI接口存储器,并不成其为问题 。)
无法在用DMA控制SPI发送时控制CS信号 , 我只好退而求其次:改由软件控制SPI发送,并同步产生CS信号 。但这样做已经失去了DMA接收SPI的意义,因为软件控制SPI发送后,通信的速度和使用查询法是一样的!
2、SPI接收使用DMA控制,发送使用软件控制
尽管我认为发送使用软件控制后,DMA在接收中带来的好处已经基本丧失 , 但在这里仍然给出主程序中收发控制程序供读者参考 。
文章插图
文章插图
1 SPIx_Init(); 2 DMA_Config(256);//配置DMA的SPI通道 , 数据深度设为256 3 SPI_I2S_DMACmd(SPI1 , SPI_I2S_DMAReq_Rx , ENABLE); 4 delay_ms(300); 5 while(1) 6 { 7while(n_interrupt != 0);//等到中断到来 8while(n_interrupt == 0);//等到中断结束 9DMA_SetCurrDataCounter(DMA1_Channel2,256);//这部必须在每次启动DMA之前设置,10DMA_Cmd(DMA1_Channel2, ENABLE);//使能DMA所指示的通道11for(k = 0 ; k < 256 ; k++)12{13CS = 0;14SPIx_ReadWrite16bit(0xaa55);//只使用了DMA接收SPI数据,但接收要由软件启动发送数据才能接收,此处只是随便发送了一个数据15CS = 1;16}17if(DMA_GetFlagStatus(DMA1_FLAG_TC2)!=RESET)//判断通道2传输完成18DMA_ClearFlag(DMA1_FLAG_TC2);//清除通道2传输完成标志19DMA_Cmd(DMA1_Channel2, DISABLE);//禁止DMA20//////////以下可以把数据传输走//////////2122}SPI主机 , 软件控制逐字发送,接收用DMA控制
可以看到,当由软件控制SPI发送后,就可以由软件产生和发送同步的片选CS了 。但这样做与收发都采用查询法的效率几乎一样了 。
特别的 , 当采用查询法直接控制SPI口的接收和发送时,硬件的读写和软件的指令总是存在较大时间空隙:向SPI数据寄存器SPI_DR写入数据到SPI实际发出数据之间存在至少200ns间隔;检测SPI状态寄存器SPI_SR中的TXE(发送缓冲区空位)时,TXE位的变化总是比实际发送完成晚至少200ns 。例如上面的代码,函数SPIx_ReadWrite16bit();通过软件控制片选CS信号和SPI硬件的方式通信,下图是它所产生的CS信号(蓝)和SCK(黄),可以发现该函数用于发送的时间只占了实际耗费时间的一半以下 , 特别是当发送字长仅为8bits时,时间利用率真的是非常感人 。
推荐阅读
- 无悔华夏横扫六合灭国的顺序是什么
- 原神愿慧梦成真活动怎么玩
- 怎么了和为什么的区别(细菌感染和病毒感染的区别)
- 怎么啦的意思(男生问你怎么了如何高情商回复)
- 干嘛和怎么了的意思有什么区别(咋的了和怎么了是一个意思吗)
- .Net WebApi 中的 FromBody FromForm FromQuery FromHeader FromRoute
- oracle中的行转列,列转行
- 怎么了是啥意思(女人回复怎么了如何高情商的回复)
- 怎么了什么意思(怎么了的意思是什么)
- 一 CPS攻击案例——基于脉冲宽度调制PWM的无人机攻击