2021-01-13 12:47 PM
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++;
}
Solved! Go to Solution.
2021-01-13 02:42 PM
> 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
2021-01-13 01:49 PM
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.
2021-01-13 02:42 PM
> 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
2021-01-14 08:36 AM
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 :))