之前写过一篇I2S+DMA的使用(I2S通信工程建立 - kkk123456** - 博客园 (cnblogs.com))
这次又用到了I2S+DMA,但是和上次不同,这次DMA使用Normal模式,我想等I2S接收完成之后再使用DMA把数据从外设搬到内存中
配置修改如下:
生成工程后,定义了一个标志位 iis_flag,在I2S接收回调函数里将iis_flag置1。在主循环中判断当iis_flag为1时,启动dma接收。主循环代码如下:
while (1) { if(iis_flag == 1) { HAL_I2S_Receive_DMA(&hi2s2,iis_rec,64); iis_flag = 0; } }
I2S接收中断回调函数代码如下:
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) { iis_flag =1; }
进入debug,在“ iis_flag=0; ”处打断点, 发现没有程序没有执行到这里。觉得很奇怪,以为时中断没进去。于是把断点打到中断回调函数里。发现中断进去了,但是没有执行主循环的函数。
打开寄存器查看,中断标志位 RXNEIE,发现此位一直都是1,猜想可能是卡在中断没出去。
于是在I2S中断回调函数里,手动将接收中断标志位清零。
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) { SPI2->CR2 &= ~(1 << 6); iis_flag =1; }
然后问题就解决了。
参考手册知识补充:
I2S和SPI共用中断,所以有些寄存器也是共用的。
首先我们看到章节28.4.9中有描述I2S中断相关的事件及标志位和使能控制bit
可以看到RXNEIE是使能接收中断位。于是我们会在章节28.5.2中看到SPI control register 2中有RXNEIE的描述:
大致意思就是,RXNE flag置1的时候,此时RXNEIE会被置1,然后产生一个中断
更详细的解释在章节25.4.4 I2S master mode中: