CH32V103学习笔记之七——SPI DMA与NRF24L01+(SI24R1)2.4GHz无线模块通讯
1、前言
近段时间一直在学习写一个简单的遥控程序,为制作一个多通道的遥控小车做些准备。了解到NRF24L01+(国产替代型号是SI24R1)这款使用SPI协议通讯的2.4GHz无线通讯模块。
经过一段时间学习之后,发现该模块ACK模式可以带数据发回发送端。使用该功能在程序上就不用切换通讯模式,主发送端一直使用发送模式,发送控制信号之后,接收ACK应答信号的同时接收主接收端发回的数据,实现双向通讯。在更为深入的学习和验证之后,发现写入ACK数据的时间只有在发送端切换接收模式至发送模式发回ACK之前的130微秒(状态切换时间,固定值),如果不能在这段时间内写入数据至NRF24L01+ TX FIFO缓冲区,那么ACK就不会带回有效数据至主发送端。这就需要寻找一种办法来提高写数据至NRF24L01+ 数据缓冲区的效率。早前在学习ADC的时候了解过DMA的使用,方便易用,而SPI作为一种高速全双工的通信总线,使用DMA应该更能体现出SPI高速性能。在搜索了一番之后,发现关于SPI DMA与NRF24L01+(SI24R1)2.4GHz无线模块通讯的案例没有公开的程序可以参考,那就只能自己一点点摸索了。花了些时间,逐渐解决了遇到的问题,实现了使用SPI DMA与NRF24L01+模块通讯。
2、解决思路
首先需要了解的是,NRF24L01+模块作为从机,读出、写入数据的通信同步时间信号都需要主机主动发起。那么就可以明确,写入数据至NRF24L01+发送缓冲区需要使用 SPI TX的DMA通道,至于MISO发回的数据可以忽视。读出NRF24L01+接收缓冲区中的数据需要由主机发起通讯同步时钟信号,那么就可以使用SPI TX DMA通道向NRF24L01+接收缓冲区写入一串可以是无意义的数据产生同步时钟信号,与此同时,使用SPI RX DMA通道接收MISO的数据(ACK带回的有效数据)。
3、配置方法
本文以SPI2的配置方法为例展开说明,因为SPI1接口与同时需要使用的ADC通道有冲突,所以使用的SPI2。
3.1、根据DMA 各通道外设映射表,SPI2 RX、TX DMA通道分别位于通道4和通道5。因为不需要执行循环DAM传输,模式均为单次执行,需要接发数据的时候启动DMA传输即可。

初始化SPI2 RX和TX DMA通道
3.2、SPI DMA通讯说明



3.3、使用DMA SPI通道将数据写入NRF24L01 TX FIFO缓冲区配置方式
配置存储器地址加1是因为发送数据缓冲数组TxData第二个元素是写数据至TX FIFO的寄存器操作指令(第一个元素是读RX FIFO的寄存器操作指令,在读出NRF24L01 RX FIFO缓冲区中数据时使用)。DMA传输数量加1是因为在传输有效数据个数之外需要额外加上一次寄存器操作指令。等待TXE=1和BSY=0是在参考手册中提到的重点说明,按照说明配置即可。如果不加入读取数据寄存器的操作,SPI DMA接收到的数据会发生错位(软件调试结合逻辑分析仪调试时发现)。片选和取消片选是GPIO输出高低电平的操作,这里以宏定义代替。
使用SPI DMA向NRF24L01 TX FIFO缓冲区写入1字节寄存器操作指令和25字节数据时序图(SCK = 4.5MHz,完成共需要约47us)

3.4、使用DMA SPI通道读出NRF24L01 RX FIFO缓冲区中的数据
首先以单字节SPI通讯方式读取RX FIFO缓冲区中ACK数据的个数,然后再次片选NRF24L01+模块发起SPI通讯(调试时发现必须这么操作,否则无法接收到数据)。DMA传输数量各加1是因为,在传输有效数据个数之外需要额外加上一次操作指令。DMA接收存储器地址因为在初始化时已经配置过,且在程序运行的过程中未再次更改,不需要再次配置。最后读取数据寄存器的值至接收缓冲区数组(实际接收到的最后一个有效数据),不做此操作会少接收一字节有效数据(实际调试发现的,至于为何这样因为没有更多资料可以进一步学习,就不展开讨论)。
使用DMA SPI通道读出NRF24L01 RX FIFO缓冲区中的数据时序图(1+7字节)

4、后记
使用SPI DMA与NRF24L01+ 2.4GHz无线模块通讯的方法到这里就介绍完了。整个学习和调试过程前后摸索了十多天,学的十分艰难,最后还是一点点试错调试出来了。
