0___________
0___________

Reputation: 68008

STM32F303 ADC gets stuck in the calibration

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

Answers (3)

WBuck
WBuck

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

BanJoe
BanJoe

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

Guillaume Michel
Guillaume Michel

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

Related Questions