stm32: Apply race fixes to stm32h7_adc.c

Improve handling of race conditions with hardware updates.  This is
the same changes applied to stm32f0_adc.c in commit 88325b6c.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2022-11-25 13:20:16 -05:00
parent 201f715b55
commit 69f76b3b66
1 changed files with 18 additions and 19 deletions

View File

@ -28,7 +28,6 @@
// Number of samples is 2^OVERSAMPLES_EXPONENT (exponent can be 0-10)
#define OVERSAMPLES_EXPONENT 3
#define OVERSAMPLES (1 << OVERSAMPLES_EXPONENT)
#define ADC_MEAS_DELAY (1 + 2.3666*OVERSAMPLES)
// LDORDY registers are missing from CMSIS (only available on revision V!)
#define ADC_ISR_LDORDY_Pos (12U)
@ -44,7 +43,6 @@
#define ADC_TS (ADC12_COMMON)
#define OVERSAMPLES (0)
#define ADC_MEAS_DELAY (10)
#elif CONFIG_MACH_STM32G4
#define ADCIN_BANK_SIZE (19)
@ -57,7 +55,6 @@
#define ADC_CCR_TSEN (ADC_CCR_VSENSESEL)
#define OVERSAMPLES (0)
#define ADC_MEAS_DELAY (10)
#endif
#define ADC_TEMPERATURE_PIN 0xfe
@ -361,20 +358,19 @@ uint32_t
gpio_adc_sample(struct gpio_adc g)
{
ADC_TypeDef *adc = g.adc;
// Conversion ready
// EOC flag is cleared by hardware when reading DR
// the channel condition only works if this ist the only channel
// on the sequence and length set to 1 (ADC_SQR1_L = 0000)
if (adc->ISR & ADC_ISR_EOC && adc->SQR1 == (g.chan << ADC_SQR1_SQ1_Pos))
return 0;
// Conversion started but not ready or wrong channel
if (adc->CR & ADC_CR_ADSTART)
return timer_from_us(10);
uint32_t cr = adc->CR;
if (cr & ADC_CR_ADSTART)
goto need_delay;
if (adc->ISR & ADC_ISR_EOC) {
if (adc->SQR1 == (g.chan << ADC_SQR1_SQ1_Pos))
return 0;
goto need_delay;
}
// Start sample
adc->SQR1 = (g.chan << ADC_SQR1_SQ1_Pos);
adc->CR |= ADC_CR_ADSTART;
// Should take 2.3666us, add 1us for clock synchronisation etc.
return timer_from_us(ADC_MEAS_DELAY);
adc->CR = cr | ADC_CR_ADSTART;
need_delay:
return timer_from_us(20);
}
// Read a value; use only after gpio_adc_sample() returns zero
@ -391,9 +387,12 @@ gpio_adc_cancel_sample(struct gpio_adc g)
{
ADC_TypeDef *adc = g.adc;
irqstatus_t flag = irq_save();
// ADSTART is not as long true as SR_STRT on stm32f4
if ((adc->CR & ADC_CR_ADSTART || adc->ISR & ADC_ISR_EOC)
&& adc->SQR1 == (g.chan << ADC_SQR1_SQ1_Pos))
gpio_adc_read(g);
if (adc->SQR1 == (g.chan << ADC_SQR1_SQ1_Pos)) {
uint32_t cr = adc->CR;
if (cr & ADC_CR_ADSTART)
adc->CR = (cr & ~ADC_CR_ADSTART) | ADC_CR_ADSTP;
if (adc->ISR & ADC_ISR_EOC)
gpio_adc_read(g);
}
irq_restore(flag);
}