STM32F303 ADC卡在校准中

时间:2017-05-09 17:38:04

标签: arm microcontroller stm32 adc

我有一个很奇怪的问题。我在三个项目中使用相同的micro。其中两个使用HSI时钟源,一个HSE。电源提供方式完全相同。 HSI没有任何问题进行ADC校准,HSE卡住了。完全相同的初始化过程。 ADC绝对可以工作,因为我可以从寄存器读取和写入,我得到ADC读数,但我不能通过校准

static inline void ADCCalibration(ADC_TypeDef *ADC) {
    uint32_t start = HAL_GetTick();
    ADC -> CR |= ADC_CR_ADCAL;
    while((ADC1 -> CR & ADC_CR_ADCAL)) {
        if((HAL_GetTick() - start) > ADC_CAL_TIMEOUT) {
            __BKPT();
        }
    }
}

__HAL_RCC_ADC12_CLK_ENABLE();
__HAL_RCC_ADC34_CLK_ENABLE();

ADC1 -> DIFSEL = 0;
ADC2 -> DIFSEL = 0;
ADC3 -> DIFSEL = 0;
ADC4 -> DIFSEL = 0;
while(ADC1 -> DIFSEL || ADC2 -> DIFSEL || ADC3 -> DIFSEL || ADC4 -> DIFSEL);
ADC1 -> CR &= ~(ADC_CR_ADVREGEN_Msk);
ADC1 -> CR |= ADC_CR_ADVREGEN_0;
ADC2 -> CR &= ~(ADC_CR_ADVREGEN_Msk);
ADC2 -> CR |= ADC_CR_ADVREGEN_0;
ADC3 -> CR &= ~(ADC_CR_ADVREGEN_Msk);
ADC3 -> CR |= ADC_CR_ADVREGEN_0;
ADC4 -> CR &= ~(ADC_CR_ADVREGEN_Msk);
ADC4 -> CR |= ADC_CR_ADVREGEN_0;
__ADC_Delay();

ADCCalibration(ADC1);
ADCCalibration(ADC2);
ADCCalibration(ADC3);
ADCCalibration(ADC4);

ADC1 -> CR |= ADC_CR_ADEN;
ADC2 -> CR |= ADC_CR_ADEN;
ADC3 -> CR |= ADC_CR_ADEN;
ADC4 -> CR |= ADC_CR_ADEN;

3 个答案:

答案 0 :(得分:1)

在你的循环中,你的意思是:

while((ADC -> CR & ADC_CR_ADCAL))

而不是

while((ADC1 -> CR & ADC_CR_ADCAL))

答案 1 :(得分:1)

我在 STM32F303VC(探索版)上也遇到了同样的问题。 您对纪尧姆回答的评论就是答案:

<块引用>

问题出在 PLL 和 ADC 时钟设置中。由于 ADC 具有双时钟域架构,因此该微需要一些额外的配置

参考手册有以下内容:

<块引用>

双时钟域架构 双时钟域架构意味着每个 ADC 时钟独立于 AHB 总线时钟。 两个 ADC(主从)的输入时钟可以在两个不同的时钟之间选择 时钟源(参见图 53:ADC 时钟方案):

<块引用>

a) ADC 时钟可以是特定的时钟源,名为“ADCxy_CK (xy=12 or 34)” 与 AHB 时钟独立且异步”。 它可以在 RCC 中配置以提供高达 72 MHz(PLL 输出)的频率。参考 有关生成 ADC12_CK 和 ADC34_CK 的更多信息,请参阅 RCC 部分。 要选择此方案,ADCx_CCR 寄存器的 CKMODE[1:0] 位必须为 重置。

<块引用>

b) ADC 时钟可以从 ADC 总线接口的 AHB 时钟导出, 除以可编程因子(1、2 或 4)。在这种模式下,可编程分频器 可以选择因子(/1、2 或 4,根据位 CKMODE[1:0])。 要选择此方案,ADCx_CCR 寄存器的 CKMODE[1:0] 位必须为 不同于“00”。

当我最初尝试运行校准时,模式(CKMODE 位的值)是 0

这导致校准永远不会完成,因为我从未将 RCC 配置为生成 ADC12_CK 时钟。

为了解决这个问题,我将 CKMODE 位设置为 2。 这意味着 ADC 时钟将来自 AHB 时钟除以 2

答案 2 :(得分:0)

也许您可以分享您所做的事情。因为我遇到了同样的问题。 我要做的是检查是否设置了ARDY位,以及是否启用了ADC(由于某种原因而在重置后启用了)并清除/禁用了它们。由于参考。手动,如果启用ADC,则不允许开始校准。

/* if ADRDY is set */
if((ADC3->ISR & ADC_ISR_ADRDY) == (ADC_ISR_ADRDY))
{
    ADC3->ISR |= (ADC_ISR_ADRDY); /* clear ADRDY */
}

/* if ADC3 is enabled */
if((ADC3->CR & ADC_CR_ADEN) == (ADC_CR_ADEN))
{
    ADC3->CR |= (ADC_CR_ADDIS); /* disable ADC3 */
}