Skip to content

Commit

Permalink
cpu/stm32/periph_adc: fix register access
Browse files Browse the repository at this point in the history
The register access to SMPR1/SMPR2 was incorrect in three aspects:

1. For channels < 10, SMPR1 was cleared but SMPR2 should have been
   cleared
2. The code was not thread-safe
3. An unneeded write was issued. (The compiler won't combine the
   in-place bitwise operations into a single read-modify-write
   sequence on `volatile` memory.)

Fixes #20261
  • Loading branch information
maribu committed Feb 8, 2024
1 parent e2e5c3a commit 4ed287c
Showing 1 changed file with 12 additions and 5 deletions.
17 changes: 12 additions & 5 deletions cpu/stm32/periph/adc_f4_f7.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
*/

#include "cpu.h"
#include "irq.h"
#include "mutex.h"
#include "periph/adc.h"
#include "periph_conf.h"
#include "periph/vbat.h"
#include "periph_conf.h"

/**
* @brief Maximum allowed ADC clock speed
Expand Down Expand Up @@ -100,14 +101,20 @@ int adc_init(adc_t line)
}
ADC->CCR = ((clk_div / 2) - 1) << 16;
/* set sampling time to the maximum */
unsigned irq_state = irq_disable();
if (adc_config[line].chan >= 10) {
dev(line)->SMPR1 &= ~(MAX_ADC_SMP << (3 * (adc_config[line].chan - 10)));
dev(line)->SMPR1 |= MAX_ADC_SMP << (3 * (adc_config[line].chan - 10));
uint32_t smpr1 = dev(line)->SMPR1;
smpr1 &= ~(MAX_ADC_SMP << (3 * (adc_config[line].chan - 10)));
smpr1 |= MAX_ADC_SMP << (3 * (adc_config[line].chan - 10));
dev(line)->SMPR1 = smpr1;
}
else {
dev(line)->SMPR1 &= ~(MAX_ADC_SMP << (3 * adc_config[line].chan));
dev(line)->SMPR2 |= MAX_ADC_SMP << (3 * adc_config[line].chan);
uint32_t smpr2 = dev(line)->SMPR2;
smpr2 &= ~(MAX_ADC_SMP << (3 * adc_config[line].chan));
smpr2 |= MAX_ADC_SMP << (3 * adc_config[line].chan);
dev(line)->SMPR2 = smpr2;
}
irq_restore(irq_state);
/* free the device again */
done(line);
return 0;
Expand Down

0 comments on commit 4ed287c

Please sign in to comment.