打印
[STM32H7]

H743 DMA传输错误中断的问题

[复制链接]
1889|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
阿尔法99|  楼主 | 2020-7-10 15:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
调试H743 DMA传输的时候,每次中断都是因为传输错误标志(TEIF)置位引起的。
我的目的是从外部FIFO(片选FMC_NE2,地址0X64000000),把16000个半字(16位)搬移到内部RAM(起始地址0X24001000)。
程序如下:
/**
   * Enable DMA controller clock
   * Configure DMA for memory to memory transfers
   *   hdma_memtomem_dma1_stream0
   */
static void MX_DMA_Init(void)
{
   // DMA controller clock enable
   __HAL_RCC_DMA1_CLK_ENABLE();
   // Configure DMA request hdma_memtomem_dma1_stream0 on DMA1_Stream0
   hdma_memtomem_dma1_stream0.Instance = DMA1_Stream0;
   hdma_memtomem_dma1_stream0.Init.Request = DMA_REQUEST_MEM2MEM;         //内存到内存
  hdma_memtomem_dma1_stream0.Init.Direction = DMA_MEMORY_TO_MEMORY;        //内存到内存
  hdma_memtomem_dma1_stream0.Init.PeriphInc = DMA_PINC_DISABLE;          //外设地址不变
  hdma_memtomem_dma1_stream0.Init.MemInc = DMA_MINC_ENABLE;            //内存地址自动增加
  hdma_memtomem_dma1_stream0.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; //半字
  hdma_memtomem_dma1_stream0.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;   //半字
  hdma_memtomem_dma1_stream0.Init.Mode = DMA_NORMAL;               //普通DMA传输
  hdma_memtomem_dma1_stream0.Init.Priority = DMA_PRIORITY_HIGH;          //优先级高
  hdma_memtomem_dma1_stream0.Init.FIFOMode = DMA_FIFOMODE_ENABLE;         //FIFO使能
  hdma_memtomem_dma1_stream0.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
   hdma_memtomem_dma1_stream0.Init.MemBurst = DMA_MBURST_SINGLE;          //单次突发传输
  hdma_memtomem_dma1_stream0.Init.PeriphBurst = DMA_PBURST_SINGLE;        //单次突发传输
  if (HAL_DMA_Init(&hdma_memtomem_dma1_stream0) != HAL_OK)
   {
     Error_Handler( );
   }
   // DMA interrupt init
   // DMA1_Stream0_IRQn interrupt configuration
   HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
   HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
}

//FIFO中断 外部中断1 PB1
void EXTI1_IRQHandler(void)
{
   /* USER CODE BEGIN EXTI1_IRQn 0 */
   /* USER CODE END EXTI1_IRQn 0 */
DisADsample();  //停止AD数据往FIFO里写
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
   /* USER CODE BEGIN EXTI1_IRQn 1 */
HAL_DMA_Start_IT(&hdma_memtomem_dma1_stream0, 0x64000000, 0x24001000, 16000);//启动传输,源地址为0x64000000,
         
   /* USER CODE END EXTI1_IRQn 1 */
}
// dma传输完成中断处理
void DMA1_Stream0_IRQHandler(void)
{
      HAL_DMA_IRQHandler(&hdma_memtomem_dma1_stream0);
      /* USER CODE BEGIN DMA1_Stream0_IRQn 1 */
     if(__HAL_DMA_GET_FLAG(&hdma_memtomem_dma1_stream0,DMA_FLAG_TCIF0_4))//判断是否为DMA传输完成中断
    {
   
            __HAL_DMA_CLEAR_FLAG(&hdma_memtomem_dma1_stream0,DMA_FLAG_TCIF0_4);//清除中断标志位
          HAL_DMA_Abort_IT(&hdma_memtomem_dma1_stream0);      //传输完成以后关闭DMA
     }
}

问题描述:
1、H743可以采集到FIFO输出半满中断信号,并可以触发EXTI1中断。
2、EXTI1中断处理程序EXTI1_IRQHandler里启动DMA传输,传输完成触发中断。
3、DMA中断每次由TEIF0触发。

请各位老师帮忙解决一下这个问题!谢谢!

使用特权

评论回复
沙发
香水城| | 2020-7-10 16:04 | 只看该作者
你现在好像是ADC结果通过DMA传输进来。
采样外设到内存模式比较合适,通过触发事件来控制DMA传输。

比方你换成用定时器事件来触发DMA读取看看。

使用特权

