cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H723ZGT6 ADC stuck after first sample

n719z
Associate

I'm trying, unsuccessfully, to get a simplest single-channel single-ended polling-the-ADC example going on the nucleo h723 eval board.

At first I started bare-metal in assembler from the datasheet, but couldn't get the second ADC sample to fire no matter what register gymnastics I did (the first ADSTART puts some bits in the DR, I figure that did something to the analog input).

Then, figuring I'm still not setting up clocks right or something, I reverted to STM32CubeIDE and followed various HAL tutorials such as this one; same outcome.

https://www.youtube.com/watch?v=6uiO68pdjZA

This particular ADC seems more involved than the simple ones usually covered in tutorials. Can anyone point me to an example of repeated single-shot acquisition with polling or interrupts that actually works on the 723ZGT6 part?

(Bonus points if it can actually run at the claimed 3.5 MS/s...)

1 ACCEPTED SOLUTION

Accepted Solutions
Hl_st
ST Employee

Hello,

there is one simple example of using ADC. This code initialize ADC with input as PA0 and than conversing this input in infinite loop :

/* Enable GPIOA peripheral clock */
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;

/* Peripheral ADC clock enable */
RCC->APBENR2 |= RCC_APBENR2_ADCEN;

/* Enable ADC internal voltage regulator */
ADC1->CR |= ADC_CR_ADVREGEN;
int i = 160000;
while(i > 0) i--;

/* Configure CHNNEL_0 (PA0) as ADC input */
ADC1->CHSELR |= ADC_CHSELR_CHSEL0;

/* ADC calibration */
ADC1->CR |= ADC_CR_ADCAL;
while ((ADC1->CR & ADC_CR_ADCAL) == (ADC_CR_ADCAL));

/* ADC Enable */
ADC1->CR |= ADC_CR_ADEN;

/* Infinite loop */
while (1)
{
/* Start conversion */
MODIFY_REG(ADC1->CR, (ADC_CR_ADSTP | ADC_CR_ADSTART), ADC_CR_ADSTART);
/* Wait for end of conversion */
while ((ADC1->ISR & ADC_ISR_EOC) != ADC_ISR_EOC);
/* Stop conversion */
MODIFY_REG(ADC1->CR, (ADC_CR_ADSTP | ADC_CR_ADSTART), ADC_CR_ADSTP);

/* Clear flag end of conversion */
ADC1->ISR = ADC_ISR_EOC;
/* Read converted data */
int result = ADC1->DR;
}

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.

View solution in original post

3 REPLIES 3
Hl_st
ST Employee

Hello,

there is one simple example of using ADC. This code initialize ADC with input as PA0 and than conversing this input in infinite loop :

/* Enable GPIOA peripheral clock */
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;

/* Peripheral ADC clock enable */
RCC->APBENR2 |= RCC_APBENR2_ADCEN;

/* Enable ADC internal voltage regulator */
ADC1->CR |= ADC_CR_ADVREGEN;
int i = 160000;
while(i > 0) i--;

/* Configure CHNNEL_0 (PA0) as ADC input */
ADC1->CHSELR |= ADC_CHSELR_CHSEL0;

/* ADC calibration */
ADC1->CR |= ADC_CR_ADCAL;
while ((ADC1->CR & ADC_CR_ADCAL) == (ADC_CR_ADCAL));

/* ADC Enable */
ADC1->CR |= ADC_CR_ADEN;

/* Infinite loop */
while (1)
{
/* Start conversion */
MODIFY_REG(ADC1->CR, (ADC_CR_ADSTP | ADC_CR_ADSTART), ADC_CR_ADSTART);
/* Wait for end of conversion */
while ((ADC1->ISR & ADC_ISR_EOC) != ADC_ISR_EOC);
/* Stop conversion */
MODIFY_REG(ADC1->CR, (ADC_CR_ADSTP | ADC_CR_ADSTART), ADC_CR_ADSTP);

/* Clear flag end of conversion */
ADC1->ISR = ADC_ISR_EOC;
/* Read converted data */
int result = ADC1->DR;
}

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.

n719z
Associate

Aaand there it is, the key... Thank you!

 

So the missing piece, then, is that one must STOP the conversion before starting the next one. The TRM wording implies that simply reading the DR clears the EOC bit, which obviously doesn't reset the state machine to a truly ready state despite the ready bit reading as one. We can debate this point, but shouldn't the HAL already do this for me the dumb user in HAL_ADC_GetValue(), and/or HAL_ADC_Start() for that matter, if single-conversion mode is set?

The conversion don´t have to be stopped if the conversion was correctly done. You are right that if you read DR, the EOC is cleared by hardware so it is not necessary to clear it by software so it should also works if you try HAL library:

/* Calibrate ADC */
HAL_ADCEx_Calibration_Start(&hadc1);


while (1)
{
/* Start ADC conversion */
HAL_ADC_Start(&hadc1);

/* Wait for end of conversion */
HAL_ADC_PollForConversion(&hadc1, 100);

/* Read converted data */
int result = HAL_ADC_GetValue(&hadc1);
}

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.