2023-02-16 03:19 AM
Hi,
I am having trouble configuring the ADC on my STM32L431KB. The calibration procedure appears to go well until it gets to the step where the program waits for the calibration to finish. It is never able to finish. I think the problem may be related to the fact that ADC1_CR_ADEN is always set 1, and I am unable to change it to 0. Does anyone know why this might be happening?
Thanks,
Solved! Go to Solution.
2023-02-16 07:39 AM
Do you call this function repeatedly, or only after reset?
> // Ensure that ADEN = 0
> ADC1->CR &= ~ADC_CR_ADEN;
You can't switch off ADEN by writing 0 to it, it's a rs bit. If you need to switch off ADEN, you have to write 1 to ADDIS (but do it ONLY if ADEN == 1).
Read carefully ADC_CR bits description. It's tricky, but mostly the description is there.
JW
2023-02-16 07:10 AM
Post code.
JW
2023-02-16 07:13 AM
retval_t adc_init(){
// Enable clock to ADC peripheral
RCC->AHB2ENR |= RCC_AHB2ENR_ADCEN;
// Ensure that ADEN = 0
ADC1->CR &= ~ADC_CR_ADEN;
// Configure ADC pins PB0
pinCtrl_config_T BATT_cfg = {.base = ADC_BATT_PORT, .pin = ADC_BATT_PIN, .mode = pinMode_disabledOrAnalog};
pinCtrl_pinInit(BATT_cfg);
// Configure ADC registers
ADC1->CFGR |= ADC_CFGR_CONT | ADC_CFGR_OVRMOD; // Set ADC for continuous conversion, overwrite data during overrun
ADC1_COMMON->CCR |= 0b01 << ADC_CCR_CKMODE_Pos; // Set ADC to use HCLK
ADC1->SQR1 = 15 << ADC_SQR1_SQ1_Pos; // Puts the desired channel in the sample queue, only sample 1 channel
// Configure ADC Sample time to 640 ADC clock (8uS)
ADC1->SMPR2 |= 0b111 << ADC_SMPR2_SMP15_Pos;
ADC1->SMPR1 |= 0b111 << ADC_SMPR1_SMP8_Pos;
// Exit ADC deep power down mode
ADC1->CR &= ~ADC_CR_DEEPPWD;
// Enable ADC internal voltage regulator
ADC1->CR |= ADC_CR_ADVREGEN;
// Wait for ADC internal voltage regulator to start-up
_delay_ms(1);
// Start ADC internal calibration procedure
ADC1->CR &= ~ADC_CR_ADCALDIF; // Set calibration mode for single ended input
_delay_ms(10);
ADC1->CR |= ADC_CR_ADCAL; // Start Calibration
_delay_ms(10);
// Wait calibration is done
if(checkRetry(&ADC1->CR, ADC_CR_ADCAL_Msk, 0, ADC_CAL_MAXRETRY) == RET_ERROR){
return RET_ERROR;
}
// Enable ADC
ADC1->ISR |= ADC_ISR_ADRDY; //Clear the ADRDY bit in the ADC_ISR register by writing ‘1’.
ADC1->CR |= ADC_CR_ADEN;
// Wait until ADRDY is set to 1, which indicates that the ADC has finished startup
if(checkRetry(&ADC1->ISR, ADC_ISR_ADRDY_Msk, ADC_ISR_ADRDY, ADC_START_MAXRETRY) == RET_ERROR){
return RET_ERROR;
}
// Start regular conversion
ADC1->CR |= ADC_CR_ADSTART;
return RET_SUCCESS;
}
2023-02-16 07:39 AM
Do you call this function repeatedly, or only after reset?
> // Ensure that ADEN = 0
> ADC1->CR &= ~ADC_CR_ADEN;
You can't switch off ADEN by writing 0 to it, it's a rs bit. If you need to switch off ADEN, you have to write 1 to ADDIS (but do it ONLY if ADEN == 1).
Read carefully ADC_CR bits description. It's tricky, but mostly the description is there.
JW
2023-02-17 03:15 AM
That worked! I set ADDEN to 1 and now the calibration works. Thank you.