一、外设
- GPIO
- USART
- NVIC
- DMA
严格说NVIC不属于外设,属于内核,这里只是将使用到的模块罗列出来
二、中断
共使用4个中断:
- 串口中断:
- 发送完成中断:TC
- 空闲中断:IDLE
- DMA中断:NDTR为0时产生中断
- 发送DMA对应的流中断:传输完成中断TCIF
- 接收DMA对应的流中断:传输完成中断TCIF
中断产生顺序:
发送:DMA发送的传输完成中断触发,再串口的发送完成中断TC触发
接收:DMA接收的传输完成中断是在DMA硬件对接缓存区存满才会触发,与串口的IDLE并没有明确的先后顺序,串口的IDLE在接收到一帧数据即会触发
三、开辟的主要存储空间
- DMA硬件接收双缓存:buf[0]与buf[1]
- DMA硬件发送缓存
- 接收环形缓冲区
- 发送环形缓冲区
四、发送与接收流程
发送流程:
- 准备好需要发送的数据
- 将数据拷贝到发送环形缓冲区
- 再从发送环形缓冲区拷贝到DMA硬件发送缓存
- DMA自动搬运到串口的DR寄存器
接收流程:
- DMA自动搬运,从串口的DR寄存器搬运到DMA硬件接收双缓存
- 从DMA硬件接收双缓存拷贝到接收环形缓冲区
- 读取环形缓冲区数据并处理
五、发送与接收数据具体流程
发送一帧数据流程:
- 准备好要发送的数据
- 将要发送的数据拷贝到发送环形缓冲区
- 设置DMA的数据项寄存器NDTR为要发送数据数量并将要发送的数据从发送环形缓冲区拷贝到DMA硬件发送缓存
- 使能发送
- 进入DMA传输完成中断
- 在中断中检查环形缓缓冲区中是否还有数据,如果还有数据说明在DMA转移数据过程中又有数据被放入了环形缓冲区
- 如果环形缓冲区还有数据,则再次启动DMA传输
问题:发送完数据只能保证数据被DMA转移出去,并没有检查发送完成,而且中间又有数据被放入环形缓冲区则需要再次处理,较为麻烦
后续优化:使用信号量,在串口发送完成TC的中断服务函数中释放信号量,在调用发送函数时获取信号量,这样发送未完成时则会阻塞等待直到发送完成,这样处理较为简单
接收一帧数据流程:
两种场景:
场景一:硬件接收双缓冲区任意缓冲区都未满
- 只会触发串口空闲中断IDLE
- 在中断中将接收到的一帧数据从DMA硬件缓冲区中拷贝到接收环形缓冲区
- 将接收环形缓冲区中数据取出处理
场景二:硬件接收双缓冲区任一缓冲区存满
- 先触发DMA传输完成中断
- 在中断中将已经存满的缓存最后一部分数据拷贝到接收环形缓冲区中
- 再触发串口空闲中断IDLE
- 在中断中将DMA这一新缓存中的数据继续拷贝到接收环形缓冲区中
- 将接收环形缓冲区中数据取出处理