HAL_DMA_IRQHandler()代码详细分析

2023-05-16

这里使用ADC1联动DMA1, 开启半传输中断、传输中断。debug时,dma也一直在工作,所以半传输中断、传输中断会同时生效。

1. adc1使用了DMA1_Stream0,Instance表示如下

在这里插入图片描述
在这里插入图片描述
一个DMA数据流中断标志占6个bit(在DMA_LISR)。Stream0 :hdma->StreamIndex=0,Stream1:hdma->StreamIndex=6
DMA_Base_Registers *regs_dma = (DMA_Base_Registers *)hdma->StreamBaseAddress;
tmpisr_dma = regs_dma->ISR;

tmpisr_dma表示
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
(hdma->StreamIndex & 0x1FU) 保证在0~31之间。
DMA_FLAG_TEIF0_4 ((uint32_t)0x00000008U)
在这里插入图片描述
在这里插入图片描述

2. 代码
/**
  * @brief  Handles DMA interrupt request.
  * @param  hdma: pointer to a DMA_HandleTypeDef structure that contains
  *               the configuration information for the specified DMA Stream.
  * @retval None
  */
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)
{
  uint32_t tmpisr_dma, tmpisr_bdma;
  uint32_t ccr_reg;
  __IO uint32_t count = 0U;
  uint32_t timeout = SystemCoreClock / 9600U;

  /* calculate DMA base and stream number */
  DMA_Base_Registers  *regs_dma  = (DMA_Base_Registers *)hdma->StreamBaseAddress;
  BDMA_Base_Registers *regs_bdma = (BDMA_Base_Registers *)hdma->StreamBaseAddress;

  tmpisr_dma  = regs_dma->ISR;
  tmpisr_bdma = regs_bdma->ISR;

  if(IS_DMA_STREAM_INSTANCE(hdma->Instance) != 0U)  /* DMA1 or DMA2 instance */
  {
//hdma->Instance = DMA1_Stream0 = 0x40020010
    /* Transfer Error Interrupt management ***************************************/
    if ((tmpisr_dma & (DMA_FLAG_TEIF0_4 << (hdma->StreamIndex & 0x1FU))) != 0U)	//发生了Transfer error中断
{
//tmpisr_dma = DMA_LISR寄存器
//hdma->StreamIndex = 0
//DMA_FLAG_TEIF0_4 = 	((uint32_t)0x00000008U)
//(hdma->StreamIndex & 0x1FU)  0~31之间

      if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TE) != 0U)	//数据流x的传输错误中断使能,在DMA_SxCR
      {
//DMA_IT_TE		((uint32_t)DMA_SxCR_TEIE)
 /* Disable the transfer error interrupt */
        ((DMA_Stream_TypeDef   *)hdma->Instance)->CR  &= ~(DMA_IT_TE);
//停止数据流x的error中断

        /* Clear the transfer error flag */
        regs_dma->IFCR = DMA_FLAG_TEIF0_4 << (hdma->StreamIndex & 0x1FU);
//清数据流x的error标志

        /* Update error code */
        hdma->ErrorCode |= HAL_DMA_ERROR_TE;
      }
    }
    /* FIFO Error Interrupt management ******************************************/
    if ((tmpisr_dma & (DMA_FLAG_FEIF0_4 << (hdma->StreamIndex & 0x1FU))) != 0U)	//发生了FIFI error中断
{
//DMA_FLAG_FEIF0_4 = ((uint32_t)0x00000001U)
      if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_FE) != 0U)		//数据流x的FIFO错误中断使能,在DMA_DxFCR
      {
        /* Clear the FIFO error flag */
        regs_dma->IFCR = DMA_FLAG_FEIF0_4 << (hdma->StreamIndex & 0x1FU);
//清数据流x的FIFO error标志

        /* Update error code */
        hdma->ErrorCode |= HAL_DMA_ERROR_FE;
      }
    }
    /* Direct Mode Error Interrupt management ***********************************/