评论回复
板凳
阿尔法99|  楼主 | 2020-7-10 16:42 | 只看该作者
香水城 发表于 2020-7-10 16:04
你现在好像是ADC结果通过DMA传输进来。
采样外设到内存模式比较合适,通过触发事件来控制DMA传输。

多谢城主答复。
外部中断比较适合我的应用。
我试一下外设到内存模式看看。

使用特权

评论回复
地板
阿尔法99|  楼主 | 2020-7-10 17:00 | 只看该作者
香水城 发表于 2020-7-10 16:53

根据你的应用,怎么合适怎么来。

我改成外设到内存模式,产生中断后,所对应的中断标志DMA1->LIFCR所有位都是0。初始化,我采用寄存器方式,简单明了。麻烦城主看一下哪地方出错了?
//DMAx的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//chx:DMA通道选择,范围:1~115(详见<<STM32H7xx参考手册>>16.3.2节,Table 116)
//par:外设地址
//mar:存储器地址
//ndtr:数据传输量  
void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,uint8_t chx,uint32_t par,uint32_t mar,uint16_t ndtr)
{
        DMA_TypeDef *DMAx;
        DMAMUX_Channel_TypeDef *DMAMUXx;
        uint8_t streamx;
        if((uint32_t)DMA_Streamx>(uint32_t)DMA2)//得到当前stream是属于DMA2还是DMA1
        {
                DMAx=DMA2;
                RCC->AHB1ENR|=1<<1;                //DMA2时钟使能  
        }else
        {
                DMAx=DMA1;
                RCC->AHB1ENR|=1<<0;                //DMA1时钟使能
        }
        while(DMA_Streamx->CR&0X01);//等待DMA可配置
        streamx=(((uint32_t)DMA_Streamx-(uint32_t)DMAx)-0X10)/0X18;                        //得到stream通道号
        if(streamx>=6)DMAx->HIFCR|=0X3D<<(6*(streamx-6)+16);                //清空之前该stream上的所有中断标志
        else if(streamx>=4)DMAx->HIFCR|=0X3D<<6*(streamx-4);                //清空之前该stream上的所有中断标志
        else if(streamx>=2)DMAx->LIFCR|=0X3D<<(6*(streamx-2)+16);        //清空之前该stream上的所有中断标志
        else DMAx->LIFCR|=0X3D<<6*streamx;                                                        //清空之前该stream上的所有中断标志

        if((uint32_t)DMA_Streamx>(uint32_t)DMA2)streamx+=8;                                        //如果是DMA2,通道编号+8
        DMAMUXx=(DMAMUX_Channel_TypeDef *)(DMAMUX1_BASE+streamx*4);        //得到对应的DMAMUX通道控制地址
        DMAMUXx->CCR=chx&0XFF;                //通道选择
       
        DMA_Streamx->PAR=par;                        //DMA外设地址
        DMA_Streamx->M0AR=mar;                //DMA 存储器0地址
        DMA_Streamx->NDTR=ndtr;                //DMA 存储器0地址
        DMA_Streamx->CR=0;                                //先全部复位CR寄存器值
       
        DMA_Streamx->CR|=0<<6;
        DMA_Streamx->CR|=0<<7;                //外设到存储器模式               
        DMA_Streamx->CR|=0<<8;                //非循环模式(即使用普通模式)
        DMA_Streamx->CR|=0<<9;                //外设非增量模式
        DMA_Streamx->CR|=1<<10;                //存储器增量模式
        DMA_Streamx->CR|=1<<11;                //外设数据长度:16位
        DMA_Streamx->CR|=1<<13;                //存储器数据长度:16位
        DMA_Streamx->CR|=1<<16;                //中等优先级
        DMA_Streamx->CR|=0<<21;                //外设突发单次传输
        DMA_Streamx->CR|=0<<23;                //存储器突发单次传输
       
        DMA_Streamx->CR|=1<<4;                //传输完成产生中断
        DMA_Streamx->CR|=1<<3;                //传输完成一半产生中断
        DMA_Streamx->CR|=1<<2;                //传输错误产生中断
        DMA_Streamx->CR|=1<<1;                //直接模式错误产生中断  
       
        //DMA_Streamx->FCR=0X21;        //FIFO控制寄存器
         
   // DMA interrupt init
  // DMA1_Stream0_IRQn interrupt configuration
  HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
}

