aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2022-11-25 13:20:16 -0500
committerKevin O'Connor <kevin@koconnor.net>2022-12-12 23:46:49 -0500
commit69f76b3b66ba72d6a42f93a829304b1a802dbf02 (patch)
tree0e2ba1355fe7162657ed7a4efcaf8fe9798667d0
parent201f715b55ca3626d31cd98a826053f4be861067 (diff)
downloadkutter-69f76b3b66ba72d6a42f93a829304b1a802dbf02.tar.gz
kutter-69f76b3b66ba72d6a42f93a829304b1a802dbf02.tar.xz
kutter-69f76b3b66ba72d6a42f93a829304b1a802dbf02.zip
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>
-rw-r--r--src/stm32/stm32h7_adc.c37
1 files changed, 18 insertions, 19 deletions
diff --git a/src/stm32/stm32h7_adc.c b/src/stm32/stm32h7_adc.c
index 08d68fa2..8a9bb318 100644
--- a/src/stm32/stm32h7_adc.c
+++ b/src/stm32/stm32h7_adc.c
@@ -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);
}