我有一个很奇怪的问题。我在三个项目中使用相同的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;
答案 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 */
}