aboutsummaryrefslogtreecommitdiffstats
path: root/src/stm32/stm32h7_adc.c
diff options
context:
space:
mode:
authorMatt Baker <baker.matt.j@gmail.com>2021-04-22 13:44:39 -0700
committerKevinOConnor <kevin@koconnor.net>2022-09-15 11:51:26 -0400
commitd9c917b95099617b32dfaca4ae90c9e2dd641fff (patch)
treea6a7adb3fec7d84a5fa0bbb75432a229b1ee7699 /src/stm32/stm32h7_adc.c
parent57b0eb5d43e4324c2c52282925ddc63fc36df783 (diff)
downloadkutter-d9c917b95099617b32dfaca4ae90c9e2dd641fff.tar.gz
kutter-d9c917b95099617b32dfaca4ae90c9e2dd641fff.tar.xz
kutter-d9c917b95099617b32dfaca4ae90c9e2dd641fff.zip
stm32l4: add stm32l412 support with adc,i2c,spi,usb
Signed-off-by: Matt Baker <baker.matt.j@gmail.com>
Diffstat (limited to 'src/stm32/stm32h7_adc.c')
-rw-r--r--src/stm32/stm32h7_adc.c104
1 files changed, 85 insertions, 19 deletions
diff --git a/src/stm32/stm32h7_adc.c b/src/stm32/stm32h7_adc.c
index 00be6209..d873dfb8 100644
--- a/src/stm32/stm32h7_adc.c
+++ b/src/stm32/stm32h7_adc.c
@@ -13,14 +13,36 @@
#include "internal.h" // GPIO
#include "sched.h" // sched_shutdown
+#if CONFIG_MACH_STM32H7
+#define ADCIN_BANK_SIZE (20)
+#define RCC_AHBENR_ADC (RCC->AHB1ENR)
+#define RCC_AHBENR_ADCEN (RCC_AHB1ENR_ADC12EN)
+#define ADC_CKMODE (0b11)
+#define ADC_ATICKS (0b101)
+#define ADC_RES (0b110)
+#define ADC_TS (ADC3_COMMON)
+
// 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)
-#define ADC_ISR_LDORDY_Msk (0x1UL << ADC_ISR_LDORDY_Pos)
-#define ADC_ISR_LDORDY ADC_ISR_LDORDY_Msk
+#define ADC_ISR_LDORDY_Pos (12U)
+#define ADC_ISR_LDORDY_Msk (0x1UL << ADC_ISR_LDORDY_Pos)
+#define ADC_ISR_LDORDY ADC_ISR_LDORDY_Msk
+
+#else // stm32l4
+#define RCC_AHBENR_ADC (RCC->AHB2ENR)
+#define RCC_AHBENR_ADCEN (RCC_AHB2ENR_ADCEN)
+#define ADC_CKMODE (0)
+#define ADC_ATICKS (0b100)
+#define ADC_RES (0b00)
+#define ADC_TS (ADC12_COMMON)
+
+#define OVERSAMPLES (0)
+#define ADC_MEAS_DELAY (10)
+#endif
#define ADC_TEMPERATURE_PIN 0xfe
DECL_ENUMERATION("pin", "ADC_TEMPERATURE", ADC_TEMPERATURE_PIN);
@@ -30,6 +52,7 @@ DECL_CONSTANT("ADC_MAX", 4095);
// GPIOs like A0_C are not covered!
// This always gives the pin connected to the positive channel
static const uint8_t adc_pins[] = {
+#if CONFIG_MACH_STM32H7
// ADC1
0, // PA0_C ADC12_INP0
0, // PA1_C ADC12_INP1
@@ -93,6 +116,27 @@ static const uint8_t adc_pins[] = {
0, // Vbat/4
ADC_TEMPERATURE_PIN,// VSENSE
0, // VREFINT
+#else // stm32l4
+ 0, // vref
+ GPIO('C', 0), // ADC12_IN1 .. 16
+ GPIO('C', 1),
+ GPIO('C', 2),
+ GPIO('C', 3),
+ GPIO('A', 0),
+ GPIO('A', 1),
+ GPIO('A', 2),
+ GPIO('A', 3),
+ GPIO('A', 4),
+ GPIO('A', 5),
+ GPIO('A', 6),
+ GPIO('A', 7),
+ GPIO('C', 4),
+ GPIO('C', 5),
+ GPIO('B', 0),
+ GPIO('B', 1),
+ ADC_TEMPERATURE_PIN, // temp
+ 0, // vbat
+#endif
};
@@ -115,25 +159,29 @@ gpio_adc_setup(uint32_t pin)
// (SYSCLK 480Mhz) /HPRE(2) /CKMODE divider(4) /additional divider(2)
// (ADC clock 30Mhz)
ADC_TypeDef *adc;
- if (chan >= 40){
+#ifdef ADC3
+ if (chan >= 2 * ADCIN_BANK_SIZE){
adc = ADC3;
if (!is_enabled_pclock(ADC3_BASE)) {
enable_pclock(ADC3_BASE);
}
MODIFY_REG(ADC3_COMMON->CCR, ADC_CCR_CKMODE_Msk,
- 0b11 << ADC_CCR_CKMODE_Pos);
- } else if (chan >= 20){
+ ADC_CKMODE << ADC_CCR_CKMODE_Pos);
+ chan -= 2 * ADCIN_BANK_SIZE;
+ } else if (chan >= ADCIN_BANK_SIZE){
adc = ADC2;
- RCC->AHB1ENR |= RCC_AHB1ENR_ADC12EN;
+ RCC_AHBENR_ADC |= RCC_AHBENR_ADCEN;
MODIFY_REG(ADC12_COMMON->CCR, ADC_CCR_CKMODE_Msk,
- 0b11 << ADC_CCR_CKMODE_Pos);
- } else{
+ ADC_CKMODE << ADC_CCR_CKMODE_Pos);
+ chan -= ADCIN_BANK_SIZE;
+ } else
+#endif
+ {
adc = ADC1;
- RCC->AHB1ENR |= RCC_AHB1ENR_ADC12EN;
+ RCC_AHBENR_ADC |= RCC_AHBENR_ADCEN;
MODIFY_REG(ADC12_COMMON->CCR, ADC_CCR_CKMODE_Msk,
- 0b11 << ADC_CCR_CKMODE_Pos);
+ ADC_CKMODE << ADC_CCR_CKMODE_Pos);
}
- chan %= 20;
// Enable the ADC
if (!(adc->CR & ADC_CR_ADEN)){
@@ -142,16 +190,27 @@ gpio_adc_setup(uint32_t pin)
MODIFY_REG(adc->CR, ADC_CR_DEEPPWD_Msk, 0);
// Switch on voltage regulator
adc->CR |= ADC_CR_ADVREGEN;
+#ifdef ADC_ISR_LDORDY
while(!(adc->ISR & ADC_ISR_LDORDY))
;
+#else // stm32l4 lacks ldordy, delay to spec instead
+ uint32_t end = timer_read_time() + timer_from_us(20);
+ while (timer_is_before(timer_read_time(), end))
+ ;
+#endif
+
// Set Boost mode for 25Mhz < ADC clock <= 50Mhz
+#ifdef ADC_CR_BOOST
MODIFY_REG(adc->CR, ADC_CR_BOOST_Msk, 0b11 << ADC_CR_BOOST_Pos);
+#endif
// Calibration
// Set calibration mode to Single ended (not differential)
MODIFY_REG(adc->CR, ADC_CR_ADCALDIF_Msk, 0);
// Enable linearity calibration
+#ifdef ADC_CR_ADCALLIN
MODIFY_REG(adc->CR, ADC_CR_ADCALLIN_Msk, ADC_CR_ADCALLIN);
+#endif
// Start the calibration
MODIFY_REG(adc->CR, ADC_CR_ADCAL_Msk, ADC_CR_ADCAL);
while(adc->CR & ADC_CR_ADCAL)
@@ -160,13 +219,14 @@ gpio_adc_setup(uint32_t pin)
// Enable ADC
// "Clear the ADRDY bit in the ADC_ISR register by writing ‘1’"
adc->ISR |= ADC_ISR_ADRDY;
+ adc->ISR; // Dummy read to make sure write is flushed
adc->CR |= ADC_CR_ADEN;
while(!(adc->ISR & ADC_ISR_ADRDY))
;
// Set 64.5 ADC clock cycles sample time for every channel
// (Reference manual pg.940)
- uint32_t aticks = 0b101;
+ uint32_t aticks = ADC_ATICKS;
// Channel 0-9
adc->SMPR1 = (aticks | (aticks << 3) | (aticks << 6)
| (aticks << 9) | (aticks << 12) | (aticks << 15)
@@ -180,23 +240,29 @@ gpio_adc_setup(uint32_t pin)
// Disable Continuous Mode
MODIFY_REG(adc->CFGR, ADC_CFGR_CONT_Msk, 0);
// Set to 12 bit
- MODIFY_REG(adc->CFGR, ADC_CFGR_RES_Msk, 0b110 << ADC_CFGR_RES_Pos);
+ MODIFY_REG(adc->CFGR, ADC_CFGR_RES_Msk, ADC_RES << ADC_CFGR_RES_Pos);
+#if CONFIG_MACH_STM32H7
// Set hardware oversampling
MODIFY_REG(adc->CFGR2, ADC_CFGR2_ROVSE_Msk, ADC_CFGR2_ROVSE);
MODIFY_REG(adc->CFGR2, ADC_CFGR2_OVSR_Msk,
(OVERSAMPLES - 1) << ADC_CFGR2_OVSR_Pos);
MODIFY_REG(adc->CFGR2, ADC_CFGR2_OVSS_Msk,
OVERSAMPLES_EXPONENT << ADC_CFGR2_OVSS_Pos);
+#else // stm32l4
+ adc->CFGR |= ADC_CFGR_JQDIS | ADC_CFGR_OVRMOD;
+#endif
}
if (pin == ADC_TEMPERATURE_PIN) {
- ADC3_COMMON->CCR |= ADC_CCR_TSEN;
+ ADC_TS->CCR |= ADC_CCR_TSEN;
} else {
gpio_peripheral(pin, GPIO_ANALOG, 0);
}
// Preselect (connect) channel
+#ifdef ADC_PCSEL_PCSEL
adc->PCSEL |= (1 << chan);
+#endif
return (struct gpio_adc){ .adc = adc, .chan = chan };
}
@@ -211,16 +277,16 @@ gpio_adc_sample(struct gpio_adc g)
// 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 << 6))
+ 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);
// Start sample
- adc->SQR1 = (g.chan << 6);
+ 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(1 + 2.3666*OVERSAMPLES);
+ return timer_from_us(ADC_MEAS_DELAY);
}
// Read a value; use only after gpio_adc_sample() returns zero
@@ -239,7 +305,7 @@ gpio_adc_cancel_sample(struct gpio_adc g)
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 << 6))
+ && adc->SQR1 == (g.chan << ADC_SQR1_SQ1_Pos))
gpio_adc_read(g);
irq_restore(flag);
}