From 4ec6db7a87b2f0b0e033b87ca912818dc84cbe2f Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Thu, 15 Aug 2019 22:48:07 -0400 Subject: [PATCH] stm32: Add support for additional ADC3 ports on stm32f4 Signed-off-by: Kevin O'Connor --- src/stm32/adc.c | 61 ++++++++++++++++++++++++++++++++---------------- src/stm32/gpio.h | 1 + 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/stm32/adc.c b/src/stm32/adc.c index b24b9e06..b6aa14b8 100644 --- a/src/stm32/adc.c +++ b/src/stm32/adc.c @@ -19,7 +19,13 @@ static const uint8_t adc_pins[] = { 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('B', 0), GPIO('B', 1), GPIO('C', 0), GPIO('C', 1), - GPIO('C', 2), GPIO('C', 3), GPIO('C', 4), GPIO('C', 5) + GPIO('C', 2), GPIO('C', 3), GPIO('C', 4), GPIO('C', 5), +#if CONFIG_MACH_STM32F4 + 0x00, 0x00, 0x00, 0x00, + GPIO('F', 6), GPIO('F', 7), GPIO('F', 8), GPIO('F', 9), + GPIO('F', 10), GPIO('F', 3), 0x00, 0x00, + 0x00, 0x00, GPIO('F', 4), GPIO('F', 5), +#endif }; #if CONFIG_MACH_STM32F1 @@ -40,30 +46,42 @@ gpio_adc_setup(uint32_t pin) break; } + // Determine which ADC block to use + ADC_TypeDef *adc = ADC1; + uint32_t adc_base = ADC1_BASE; +#if CONFIG_MACH_STM32F4 + if (chan >= 16) { + // On the STM32F4, some ADC channels are only available from ADC3 + adc = ADC3; + adc_base += 0x800; + chan -= 16; + } +#endif + // Enable the ADC - if (!is_enabled_pclock(ADC1_BASE)) { - enable_pclock(ADC1_BASE); + if (!is_enabled_pclock(adc_base)) { + enable_pclock(adc_base); uint32_t aticks = 3; // 2.5-3.2us (depending on stm32 chip) - ADC1->SMPR1 = (aticks | (aticks << 3) | (aticks << 6) | (aticks << 9) - | (aticks << 12) | (aticks << 15) | (aticks << 18) - | (aticks << 21) | (aticks << 24)); - ADC1->SMPR2 = (aticks | (aticks << 3) | (aticks << 6) | (aticks << 9) - | (aticks << 12) | (aticks << 15) | (aticks << 18) - | (aticks << 21) | (aticks << 24) | (aticks << 27)); - ADC1->CR2 = CR2_FLAGS; + adc->SMPR1 = (aticks | (aticks << 3) | (aticks << 6) | (aticks << 9) + | (aticks << 12) | (aticks << 15) | (aticks << 18) + | (aticks << 21) | (aticks << 24)); + adc->SMPR2 = (aticks | (aticks << 3) | (aticks << 6) | (aticks << 9) + | (aticks << 12) | (aticks << 15) | (aticks << 18) + | (aticks << 21) | (aticks << 24) | (aticks << 27)); + adc->CR2 = CR2_FLAGS; #if CONFIG_MACH_STM32F1 // Perform calibration udelay(timer_from_us(1)); - ADC1->CR2 = ADC_CR2_CAL | CR2_FLAGS; - while (ADC1->CR2 & ADC_CR2_CAL) + adc->CR2 = ADC_CR2_CAL | CR2_FLAGS; + while (adc->CR2 & ADC_CR2_CAL) ; #endif } gpio_peripheral(pin, GPIO_ANALOG, 0); - return (struct gpio_adc){ .chan = chan }; + return (struct gpio_adc){ .adc = adc, .chan = chan }; } // Try to sample a value. Returns zero if sample ready, otherwise @@ -72,17 +90,18 @@ gpio_adc_setup(uint32_t pin) uint32_t gpio_adc_sample(struct gpio_adc g) { - uint32_t sr = ADC1->SR; + ADC_TypeDef *adc = g.adc; + uint32_t sr = adc->SR; if (sr & ADC_SR_STRT) { - if (!(sr & ADC_SR_EOC) || ADC1->SQR3 != g.chan) + if (!(sr & ADC_SR_EOC) || adc->SQR3 != g.chan) // Conversion still in progress or busy on another channel goto need_delay; // Conversion ready return 0; } // Start sample - ADC1->SQR3 = g.chan; - ADC1->CR2 = ADC_CR2_SWSTART | CR2_FLAGS; + adc->SQR3 = g.chan; + adc->CR2 = ADC_CR2_SWSTART | CR2_FLAGS; need_delay: return timer_from_us(10); @@ -92,16 +111,18 @@ need_delay: uint16_t gpio_adc_read(struct gpio_adc g) { - ADC1->SR = ~ADC_SR_STRT; - return ADC1->DR; + ADC_TypeDef *adc = g.adc; + adc->SR = ~ADC_SR_STRT; + return adc->DR; } // Cancel a sample that may have been started with gpio_adc_sample() void gpio_adc_cancel_sample(struct gpio_adc g) { + ADC_TypeDef *adc = g.adc; irqstatus_t flag = irq_save(); - if (ADC1->SR & ADC_SR_STRT && ADC1->SQR3 == g.chan) + if (adc->SR & ADC_SR_STRT && adc->SQR3 == g.chan) gpio_adc_read(g); irq_restore(flag); } diff --git a/src/stm32/gpio.h b/src/stm32/gpio.h index c7602504..ad8a9979 100644 --- a/src/stm32/gpio.h +++ b/src/stm32/gpio.h @@ -22,6 +22,7 @@ void gpio_in_reset(struct gpio_in g, int32_t pull_up); uint8_t gpio_in_read(struct gpio_in g); struct gpio_adc { + void *adc; uint32_t chan; }; struct gpio_adc gpio_adc_setup(uint32_t pin);