Skip to main content
AAnth.1
Senior
January 13, 2021
Solved

STM32F303 ADC1 calibration stuck

  • January 13, 2021
  • 3 replies
  • 1737 views

Hi

I'm porting my STM32F103 code to the STM32F303, and noticed the significant difference in the ref manual regarding the ADC module. Being a beginner in STM32 MCUs, I'm struggling to get my calibration run correctly.

I feel like I am doing as I'm supposed to, but my calibration gets stuck in line 38. Debugging the register bits, ADCAL remains 1, even though it should be cleared by hardware once calibration is over.

Can anyone see what I'm doing wrong?

PS: If I don't run the calibration, my ADC works, but gives the wrong values, which is why I would like to run my calibration

Thank you.

/**
 * STM32F303CC ADC
 * Uses ADC1
 * Reads the temperature from the internal temp sensor.
 * Also, SWV is implemented. PB3 on MCU is used for TRACESWO
 * NOT DONE YET
 */
 
#include <stdint.h>
#include <stdio.h>
#include "stm32f3xx.h"
 
#define AVG_SLOPE	4.3	// mV per C
#define V25			1.43	// V
volatile uint32_t msTicks = 0;
 
int main(void)
{
	__NVIC_EnableIRQ(ADC1_2_IRQn);
	SystemCoreClockUpdate();
	SysTick_Config(SystemCoreClock / 1000);	// 1ms interrupt
 
	// Setup of ADC1
	uint16_t i = 0;
	RCC->AHBENR |= RCC_AHBENR_ADC12EN;
	for(;i<255;i++);
	i=0;
 
	ADC1->IER |= ADC_IER_EOCIE;
	ADC1->CR &= ~ADC_CR_ADVREGEN;
	ADC1->CR |= ADC_CR_ADVREGEN_0;
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;	// Enables SysTick
	while(msTicks<1);
	msTicks = 0;
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;	// Disables SysTick until next delay call
 
	ADC1->CR |= ADC_CR_ADCAL;	//ADCALDIF = 0
	while(ADC1->CR && ADC_CR_ADCAL);	// Wait for calibration to be over
 
	ADC1->CFGR |= ADC_CFGR_EXTEN_0 | ADC_CFGR_EXTSEL_0 | ADC_CFGR_EXTSEL_1;
	ADC1->SMPR1 |= ADC_SMPR1_SMP1_2;
	ADC12_COMMON->CCR |= ADC12_CCR_TSEN | ADC12_CCR_CKMODE_0;
	ADC1->SQR1 |= (16<<ADC_SQR1_SQ1_Pos);	// ADC channel 16 for Temp sensor
 
	ADC1->CR |= ADC_CR_ADEN;
	while(!(ADC1->ISR && ADC_ISR_ADRDY));
 
	ADC1->CR |= ADC_CR_ADSTART;
 
	// Enables Port A on APB2 bus to set PA1 to AF
	RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
	for(;i<255;i++);
	i=0;
	GPIOA->MODER |= GPIO_MODER_MODER1_1;
	GPIOA->AFR[0] |= (1<<GPIO_AFRL_AFRL1_Pos);
 
	// Enables TIM2 bus
	RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
	for(;i<255;i++);
	i=0;
	TIM2->DIER |= TIM_DIER_UIE;
	TIM2->PSC = 7999;
	TIM2->ARR = 1000;
	TIM2->CCR2 = 500;
	TIM2->EGR |= TIM_EGR_CC2G;
	TIM2->CCER |= TIM_CCER_CC2E;
	TIM2->CCMR1 |= TIM_CCMR1_OC2PE | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2;
 
	TIM2->CR1 |= TIM_CR1_ARPE | TIM_CR1_URS | TIM_CR1_CEN;
 
	/* Loop forever */
	for(;;);
}
 
void ADC1_2_IRQHandler(void)
{
	// Handles the IRQ of ADC1. EOC flag is cleared by reading data register
	static uint32_t temp = 0;
	static uint32_t temp_sensor = 0;
	temp = ADC1->DR;
	temp_sensor = (V25-temp*3.3/4095)/(AVG_SLOPE)*1000+25;
	printf("Temperature is: %lu\n", temp_sensor);
}
 
void SysTick_Handler(void)
{
	msTicks++;
}

This topic has been closed for replies.
Best answer by waclawek.jan

> ADC need be disable before calibration.

Yes, but only if it was enabled before, which it does not appear to be the case.

> ADC1->CR && ADC_CR_ADCAL

You want mask, not perform a logical AND, so

ADC1->CR & ADC_CR_ADCAL

Similarly below for

while(!(ADC1->ISR && ADC_ISR_ADRDY));

Also, make sure you have a valid clock for ADC, so you'll need to set ADCxx_CCR.CKMODE (and if set to 0, select proper clock in RCC) before you start calibration.

JW

3 replies

zzzzz
Senior
January 13, 2021

ADC need be disable before calibration. disable bit in CR need be set. Add the following code before line 37

ADC1->CR|=ADC_CR_ADDIS

ADC1->ISR=(ADC_FLAG_EOSMP | ADC_FLAG_RDY) // clear these two flags by write 1.

waclawek.jan
waclawek.janBest answer
Super User
January 13, 2021

> ADC need be disable before calibration.

Yes, but only if it was enabled before, which it does not appear to be the case.

> ADC1->CR && ADC_CR_ADCAL

You want mask, not perform a logical AND, so

ADC1->CR & ADC_CR_ADCAL

Similarly below for

while(!(ADC1->ISR && ADC_ISR_ADRDY));

Also, make sure you have a valid clock for ADC, so you'll need to set ADCxx_CCR.CKMODE (and if set to 0, select proper clock in RCC) before you start calibration.

JW

AAnth.1
AAnth.1Author
Senior
January 14, 2021

Hi guys,

thank you very much for your input. Jan's input brought me in the right direction. I'm performing the calibration BEFORE defining the ADC clock (line 41). So line 41 needs to be moved before the ADC calibration in order to activate the proper ADC clock.

Thank you both for your feedback. It now works as expected (after some small other corrections :))