if ((tmpisr_dma & (DMA_FLAG_DMEIF0_4 << (hdma->StreamIndex & 0x1FU))) != 0U)	//发生了Direct Mode Error中断
{
//DMA_FLAG_DMEIF0_4 = ((uint32_t)0x00000004U)	DMEIE
      if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_DME) != 0U)		//直接模式错误中断使能,在DMA_SxCR
      {
        /* Clear the direct mode error flag */
        regs_dma->IFCR = DMA_FLAG_DMEIF0_4 << (hdma->StreamIndex & 0x1FU);
//清数据流x的Direct error标志

        /* Update error code */
        hdma->ErrorCode |= HAL_DMA_ERROR_DME;
      }
    }
    /* Half Transfer Complete Interrupt management ******************************/
    if ((tmpisr_dma & (DMA_FLAG_HTIF0_4 << (hdma->StreamIndex & 0x1FU))) != 0U)	//发生了半传输中断
    {
      if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_HT) != 0U)		//半传输中断使能,在DMA_SxCR
      {
//DMA_IT_HT ((uint32_t)DMA_SxCR_HTIE)
/* Clear the half transfer complete flag */
        regs_dma->IFCR = DMA_FLAG_HTIF0_4 << (hdma->StreamIndex & 0x1FU);	//清半传输中断标志

        /* Multi_Buffering mode enabled */
        if(((((DMA_Stream_TypeDef   *)hdma->Instance)->CR) & (uint32_t)(DMA_SxCR_DBM)) != 0U)//双缓存开启,代码没开启
        {
          /* Current memory buffer used is Memory 0 */
          if((((DMA_Stream_TypeDef   *)hdma->Instance)->CR & DMA_SxCR_CT) == 0U)
          {
            if(hdma->XferHalfCpltCallback != NULL)
            {
              /* Half transfer callback */
              hdma->XferHalfCpltCallback(hdma);
            }
          }
          /* Current memory buffer used is Memory 1 */
          else
          {
            if(hdma->XferM1HalfCpltCallback != NULL)
            {
              /* Half transfer callback */
              hdma->XferM1HalfCpltCallback(hdma);
            }
          }
        }
        else
        {
          /* Disable the half transfer interrupt if the DMA mode is not CIRCULAR */
          if((((DMA_Stream_TypeDef   *)hdma->Instance)->CR & DMA_SxCR_CIRC) == 0U)	//循环模式,则清半传输中断
          {
            /* Disable the half transfer interrupt */
            ((DMA_Stream_TypeDef   *)hdma->Instance)->CR  &= ~(DMA_IT_HT);
          }

          if(hdma->XferHalfCpltCallback != NULL)	//回调函数不为空,则调用回调函数
          {
            /* Half transfer callback */
            hdma->XferHalfCpltCallback(hdma);		//半传输中断,循环模式下,就只调用了这行
//HAL_ADC_Start_DMA()  hadc->DMA_Handle->XferHalfCpltCallback = ADC_DMAHalfConvCplt;

          }
        }
      }
    }
    /* Transfer Complete Interrupt management ***********************************/
    if ((tmpisr_dma & (DMA_FLAG_TCIF0_4 << (hdma->StreamIndex & 0x1FU))) != 0U)	//发生了传输中断
    {
      if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TC) != 0U)	//传输中断使能,在DMA_SxCR
      {
        /* Clear the transfer complete flag */
        regs_dma->IFCR = DMA_FLAG_TCIF0_4 << (hdma->StreamIndex & 0x1FU);	//清传输中断标志

        if(HAL_DMA_STATE_ABORT == hdma->State)		//HAL_DMA_Abort_IT() hdma->State=HAL_DMA_STATE_ABORT,手动关闭DMA中断,我的代码没用到
        {
          /* Disable all the transfer interrupts */
          ((DMA_Stream_TypeDef   *)hdma->Instance)->CR  &= ~(DMA_IT_TC | DMA_IT_TE | DMA_IT_DME);	
//清传输完成、传输错误、直接模式错误中断使能标志
          ((DMA_Stream_TypeDef   *)hdma->Instance)->FCR &= ~(DMA_IT_FE);
//清FIFO错误中断使能标志

          if((hdma->XferHalfCpltCallback != NULL) || (hdma->XferM1HalfCpltCallback != NULL))
          {
            ((DMA_Stream_TypeDef   *)hdma->Instance)->CR  &= ~(DMA_IT_HT);
          }

          /* Clear all interrupt flags at correct offset within the register */
          regs_dma->IFCR = 0x3FUL << (hdma->StreamIndex & 0x1FU);

          /* Process Unlocked */
          __HAL_UNLOCK(hdma);

          /* Change the DMA state */
          hdma->State = HAL_DMA_STATE_READY;

          if(hdma->XferAbortCallback != NULL)
          {
            hdma->XferAbortCallback(hdma);
          }
          return;
        }

        if(((((DMA_Stream_TypeDef   *)hdma->Instance)->CR) & (uint32_t)(DMA_SxCR_DBM)) != 0U)		//双缓存开启,我的代码没用到
        {
          /* Current memory buffer used is Memory 0 */
          if((((DMA_Stream_TypeDef   *)hdma->Instance)->CR & DMA_SxCR_CT) == 0U)
          {
            if(hdma->XferM1CpltCallback != NULL)
            {
              /* Transfer complete Callback for memory1 */
              hdma->XferM1CpltCallback(hdma);
            }
          }
          /* Current memory buffer used is Memory 1 */
          else
          {
            if(hdma->XferCpltCallback != NULL)
            {
              /* Transfer complete Callback for memory0 */
              hdma->XferCpltCallback(hdma);
            }
          }
        }
        /* Disable the transfer complete interrupt if the DMA mode is not CIRCULAR */
        else
        {
          if((((DMA_Stream_TypeDef   *)hdma->Instance)->CR & DMA_SxCR_CIRC) == 0U)	//循环模式没开
          {
            /* Disable the transfer complete interrupt */
            ((DMA_Stream_TypeDef   *)hdma->Instance)->CR  &= ~(DMA_IT_TC);	//清传输完成中断

            /* Process Unlocked */
            __HAL_UNLOCK(hdma);

            /* Change the DMA state */
            hdma->State = HAL_DMA_STATE_READY;
          }

          if(hdma->XferCpltCallback != NULL)
          {
            /* Transfer complete callback */
            hdma->XferCpltCallback(hdma);			//传输中断,循环模式下,就只调用了这行
      		 // HAL_ADC_Start_DMA()  hadc->DMA_Handle->XferCpltCallback = ADC_DMAConvCplt;

          }
        }
      }
    }

    /* manage error case */
    if(hdma->ErrorCode != HAL_DMA_ERROR_NONE)		//有DMA错误
    {
      if((hdma->ErrorCode & HAL_DMA_ERROR_TE) != 0U)	//有DMA传输错误
      {
        hdma->State = HAL_DMA_STATE_ABORT;

        /* Disable the stream */
        __HAL_DMA_DISABLE(hdma);		//关闭DMA,关闭一个DMA数据流

        do
        {
          if (++count > timeout)
          {
            break;
          }
        }
        while((((DMA_Stream_TypeDef   *)hdma->Instance)->CR & DMA_SxCR_EN) != 0U);//等待关闭

        /* Process Unlocked */
        __HAL_UNLOCK(hdma);		//hdma开锁

        if((((DMA_Stream_TypeDef   *)hdma->Instance)->CR & DMA_SxCR_EN) != 0U)	//DMA数据流没关闭,出错
        {
          /* Change the DMA state to error if DMA disable fails */
          hdma->State = HAL_DMA_STATE_ERROR;
        }
        else
        {
          /* Change the DMA state to Ready if DMA disable success */
          hdma->State = HAL_DMA_STATE_READY;
        }
      }

      if(hdma->XferErrorCallback != NULL)
      {
        /* Transfer error callback */
        hdma->XferErrorCallback(hdma);
      }
    }
  }
  else if(IS_BDMA_CHANNEL_INSTANCE(hdma->Instance) != 0U)  /* BDMA instance(s) */
  {
    ccr_reg = (((BDMA_Channel_TypeDef   *)hdma->Instance)->CCR);

    /* Half Transfer Complete Interrupt management ******************************/
    if (((tmpisr_bdma & (BDMA_FLAG_HT0 << (hdma->StreamIndex & 0x1FU))) != 0U) && ((ccr_reg & BDMA_CCR_HTIE) != 0U))
    {
      /* Clear the half transfer complete flag */
      regs_bdma->IFCR = (BDMA_ISR_HTIF0 << (hdma->StreamIndex & 0x1FU));

      /* Disable the transfer complete interrupt if the DMA mode is Double Buffering */
      if((ccr_reg & BDMA_CCR_DBM) != 0U)
      {
        /* Current memory buffer used is Memory 0 */
        if((ccr_reg & BDMA_CCR_CT) == 0U)
        {
          if(hdma->XferM1HalfCpltCallback != NULL)
          {
            /* Half transfer Callback for Memory 1 */
            hdma->XferM1HalfCpltCallback(hdma);
          }
        }
        /* Current memory buffer used is Memory 1 */
        else
        {
          if(hdma->XferHalfCpltCallback != NULL)
          {
            /* Half transfer Callback for Memory 0 */
            hdma->XferHalfCpltCallback(hdma);
          }
        }
      }
      else
      {
        if((ccr_reg & BDMA_CCR_CIRC) == 0U)
        {
          /* Disable the half transfer interrupt */
          __HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT);
        }

        /* DMA peripheral state is not updated in Half Transfer */
        /* but in Transfer Complete case */

       if(hdma->XferHalfCpltCallback != NULL)
        {
          /* Half transfer callback */
          hdma->XferHalfCpltCallback(hdma);
        }
      }
    }

    /* Transfer Complete Interrupt management ***********************************/
    else if (((tmpisr_bdma & (BDMA_FLAG_TC0 << (hdma->StreamIndex & 0x1FU))) != 0U) && ((ccr_reg & BDMA_CCR_TCIE) != 0U))
    {
      /* Clear the transfer complete flag */
      regs_bdma->IFCR = (BDMA_ISR_TCIF0) << (hdma->StreamIndex & 0x1FU);

      /* Disable the transfer complete interrupt if the DMA mode is Double Buffering */
      if((ccr_reg & BDMA_CCR_DBM) != 0U)
      {
        /* Current memory buffer used is Memory 0 */
        if((ccr_reg & BDMA_CCR_CT) == 0U)
        {
          if(hdma->XferM1CpltCallback != NULL)
          {
            /* Transfer complete Callback for Memory 1 */
            hdma->XferM1CpltCallback(hdma);
          }
        }
        /* Current memory buffer used is Memory 1 */
        else
        {
          if(hdma->XferCpltCallback != NULL)
          {
            /* Transfer complete Callback for Memory 0 */
            hdma->XferCpltCallback(hdma);
          }
        }
      }
      else
      {
        if((ccr_reg & BDMA_CCR_CIRC) == 0U)
        {
          /* Disable the transfer complete and error interrupt, if the DMA mode is not CIRCULAR */
          __HAL_DMA_DISABLE_IT(hdma, DMA_IT_TE | DMA_IT_TC);

          /* Process Unlocked */
          __HAL_UNLOCK(hdma);

          /* Change the DMA state */
          hdma->State = HAL_DMA_STATE_READY;
        }

        if(hdma->XferCpltCallback != NULL)
        {
          /* Transfer complete callback */
          hdma->XferCpltCallback(hdma);
        }
      }
    }
    /* Transfer Error Interrupt management **************************************/
    else if (((tmpisr_bdma & (BDMA_FLAG_TE0 << (hdma->StreamIndex & 0x1FU))) != 0U) && ((ccr_reg & BDMA_CCR_TEIE) != 0U))
    {
      /* When a DMA transfer error occurs */
      /* A hardware clear of its EN bits is performed */
      /* Disable ALL DMA IT */
      __HAL_DMA_DISABLE_IT(hdma, (DMA_IT_TC | DMA_IT_HT | DMA_IT_TE));

      /* Clear all flags */
      regs_bdma->IFCR = (BDMA_ISR_GIF0) << (hdma->StreamIndex & 0x1FU);

      /* Update error code */
      hdma->ErrorCode = HAL_DMA_ERROR_TE;

      /* Process Unlocked */
      __HAL_UNLOCK(hdma);

      /* Change the DMA state */
      hdma->State = HAL_DMA_STATE_READY;

      if (hdma->XferErrorCallback != NULL)
      {
        /* Transfer error callback */
        hdma->XferErrorCallback(hdma);
      }
    }
    else
    {
      /* Nothing To Do */
    }
  }
  else
  {
    /* Nothing To Do */
  }
}

