之前写过一篇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中: