I am using Keil uvision 5 for my STM32F103C8 microcontroller. I am debugging the code for ADC single channel polling example using CMSIS Core. I am not using any Standard peripheral library or HAL but I had used the way of STD lib doing the initialization process of the ADC.
My ADC Calibration process properly work and code do not stuck into while loop when doing the calibration process. But when I try to start conversion it do not convert the value and my code stuck in this while loop
while((ADC1->SR & ADC_SR_EOC)==0);
This is my initialization process for the ADC1
uint32_t tmpreg1 = 0;
RCC->CFGR |= RCC_CFGR_ADCPRE_DIV8; //LINE#1772
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN | RCC_APB2ENR_IOPAEN; //clock for ADC1 and GPIOA is active
GPIOA->CRL &= ~(GPIO_CRL_CNF0); //CNF0=0 will make analog input mode
GPIOA->CRL &= ~(GPIO_CRL_MODE0); //mode bits remains zero in input mode
tmpreg1 = ADC1->CR1;
tmpreg1 &= 0xFFF0FEFF; //clear SCAN AND DUALMODE bits
ADC1->CR1 = tmpreg1;
/* Clear CONT, ALIGN and EXTSEL bits */
tmpreg1 = ADC1->CR2;
tmpreg1 &=0xFFF1F7FD;
/* Write to ADCx CR2 */
ADC1->CR2 = tmpreg1;
tmpreg1 = ADC1->SQR1;
/* Clear L bits */
tmpreg1 &=0xFF0FFFFF;
ADC1->SQR1 = tmpreg1;
ADC1->CR2 |= ADC_CR2_ADON;
/*
=====
ADC1->CR2 |= ADC_CR2_ADON;
delay_i(100);
ADC1->CR2 &= ~ADC_CR2_CONT; //single conversion mode. continues disabled
ADC1->CR2 &= ~ADC_CR2_EXTTRIG; //DISABLE EXTERNAL TRIGGER
ADC1->CR2 &= ~ADC_CR2_ALIGN; //MAKE RIGHT ALIGN
=====
*/
//ADC1->CR2 = 1;
//ADC1->CR1 |= ADC_CR1_DISCEN;
/*
These bits are written by software
to define the total number of conversions in
the regular channel conversion sequence
*/
//ADC1->SQR1 &= ~ADC_SQR1_L; //ONLY ONE CONVERSION WILL BE DONE
//Calibration reset
ADC1->CR2 |= ADC_CR2_RSTCAL; //RESET CALIBRATION
while((ADC1->CR2 & ADC_CR2_RSTCAL)!=0); //WAIT FOR CALIBRATION RESET
//Calibrate
ADC1->CR2 |= ADC_CR2_CAL;
while((ADC1->CR2 & ADC_CR2_CAL)!=0);
adc_channel_config();
ADC1->CR2 &= ~ADC_CR2_ADON;
as you can see in the commented code. I had tried the settings in bunch of different ways but that seems no issue in this. In few Forums people suggested turn of The ADC before starting a new conversion so I also tried this in my adc read function but no luck. Here is my adc read function after the last modification I tried.
int readADC(){
ADC1->CR2 |= ADC_CR2_ADON;
delay_i(100);
//select channel zero
//ADC1->SMPR2 |= ADC_SMPR2_SMP0; //239.5 Cycles for channel zero
ADC1->CR2 |= 0x00500000; //START CONVERSION
/*now wait for end of conversion*/
while((ADC1->SR & ADC_SR_EOC)==0); //WHILE IT is not set it mean no conversion done
/*Congratulations Conversion is complete: Now read it*/
ADC1->CR2 &= ~ADC_CR2_ADON;
return ADC1->DR;
}
One thing that I had noticed that during the debugging process the value of ADC1->DR register changes when I do the calibration process. it change from 0x00000000 to 0x00000073
And also I had tried SWSTART (BIT:22) ** in **ADC1->CR2 register as well as EXTTRIG (BIT:20) ** of the **ADC1->CR2 register but results are the same. I also tried enabling SWSTART flag manually in debug process but results are the same. It got cleared immediately which is the indication that conversion is started according to the reference manual which describes this bit as
This bit is set by software to start conversion and cleared by hardware as soon as
conversion starts.
So any I got stuck and have to post it here.
By the way here is the adc_channel_config function.
void adc_channel_config(){
uint32_t tmpreg1 = 0;
/* Get the old register value */
tmpreg1 = ADC1->SMPR2;
/* Clear the old channel sample time */
tmpreg1 &= ~ADC_SMPR2_SMP0;
/* Set the new channel sample time */
tmpreg1 |= ADC_SMPR2_SMP0;
/* Store the new register value */
ADC1->SMPR2 = tmpreg1;
tmpreg1 = ADC1->SQR3;
tmpreg1 &= ~(0x0000001F);
ADC1->SQR3=tmpreg1;
}