【问题标题】:STM32F4 HAL ADC DMA Transfer ErrorSTM32F4 HAL ADC DMA 传输错误
【发布时间】:2019-01-20 07:51:44
【问题描述】:

我在一个项目中使用 STM32F405OG,其中一项必要功能是以 ~1 Hz 的频率监控 3 个模拟通道。我想要的实现是在扫描模式下开始对所有 3 个通道进行 ADC DMA 读取,并在 DMA 完成中断发生后稍后检索结果。

我正在使用 ADC1 并尝试了 DMA 通道 0 和 4,结果相同:在第一次调用 HAL_ADC_Start_DMA() 后调用了 HAL_ADC_ErrorCallback()。此时,ADC 句柄处于错误状态 (HAL_ADC_STATE_ERROR_DMA),错误代码为 0x04 (HAL_ADC_ERROR_DMA)。检查链接的 DMA 句柄会产生 HAL_DMA_ERROR_NO_XFER 的 DMA 错误代码,意思是“请求中止,没有正在进行的 Xfer”。

我完全不知道是什么原因造成的——我的代码应该与示例以及 stm32f4xx_hal_adc.c 顶部的“如何使用此模块”cmets 一致。我在下面附上了我的代码。

ADC_HandleTypeDef ADC_hADC = 
{
    .Instance = ADC1,
    .Init = 
    {
        .ClockPrescaler        = ADC_CLOCK_SYNC_PCLK_DIV8,
        .Resolution            = ADC_RESOLUTION_12B,
        .EOCSelection          = ADC_EOC_SEQ_CONV, // EOC at end of sequence of channel conversions
        .ScanConvMode          = ENABLE,
        .ContinuousConvMode    = DISABLE,
        .DiscontinuousConvMode = DISABLE,
        .NbrOfDiscConversion   = 0U,
        .ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE,
        .ExternalTrigConv      = ADC_SOFTWARE_START,
        .DataAlign             = ADC_DATAALIGN_RIGHT,
        .NbrOfConversion       = _NUM_ADC_CONV,
        .DMAContinuousRequests = DISABLE
    }
};

DMA_HandleTypeDef _hDmaAdc = 
{ 
    .Instance = DMA2_Stream0,
    .Init = 
    { 
        .Channel             = DMA_CHANNEL_0,
        .Direction           = DMA_PERIPH_TO_MEMORY,
        .PeriphInc           = DMA_PINC_DISABLE,
        .MemInc              = DMA_MINC_ENABLE,
        .PeriphDataAlignment = DMA_PDATAALIGN_WORD,
        .MemDataAlignment    = DMA_MDATAALIGN_WORD,
        .Mode                = DMA_NORMAL,
        .Priority            = DMA_PRIORITY_HIGH,
        .FIFOMode            = DMA_FIFOMODE_DISABLE,
        .FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL,
        .MemBurst            = DMA_MBURST_SINGLE,
        .PeriphBurst         = DMA_PBURST_SINGLE
    }
};

void HAL_ADC_MspInit(ADC_HandleTypeDef *h)
{
    if (!h)
    {
        return;
    }
    else if (h->Instance == ADC1)
    {        
        __HAL_RCC_ADC1_CLK_ENABLE();
        __HAL_RCC_DMA2_CLK_ENABLE();

        HAL_DMA_Init(&_hDmaAdc);
        __HAL_LINKDMA(h, DMA_Handle, _hDmaAdc);

        HAL_NVIC_SetPriority(ADC_IRQn,          IT_PRIO_ADC, 0);
        HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, IT_PRIO_ADC, 0);

        HAL_NVIC_EnableIRQ(ADC_IRQn);
        HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
    }
}

uint32_t _meas[3];

ADC_ChannelConfTypeDef _chanCfg[3] = 
{ 
    // VIN_MON
    {
        .Channel = ADC_CHANNEL_1,
    },

    // VDD_MON
    {
        .Channel = ADC_CHANNEL_8,
    },

    // VDD2_MON
    {
        .Channel = ADC_CHANNEL_2,
    }
};

Bool ADC_Init(void)
{
    ADC_DeInit();
    memset(_meas, 0, sizeof(_meas));

    Bool status = (HAL_ADC_Init(&ADC_hADC) == HAL_OK);

    if (status)
    {
        // Configure each ADC channel
        for (uint32_t i = 0U; i < NELEM(_chanCfg); i++)
        {
            _chanCfg[i].Rank = (i + 1U);
            _chanCfg[i].SamplingTime = ADC_SAMPLETIME_480CYCLES;
            _chanCfg[i].Offset = 0U;

            if (HAL_ADC_ConfigChannel(&ADC_hADC, &_chanCfg[i]) != HAL_OK)
            {
                status = FALSE;
                break;
            }
        }

        _state = ADC_STATE_READY;
    }

    if (!status)
    {
        ADC_DeInit();
    }

    return status;
}

Bool ADC_StartRead(void)
{
    Bool status = TRUE;

    status = (HAL_ADC_Start_DMA(&ADC_hADC, &_meas[0], 3) == HAL_OK);

    return status;
}

【问题讨论】:

  • 您不能“尝试”DMA 通道。你需要使用正确的。阅读参考手册,其中有漂亮的表格所有必要信息
  • 顺便说一句,在寄存器中设置它需要 15 分钟的工作,10 行代码,简单明了。 HAL - 100-150 行,10 天的调试,发布问题和挫折,结果通常不完全符合您的预期。选择是你的
  • 我用一些缺失的频道初始化代码编辑了我的问题
  • 我还建议阅读有关 DMA 的参考手册。至少在调试 DMA 寄存器时阅读寄存器映射部分以查看配置是否正常,也不是 HAL、SPL 或直接寄存器写入,您可以在调试和阅读参考手册时学习 :)。如果您使用的是 HAL 库,那么它不会让您对 MCU 有任何了解。当 LIB 有缺陷时,它也会伤害你。因此,在配置外设之前,最好至少阅读参考手册中的寄存器映射。
  • 我已多次阅读有关 DMA 和 ADC 的参考手册部分的全部内容(除了其他外设)。 HAL 并没有那么糟糕,并且由于开发计划被压缩,到目前为止效果还不错。我发布此问题的原因是由于在扫描转换完成后未明确停止 DMA/ADC 时出现的奇怪行为,无论 HAL 使用情况如何,都可能发生这种情况。

标签: microcontroller stm32 hal stm32f4


【解决方案1】:

在通过 ClockPrescaler init 结构字段减慢转换速度、增加 ADC 周期数并调用 HAL_ADC_Stop_DMA()(根据 stm32f4xx_hal_adc.c 中的文件头注释)后,一切正常。

请注意,在 DMA 传输完成 ISR 中调用 HAL_ADC_Stop_DMA() 也会导致上述错误情况,因此必须在调用 DMAXferCplt ISR 之后的某个时间调用该函数。

【讨论】:

  • 感谢您分享您的修复;我遇到了同样的问题。
猜你喜欢
  • 2019-02-14
  • 2021-06-16
  • 2015-08-26
  • 2019-08-11
  • 2020-11-19
  • 2020-09-12
  • 2014-06-27
  • 2020-11-02
  • 2023-03-15
相关资源
最近更新 更多