Reputation: 68008
I have a quite strange problem. I use the same micro in three projects. Two of them use HSI clock source, one HSE. Power is supplied exactly the same way. HSI ones go through the ADC calibration without any problems, HSE one gets stuck. Exactly the same initialisation procedure. ADC definitely works as I can read and write from the registers, I am getting ADC readings, but I cant go through the calibration
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;
Upvotes: 1
Views: 3879
Reputation: 5511
I also ran into this same issue on the STM32F303VC
(Discovery board).
Your comment on Guillaume's answer was the answer:
The problem was in the PLL & ADC clock settings. This micro require some additional configuration as the ADC has dual clock domain architecture
The reference manual had the following:
Dual clock domain architecture The dual clock-domain architecture means that each ADC clock is independent from the AHB bus clock. The input clock of the two ADCs (master and slave) can be selected between two different clock sources (see Figure 53: ADC clock scheme):
a) The ADC clock can be a specific clock source, named “ADCxy_CK (xy=12 or 34) which is independent and asynchronous with the AHB clock”. It can be configured in the RCC to deliver up to 72 MHz (PLL output). Refer to RCC Section for more information on generating ADC12_CK and ADC34_CK. To select this scheme, bits CKMODE[1:0] of the ADCx_CCR register must be reset.
b) The ADC clock can be derived from the AHB clock of the ADC bus interface, divided by a programmable factor (1, 2 or 4). In this mode, a programmable divider factor can be selected (/1, 2 or 4 according to bits CKMODE[1:0]). To select this scheme, bits CKMODE[1:0] of the ADCx_CCR register must be different from “00”.
When I originally tried to run the calibration the mode (value of the CKMODE
bits) was 0
.
This caused the calibration to never complete as I never configured RCC
to generate an ADC12_CK
clock.
To fix the issue I set the CKMODE
bits to 2
.
That means the ADC
clock will be derived from the AHB
clock divided by 2
.
Upvotes: 2
Reputation: 11
maybe you could share what you did. Because I faced the same problem.
What I did was to check if ARDY
bit was set and also if the ADC
is enabled (after reset for some reason it was enabled) and clear/disable them. Due to the ref. manual it is not allowed to start a calibration if ADC
is enabled.
/* 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 */
}
Upvotes: 1
Reputation: 1214
In you while loop, don't you mean:
while((ADC -> CR & ADC_CR_ADCAL))
rather than
while((ADC1 -> CR & ADC_CR_ADCAL))
Upvotes: 1