cancel
Showing results for 
Search instead for 
Did you mean: 

Nucleo-STM32f030 ADC setup Issues This code only works when I'm debugging step by step. Otherwise, it always sends ADEN low again, which should not happen!!

OSell.1
Associate II

This code only works when I'm debugging step by step. Otherwise, it always sends ADEN low again, which should not happen!! (Correct sequence: ADEN goes high then ADRDY goes high and both stay high...) (Note both ADEN and ADRDY are low before line 54 of pa1_adc_init() function) 

0693W00000YAXrPQAX.pngThe reference manual says...

0693W00000YAXsWQAX.pngMaybe I need this "time-out management" but I don't have a watchdog timer enabled so unless I'm understanding incorrectly, I don't think that's the issue.

The issue occurs on lines 56 and 57 of my pa1_adc_init () function below.

#include "stm32f0xx.h"
#include "adc.h"
#include "uart.h"
 
int ADC_VALUE = 0; // Global variable to store the ADC value (only 16 bits are useful)
volatile int PA1_ADC_VALUE; // Global variable to store the PA1 ADC value (only 16 bits are useful)
volatile int TEMPSNS_ADCVALUE; // Global variable to store the Internal Temp Sensor ADC value (only 16 bits are useful)
 
 
int main (void)
{
	//int ADC_VALUE;
	uart2_tx_init();
	pa1_adc_init();
	adc_config();
	start_adc_single_conversion_mode();
	ADC_VALUE = adc_read();
	uart2_write(ADC_VALUE);
 
	while(1)
		{
		}
}
void pa1_adc_init(void)
{
	/////////// Enable Clock Access to the ADC //////////
	/* Enable Clock Access to GPIOA */
	RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
	/* Enable clock access to the ADC */ //Orlando Added this line
	RCC->APB2ENR |= RCC_APB2ENR_ADCEN;
	RCC->CR2 |= RCC_CR2_HSI14ON;
	while ((RCC->CR2 & RCC_CR2_HSI14RDY) == 0)
	{
		__NOP();
	}
 
	////////// Turn off the ADC ///////////////
	if ((ADC1->ISR & ADC_ISR_ADRDY) != 0) // An ADC conversion is occurring
	{
		ADC1->CR |= ADC_CR_ADSTP; // Stop the conversion
		do
		{
			__NOP(); // Nothing
		}while((ADC1->CR & ADC_CR_ADSTP) != 0); // Wait until conversion has stopped
		ADC1->CR |= ADC_CR_ADDIS; // Disable the ADC
	}
 
	/* Ensure that ADEN=0 and DMAEN=0 (only if ADC is enabled and there is no pending disable) */
	if (((ADC1->CR & ADC_CR_ADEN)==1)&&((ADC1->CR & ADC_CR_ADDIS)==0))
	{
		ADC1->CR |= ADC_CR_ADDIS;
		while((ADC1->CR & ADC_CR_ADEN) != 0){ //Wait until ADC Enable = 0
			__NOP(); // Wait and Do nothing
		}
		ADC1->CFGR1 &= ~( ADC_CFGR1_DMAEN);
	}
 
	/* Calibrate the ADC */
	ADC1->CR |= ADC_CR_ADCAL;
	/* Wait for ADC Calibration to finish */
	while(!(ADC1->CR & ADC_CR_ADCAL)){
		__NOP(); // Wait and Do nothing
	}
	/* Wait 4 clock cycles after calibration	 */
	__NOP(); // Wait and Do nothing
	__NOP(); // Wait and Do nothing
	__NOP(); // Wait and Do nothing
	__NOP(); // Wait and Do nothing
 
	//////////START SEQUENCE///////////////
	/* Clear ADRDY bit by programming to 1 (Perhaps I need a delay)*/
	if((ADC1->ISR & ADC_ISR_ADRDY) != 0)
	{
	ADC1->ISR |= ADC_ISR_ADRDY;
	__NOP(); // Wait 1 clock cycle (might be unnecessary)
	}
 
	/* Set ADEN in ADC_CR Register */
	ADC1->CR |= ADC_CR_ADEN;
	while((ADC1->ISR & ADC_ISR_ADRDY)== 0)
	{
		__NOP(); // Do Nothing 
	}
	if ((ADC1->CR & ADC_CR_ADEN)==0)
	{
		ADC1->CR |= ADC_CR_ADEN;
	}
}

Any help is much appreciated! 🙂

1 ACCEPTED SOLUTION

Accepted Solutions

> while(!(ADC1->CR & ADC_CR_ADCAL)){

> __NOP(); // Wait and Do nothing

> }

This is incorrect: as ADCAL is nonzero after setting it - calibration is ongoing - program never enters this loop and proceeds to enabling ADC through ADEN - and this fails, as hardware does not allow to set ADEN while calibration is ongoing.

Look at the example in RM, which is:

ADC1->CR |= ADC_CR_ADCAL; /* (4) */

while ((ADC1->CR & ADC_CR_ADCAL) != 0) /* (5) */

{

/* For robust implementation, add here time-out management */

}

JW

View solution in original post

7 REPLIES 7
Semer CHERNI
ST Employee

Hello @OSell.1​ 

First let me thank you for posting.

Are you using different Build settings for the two test scenario (the step by step debug and the Run).

Could you check the optimization level?

Finally, could you share a minimalistic project which contain the described behavior.

KR,

Semer.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

OSell.1
Associate II

Hi @Semer CHERNI​ ,

I am not using 2 different build settings for the 2 scenarios. In both I am using the debug perspective. The only difference is where I set the breakpoints. (Line 55 vs line 65)

My optimization level is set at the default (No optimization)

0693W00000YAqiuQAD.jpg 

I've attached the project below.

Thank you for taking the time to look at this.

Regards,

O

OSell.1
Associate II

Sorry I forgot to attach some chip header files. Please use this file instead.

> while(!(ADC1->CR & ADC_CR_ADCAL)){

> __NOP(); // Wait and Do nothing

> }

This is incorrect: as ADCAL is nonzero after setting it - calibration is ongoing - program never enters this loop and proceeds to enabling ADC through ADEN - and this fails, as hardware does not allow to set ADEN while calibration is ongoing.

Look at the example in RM, which is:

ADC1->CR |= ADC_CR_ADCAL; /* (4) */

while ((ADC1->CR & ADC_CR_ADCAL) != 0) /* (5) */

{

/* For robust implementation, add here time-out management */

}

JW

KnarfB
Principal III

Note that inspecting ADC registers with the debugger can be intrusive. Some bits are rc_w1 (read clear), reading ADC_DR clear EOC and so on..

hth

KnarfB

KnarfB
Principal III

Even if you want to go bare metal: bringing-up peripherals in basic scenarios simply works with HAL and one can learn from it about register settings and improve and strip down the code later on 🙂

KnarfB

OSell.1
Associate II

Thank you all! @Community member​ that was the issue!