在这里插入图片描述

/**
  * @brief  DMA transfer complete callback.
  * @param hdma pointer to DMA handle.
  * @retval None
  */
void ADC_DMAConvCplt(DMA_HandleTypeDef *hdma)
{
  /* Retrieve ADC handle corresponding to current DMA handle */
  ADC_HandleTypeDef *hadc = (ADC_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

  /* Update state machine on conversion status if not in error state */
  if ((hadc->State & (HAL_ADC_STATE_ERROR_INTERNAL | HAL_ADC_STATE_ERROR_DMA)) == 0UL)
  {
    /* Set ADC state */
    SET_BIT(hadc->State, HAL_ADC_STATE_REG_EOC);

    /* Determine whether any further conversion upcoming on group regular     */
    /* by external trigger, continuous mode or scan sequence on going         */
    /* to disable interruption.                                               */
    /* Is it the end of the regular sequence ? */
    if ((hadc->Instance->ISR & ADC_FLAG_EOS) != 0UL)	//系列转换完成
    {
      /* Are conversions software-triggered ? */
      if (LL_ADC_REG_IsTriggerSourceSWStart(hadc->Instance) != 0UL)		//软件触发?
      {
        /* Is CONT bit set ? */
        if (READ_BIT(hadc->Instance->CFGR, ADC_CFGR_CONT) == 0UL)
        {
          /* CONT bit is not set, no more conversions expected */
          CLEAR_BIT(hadc->State, HAL_ADC_STATE_REG_BUSY);
          if ((hadc->State & HAL_ADC_STATE_INJ_BUSY) == 0UL)
          {
            SET_BIT(hadc->State, HAL_ADC_STATE_READY);
          }
        }
      }
    }
    else
    {
      /* DMA End of Transfer interrupt was triggered but conversions sequence
         is not over. If DMACFG is set to 0, conversions are stopped. */
      if (READ_BIT(hadc->Instance->CFGR, ADC_CFGR_DMNGT) == 0UL)		//常规数据仅存储再DR中
      {
//DMNGT 数据管理配置
        /* DMACFG bit is not set, conversions are stopped. */
        CLEAR_BIT(hadc->State, HAL_ADC_STATE_REG_BUSY);
        if ((hadc->State & HAL_ADC_STATE_INJ_BUSY) == 0UL)
        {
          SET_BIT(hadc->State, HAL_ADC_STATE_READY);
        }
      }
    }

    /* Conversion complete callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
    hadc->ConvCpltCallback(hadc);
#else
    HAL_ADC_ConvCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
  }
  else /* DMA and-or internal error occurred */
  {
    if ((hadc->State & HAL_ADC_STATE_ERROR_INTERNAL) != 0UL)
    {
      /* Call HAL ADC Error Callback function */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
      hadc->ErrorCallback(hadc);
#else
      HAL_ADC_ErrorCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
    }
    else
    {
      /* Call ADC DMA error callback */
      hadc->DMA_Handle->XferErrorCallback(hdma);
    }
  }

在这里插入图片描述

/**
  * @brief  Returns the DMA Stream base address depending on stream number
  * @param  hdma:       pointer to a DMA_HandleTypeDef structure that contains
  *                     the configuration information for the specified DMA Stream.
  * @retval Stream base address
  */
static uint32_t DMA_CalcBaseAndBitshift(DMA_HandleTypeDef *hdma)
{
  if(IS_DMA_STREAM_INSTANCE(hdma->Instance) != 0U) /* DMA1 or DMA2 instance */
  {
    uint32_t stream_number = (((uint32_t)((uint32_t*)hdma->Instance) & 0xFFU) - 16U) / 24U;

    /* lookup table for necessary bitshift of flags within status registers */
    static const uint8_t flagBitshiftOffset[8U] = {0U, 6U, 16U, 22U, 0U, 6U, 16U, 22U};
    hdma->StreamIndex = flagBitshiftOffset[stream_number & 0x7U];

    if (stream_number > 3U)
    {
      /* return pointer to HISR and HIFCR */
      hdma->StreamBaseAddress = (((uint32_t)((uint32_t*)hdma->Instance) & (uint32_t)(~0x3FFU)) + 4U);
    }
    else
    {
      /* return pointer to LISR and LIFCR */
      hdma->StreamBaseAddress = ((uint32_t)((uint32_t*)hdma->Instance) & (uint32_t)(~0x3FFU));
    }
  }
  else /* BDMA instance(s) */
  {
    /* return pointer to ISR and IFCR */
    hdma->StreamBaseAddress = ((uint32_t)((uint32_t*)hdma->Instance) & (uint32_t)(~0xFFU));
  }

  return hdma->StreamBaseAddress;
}
}
3. HAL_ADC_Start_DMA 中 DMA模式下ADC溢出中断强制使能
    /* With DMA, overrun event is always considered as an error even if
       hadc->Init.Overrun is set to ADC_OVR_DATA_OVERWRITTEN. Therefore,
       ADC_IT_OVR is enabled. */

__HAL_ADC_ENABLE_IT(hadc, ADC_IT_OVR); //原来是0,现在打开,DMA模式下ADC溢出中断强制使能
在这里插入图片描述
LL_ADC_REG_SetDataTransferMode(hadc->Instance, (uint32_t)hadc->Init.ConversionDataManagement);
在这里插入图片描述

4. 代码
/**
  * @brief  DMA error callback.
  * @param hdma pointer to DMA handle.
  * @retval None
  */
void ADC_DMAError(DMA_HandleTypeDef *hdma)
{
  /* Retrieve ADC handle corresponding to current DMA handle */
  ADC_HandleTypeDef *hadc = (ADC_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

  /* Set ADC state */
  SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_DMA);

  /* Set ADC error code to DMA error */
  SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_DMA);

  /* Error callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
  hadc->ErrorCallback(hadc);
#else
  HAL_ADC_ErrorCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
}

/**
  * @brief  DMA transfer complete callback.
  * @param hdma pointer to DMA handle.
  * @retval None
  */
void ADC_DMAConvCplt(DMA_HandleTypeDef *hdma)
{
  /* Retrieve ADC handle corresponding to current DMA handle */
  ADC_HandleTypeDef *hadc = (ADC_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

  /* Update state machine on conversion status if not in error state */
  if ((hadc->State & (HAL_ADC_STATE_ERROR_INTERNAL | HAL_ADC_STATE_ERROR_DMA)) == 0UL)
//ADC_DMAError() 执行完之后HAL_ADC_STATE_ERROR_DMA
  {
    /* Set ADC state */
    SET_BIT(hadc->State, HAL_ADC_STATE_REG_EOC);

    /* Determine whether any further conversion upcoming on group regular     */
    /* by external trigger, continuous mode or scan sequence on going         */
    /* to disable interruption.                                               */
    /* Is it the end of the regular sequence ? */
    if ((hadc->Instance->ISR & ADC_FLAG_EOS) != 0UL)
    {
      /* Are conversions software-triggered ? */
      if (LL_ADC_REG_IsTriggerSourceSWStart(hadc->Instance) != 0UL)
      {
        /* Is CONT bit set ? */
        if (READ_BIT(hadc->Instance->CFGR, ADC_CFGR_CONT) == 0UL)
        {
          /* CONT bit is not set, no more conversions expected */
          CLEAR_BIT(hadc->State, HAL_ADC_STATE_REG_BUSY);
          if ((hadc->State & HAL_ADC_STATE_INJ_BUSY) == 0UL)
          {
            SET_BIT(hadc->State, HAL_ADC_STATE_READY);
          }
        }
      }
    }
    else
    {
      /* DMA End of Transfer interrupt was triggered but conversions sequence
         is not over. If DMACFG is set to 0, conversions are stopped. */
      if (READ_BIT(hadc->Instance->CFGR, ADC_CFGR_DMNGT) == 0UL)
      {
        /* DMACFG bit is not set, conversions are stopped. */
        CLEAR_BIT(hadc->State, HAL_ADC_STATE_REG_BUSY);
        if ((hadc->State & HAL_ADC_STATE_INJ_BUSY) == 0UL)
        {
          SET_BIT(hadc->State, HAL_ADC_STATE_READY);
        }
      }
    }

    /* Conversion complete callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
    hadc->ConvCpltCallback(hadc);
#else
    HAL_ADC_ConvCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
  }
  else /* DMA and-or internal error occurred */
  {
if ((hadc->State & HAL_ADC_STATE_ERROR_INTERNAL) != 0UL)
//HAL_ADC_STATE_ERROR_INTERNAL位,HAL_ADC_Init()、ADC_Enable()、ADC_Disable()之后可能
    {
      /* Call HAL ADC Error Callback function */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
      hadc->ErrorCallback(hadc);
#else
      HAL_ADC_ErrorCallback(hadc);	//该回调可不实现
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
    }
    else
    {
      /* Call ADC DMA error callback */
      hadc->DMA_Handle->XferErrorCallback(hdma);
//有DMA错误,执行ADC_DMAError()之后,每次传输完成中断也不会调用用户回调,继续调用ADC_DMAError()
    }
  }
}
}

/**
  * @brief  DMA half transfer complete callback.
  * @param hdma pointer to DMA handle.
  * @retval None
  */
void ADC_DMAHalfConvCplt(DMA_HandleTypeDef *hdma)
{
  /* Retrieve ADC handle corresponding to current DMA handle */
  ADC_HandleTypeDef *hadc = (ADC_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

  /* Half conversion callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
  hadc->ConvHalfCpltCallback(hadc);
#else
  HAL_ADC_ConvHalfCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
}

/**
  * @brief  ADC error callback in non-blocking mode
  *         (ADC conversion with interruption or transfer by DMA).
  * @note   In case of error due to overrun when using ADC with DMA transfer
  *         (HAL ADC handle parameter "ErrorCode" to state "HAL_ADC_ERROR_OVR"):
  *         - Reinitialize the DMA using function "HAL_ADC_Stop_DMA()".
  *         - If needed, restart a new ADC conversion using function
  *           "HAL_ADC_Start_DMA()"
  *           (this function is also clearing overrun flag)
  * @param hadc ADC handle
  * @retval None
  */
__weak void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hadc);

  /* NOTE : This function should not be modified. When the callback is needed,
            function HAL_ADC_ErrorCallback must be implemented in the user file.
  */
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HAL_DMA_IRQHandler()代码详细分析 的相关文章

  • 查询方式/中断方式/DMA方式的区别及适用范围

    区别 xff1a 查询方式 xff1a CPU与设备串行工作 数据传送与主程序串行工作 xff1b 中断方式 xff1a CPU与设备并行工作 数据传送与主程序串行工作 xff1b DMA方式 xff1a CPU与设备并行工作 数据传送与主
  • stm32---DMA

    DMA 全称Direct Memory Access xff08 直接存储器访问 xff09 xff0c 把一个地址空间的值 复制 到另一个地址空间 xff0c 使用DMA传输方式无需CPU直接控制传输 xff0c 通过硬件为RAM和IO设
  • I/O的控制方式——查询,中断,dma

    早期 xff0c I O串行 xff0c 查询方式 发展 xff0c I O并行 xff0c 两种方式其一是中断方式 xff0c 其二是dma方式 xff0c 使得外部设备能直接与主存储器信息交换 xff0c 减轻了cpu的工作量 技术继续
  • Cache和DMA一致性

    cache读必须要buffer是cacheline对齐的 DMA应该多多少少知道点吧 DMA Direct Memory Access 是指在外接可以不用CPU干预 xff0c 直接把数据传输到内存的技术 这个过程中可以把CPU解放出来 x
  • stm32串口DMA方式发送数据

    该文档介绍stm32 uart1通过DMA方式发送和接收数据 xff0c 代码示例基于ucos ii操作系统 该文档参考https wenku baidu com view d44ef1380975f46526d3e1b5 html 中内容
  • STM32使用DMA接收串口数据

    目录 01 概述 02 DMA接收 03 中断 04 代码 01 概述 在之前的文章里 STM32串口详解 和 STM32 DMA详解 文章中 xff0c 详细讲解了STM32的串口和DMA外设 xff0c 本篇文章将不在细述串口和DMA的
  • UART+DMA数据传输

    DMA的概念 DMA xff08 Direct Memory Access xff09 即直接内存访问 xff0c DMA传输方式无需CPU直接控制传输 xff0c 通过硬件为RAM I O设备开辟一条直接传输数据的通路 xff0c 能使C
  • HAL_UART_IRQHandler(UART_HandleTypeDef *huart)里面的中断接收函数(作者自己生成的函数代码,中间有关闭接收中断,但是原子教程中没有关闭中断的语句注意区别)

    前言 1 UART Receive IT 2 HAL UART Receive 3 HAL UART Receive IT 前言 看了很长时间串口中断的HAL库 xff0c 最容易混淆的就是函数的名称 xff0c 主要集中在UART Rec
  • HAL_UART_IRQHandler(UART_HandleTypeDef *huart)里面的中断接收函数

    目录 前言1 UART Receive IT2 HAL UART Receive3 HAL UART Receive IT 前言 看了很长时间串口中断的HAL库 xff0c 最容易混淆的就是函数的名称 xff0c 主要集中在UART Rec
  • 【STM32】HAL库-以太网外设-LAN8720A-LWIP-无操作系统

    开发环境 KEIL MDK ARM 5 27MCU STM32F429IGT6PHY IC LAN8720ALWIP LWIP2 1 2STM32CUBEMX 6 6 1HAL V1 27 1 LAN8720A使用RMII接口与STM32的
  • 16. GD32F103C8T6入门教程-adc 使用教程2-dma+连续扫描方式采集数据

    adc 使用教程2 dma 连续扫描方式采集数据 adc 的扫描模式就是把配置了规则或注入通道按照配置的顺序采集一轮 adc 的连续转换模式就是把配置了规则或注入通道按照配置的顺序采集N轮 注意 dma使用时存在一个外设映射到一个dam外设
  • 一文彻底理解DMA

    DMA Direct Memory Acess 1 什么是DMA 有什么作用 2 DMA传输过程简述 2 1 DMA普通传输过程 2 2 DMA指针递增传输过程 2 3 DMA循环传输过程 2 4 DMA双缓冲区传输过程 3 STM32F4
  • STM32F103 UART4串口使用DMA接收不定长数据和DMA中断发送

    一 前言 使用DMA通信的好处是 不占用单片机资源 不像普通串口中断 发送一个字节触发一次中断 发送100个字节触发100次中断 接收一个字节触发一次中断 接收200个字节触发200次中断 数据接收完毕触发一次DMA中断 发送数据完毕触发一
  • HAL库学习笔记-11 I2C

    目录 前言 一 I2C协议简介 I2C物理层 I2C协议层 1 基本读写过程 2 通讯的起始和停止信号 3 数据有效性 4 地址及数据方向 5 应答信号 二 STM32的I2C特性及架构 STM32 I2C架构解析 1 逻辑引脚 2 时钟控
  • 使用HAL库开发STM32:GPIO口基础使用与外部中断

    文章目录 目的 GPIO口基础使用 基础说明 初始化设置 输出与控制 读取端口值 GPIO口与外部中断 总结 目的 对于MCU来说GPIO口的使用是最基础的内容 仅使用GPIO口和延时等 就可以完成很多功能了 GPIO口基础使用 基础说明
  • Linux驱动程序DMA传输到PC作为主机的PCIe卡

    我正在开发一个 DMA 例程 将数据从 PC 传输到 PCIe 卡上的 FPGA 我阅读了 DMA API txt 和 LDD3 ch 15 详细信息 但是 我不知道如何从 PC 到 PCIe 卡上的一致 iomem 块进行 DMA 传输
  • 启用 DMA 的 UART Tx 模式

    我已经为 UART 在传输模式下编写了一个简单的设备驱动程序 并启用了 DMA 和中断 我使用的硬件是 omap 4460 pandaboard 其中加载了 Linux 3 4 下面我分享一下相关部分的代码 在开放阶段 dma map io
  • Linux 内核中的 DMA 映射和 DMA 引擎是什么?

    Linux 内核中的 DMA 映射和 DMA 引擎是什么 DMA映射API和DMA引擎API何时可以在Linux设备驱动程序中使用 任何真正的 Linux 设备驱动程序示例作为参考都会很棒 Linux 内核中的 DMA 映射和 DMA 引擎
  • glBufferSubData什么时候返回? [复制]

    这个问题在这里已经有答案了 我想将一个非常大的内存块的内容传输到足够大的 GPU 缓冲区 然后立即更改 CPU 上的内存内容 伪代码是这样的 glBindBuffer very large buffer glBufferSubData ve
  • HAL_Delay() 陷入无限循环

    我被 HAL Delay 函数困住了 当我调用此函数 HAL Delay 时 控制陷入无限循环 在寻找问题的过程中 我发现了这个 http www openstm32 org forumthread2145 threadId2146 htt

随机推荐

  • socket封装HTTP请求

    之前写过两个socket封装的HTTP GET请求 xff0c 可是知其然 xff0c 不知所以然 这次写POST请求就有点懵逼了 还是从大佬的文章出发 xff1a https blog csdn net a19881029 article
  • access中,如何删除不可见空格

    1 可以使用 Trim 函数 xff0c 删除字符串 首 尾 的正常空格 span class token keyword update span 表名 span class token keyword set span 字段 span c
  • Raspberry Pi树莓派分类和其相似产品介绍

    文章目录 前言一 1代树莓派二 2代树莓派三 3代树莓派四 4代树莓派五 树莓派Pico六 目前可替代板子介绍引用 前言 树莓派官网 作为小型计算机的代表 xff0c 树莓派可是作为开山鼻祖 xff0c 本文聊一下目前树莓派几代板子发展历程
  • ARM汇编指令ldr和MOV的区别

    1 八位图 数据 2 MOV指令 MOV指令可以把立即数或者寄存器内容 xff08 注意 xff1a 这里绝对不可以是内存 xff01 xff01 xff09 传递给一个寄存器 MOV对于立即数是有要求的 xff0c 就是上边的 8位图 数
  • GPS NEMA 0183协议

    一 NMEA0183标准语句 GPS常用语句 GPGGA 例 xff1a GPGGA 092204 999 4250 5589 S 14718 5084 E 1 04 24 4 19 7 M 0000 1F 字段0 xff1a GPGGA
  • 使用setvbuf更改printf的默认buffer 行为

    有3种buffer行为 xff0c 不缓冲 xff0c 基于块的缓冲 和 基于行的缓冲 stdout xff08 printf xff09 默认是基于行的缓冲 xff0c 即写到stdout的字符都会被缓冲起来直到一个换行符输出的时候 xf
  • linux 下 tcpdump详解 后篇(自己实现抓包过滤)

    一 概述 在了解了tcpdump的原理后 xff0c 你有没有想过自己去实现抓包过滤 xff1f 可能你脑子里有个大概的思路 xff0c 但是知道了理论知识 xff0c 其实并不能代表你完全的理解 只要运用后 xff0c 你才知道哪些点需要
  • 结构体与共同体(联合体)的妙用

    结构体与共同体 xff08 联合体 xff09 的妙用 学习过C语言后 xff0c 大家都了解了结构体与共同体 两者之间的区别是 xff1a 共同体 xff1a 使几个不同类型的变量共占一段内存 相互覆盖 所占内存长度是各最长的成员占的内存
  • [北力电子] 无人机4G图传数传一体 pixhawk mavlink GSLINK 720P

    随着无人机和4G技术的发展 xff0c 实时监看空中视角的画面已经成为可能GSLINK突破传统的传输方式 xff0c 利用了4G网络将数据和视频流融为一体进行无限距离的传输 用户使用EC2地面站 xff08 Mission Planner
  • C#笔记(基础篇)

    简介 第一次发博客 xff0c 欢迎交流沟通 因为学习虚拟现实需要所以暑假一个月学了点C xff0c 做了笔记 xff0c 在这进行分享 xff0c 欢迎浏览 有些代码打在VS中 没有记录在笔记里 请见谅 xff08 视频指路 xff09
  • 《机器人操作系统(ROS)浅析》笔记

    机器人操作系统 xff08 ROS xff09 浅析 这是看了 A Gentle Introduction to ROS 这本书后记的笔记 xff0c 网上刚好找得到中文版的 xff0c 就看中文版了 xff0c 欢迎大佬批评指正 xff0
  • 搭建ROS小车——硬件购买篇(基于arduino mega2560,L298N)

    在寒假期间完成了ROS小车的制作 xff0c 记录一下 xff0c 不过也有很多不足 xff0c 之后再进行修正 xff0c 本系列文章将分为硬件购买篇 下位机篇 上位机篇 功能拓展篇四个部分来进行讲解 上位机 树莓派3B 43 16GBS
  • 搭建ROS小车——上位机篇(基于arduino mega2560,L298N)

    环境 上位机为树莓派3B 43 环境 xff1a ubuntu mate16 04 43 ros kineticros master在电脑上 xff0c 环境为ubuntu18 04 43 ros melodic 考虑到之后可能会拓展别的功
  • R语言入门学习

    R语言 视频链接 xff1a https www bilibili com video BV19x411X7C6 数据分析过程 数据采集 数据存储 数据分析 数据挖掘 数据可视化 进行决策 1 Rstudio使用 1 1 入门 TAB补齐
  • IO多路复用实现TCP并发服务器(select)

    大致描述一下 先定义 fd set 要监视的读事件readfds xff0c FD SET将sockfd放到readfds事件里 xff0c 更新文件最大描述符 xff0c select函数返回值是返回准备好的文件描述符个数 xff08 这
  • 网页中播放RTSP(2) H5Stream

    总的思路是全面的7种方法 xff0c RTSP转换成RTMP WebSocket WebRTC HLS xff0c 再从网页中获取 而这个转换过程 xff0c 就是一个视频服务器端 xff0c 通过视频服务器软件转换RTSP为其他协议格式
  • 固态硬盘在IDE、AHCI模式下的速度对比

    AHCI全名 Advanced Host Controller Interface xff0c 中译 xff1a 高级主机控制接口 xff0c 它是 Intel 所主导的一项技术 xff0c 可以发挥SATA硬盘的潜在加速功能 xff0c
  • Win10 64位双系统UEFI官网下载镜像安装(不用PE)

    1 刻录Win10 ISO镜像 2 U盘UEFI启动 先设置BIOS xff0c Boot Mode xff1a UEFI Secure Boot OFF 3 在 要安装的语言 界面 xff0c 按shift 43 F10调出DOS窗口 4
  • FreeRTOS实验一:portYIELD_FROM_ISR()任务切换的时机分析

    分析下portYIELD FROM ISR 任务切换的时机 span class token keyword void span span class token function HAL UART RxCpltCallback span
  • HAL_DMA_IRQHandler()代码详细分析

    这里使用ADC1联动DMA1 xff0c 开启半传输中断 传输中断 debug时 xff0c dma也一直在工作 xff0c 所以半传输中断 传输中断会同时生效 1 adc1使用了DMA1 Stream0 xff0c Instance表示如