//开启一次DMA传输
//DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//ndtr:数据传输量  
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,uint16_t ndtr)
{

        DMA_Streamx->CR&=~(1<<0);         //关闭DMA传输
        while(DMA_Streamx->CR&0X1);        //确保DMA可以被设置  
        DMA_Streamx->NDTR=ndtr;                //DMA 存储器0地址
        DMA_Streamx->CR|=1<<0;                //开启DMA传输
}          

//初始化调用
MYDMA_Config(DMA1_Stream0,0,(uint32_t)0x64000000,(uint32_t) 0x24001000,16000);//DMA1,STEAM0,CH0,外设为FIFO,存储器为SendBuff,长度为:16000.

//外部中断里启动DMA
MYDMA_Enable(DMA1_Stream0,16000);//开始一次DMA传输!       
               

使用特权

评论回复
5
阿尔法99|  楼主 | 2020-7-10 17:08 | 只看该作者
阿尔法99 发表于 2020-7-10 17:00
我改成外设到内存模式,产生中断后,所对应的中断标志DMA1->LIFCR所有位都是0。初始化,我采用寄存器方式 ...

现在是外部中断两次才能产生一次DMA中断。中断标志DMA1->LIFCR所有位都是0。肯定哪地方出错了,百思不得其解。

使用特权

评论回复
评论
阿尔法99 2020-7-10 17:22 回复TA
标志位看错了。不应该看DMA1->LIFCR。而是应该看DMA1->LISR。DMA1->LISR还是等于0x08。说明还是传输错误引起的中断。 
6
香水城| | 2020-7-10 17:28 | 只看该作者
本帖最后由 香水城 于 2020-7-10 17:43 编辑

你的初始化配置是基于STM32CubeMx吗?还有,你外部中断触发DMA传输?什么意思。

我说的触发传输是指DMA已经被使能后被触发事件启动传输, 你确定外部中断可以触发DMA?

使用特权

评论回复
7
阿尔法99|  楼主 | 2020-7-10 17:35 | 只看该作者
香水城老师建议DMA模式改为外设到内存是对的。现在DMA1->LISR等于0X20。说明传输一半和传输完成都置位了中断标志。但是需要响应两次外部中断,即启动两次DMA,才能产生一次DMA中断。香水城老师,您看这次的问题出在哪?

使用特权

评论回复
8
阿尔法99|  楼主 | 2020-7-10 17:45 | 只看该作者
香水城 发表于 2020-7-10 17:28
你的初始化配置是基于STM32CubeMx吗?还有,你外部中断触发DMA传输?什么意思。

我说的触发传输是指DMA已 ...

我是根据DMA的寄存器初始化的。外部中断不能触发DMA。我是在外部中断里加了一条启动DMA传输的命令。

使用特权

评论回复
9
香水城| | 2020-7-10 17:46 | 只看该作者
阿尔法99 发表于 2020-7-10 17:35
香水城老师建议DMA模式改为外设到内存是对的。现在DMA1->LISR等于0X20。说明传输一半和传输完成都置位了中 ...

我总觉得有点乱。没明白 你DMA传输怎么老跟外部中断弄到一起了,半完成中断、完成中断都是DMA的中断。

使用特权

评论回复
10
阿尔法99|  楼主 | 2020-7-10 17:52 | 只看该作者
香水城 发表于 2020-7-10 17:46
我总觉得有点乱。没明白 你DMA传输怎么老跟外部中断弄到一起了,半完成中断、完成中断都是DMA的中断。 ...

AD采样的数据暂存在外部FIFO。外部FIFO半满的时候,向CPU发出外部中断信号,提醒CPU把FIFO的数据读走。

使用特权

评论回复
11
阿尔法99|  楼主 | 2020-7-10 17:58 | 只看该作者
HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *hdma)
{
  BDMA_Base_Registers *regs_bdma;

  /* Check the DMA peripheral handle */
  if(hdma == NULL)
  {
    return HAL_ERROR;          //DMA关闭的时候,程序运行到这里。这是外部中断不能与DMA直接关联的缘故吧?
  }

  if(hdma->State != HAL_DMA_STATE_BUSY)
  {
    hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
    return HAL_ERROR;
  }
  else
  {
    if(IS_DMA_STREAM_INSTANCE(hdma->Instance) != 0U) /* DMA1 or DMA2 instance */
    {
      /* Set Abort State  */
      hdma->State = HAL_DMA_STATE_ABORT;

      /* Disable the stream */
      __HAL_DMA_DISABLE(hdma);
    }
    else /* BDMA channel */
    {

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

21

主题

219

帖子

1

粉丝