stm32: Add support for additional ADC3 ports on stm32f4
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
d3bd4f9622
commit
4ec6db7a87
|
@ -19,7 +19,13 @@ static const uint8_t adc_pins[] = {
|
||||||
GPIO('A', 0), GPIO('A', 1), GPIO('A', 2), GPIO('A', 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('A', 4), GPIO('A', 5), GPIO('A', 6), GPIO('A', 7),
|
||||||
GPIO('B', 0), GPIO('B', 1), GPIO('C', 0), GPIO('C', 1),
|
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
|
#if CONFIG_MACH_STM32F1
|
||||||
|
@ -40,30 +46,42 @@ gpio_adc_setup(uint32_t pin)
|
||||||
break;
|
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
|
// Enable the ADC
|
||||||
if (!is_enabled_pclock(ADC1_BASE)) {
|
if (!is_enabled_pclock(adc_base)) {
|
||||||
enable_pclock(ADC1_BASE);
|
enable_pclock(adc_base);
|
||||||
uint32_t aticks = 3; // 2.5-3.2us (depending on stm32 chip)
|
uint32_t aticks = 3; // 2.5-3.2us (depending on stm32 chip)
|
||||||
ADC1->SMPR1 = (aticks | (aticks << 3) | (aticks << 6) | (aticks << 9)
|
adc->SMPR1 = (aticks | (aticks << 3) | (aticks << 6) | (aticks << 9)
|
||||||
| (aticks << 12) | (aticks << 15) | (aticks << 18)
|
| (aticks << 12) | (aticks << 15) | (aticks << 18)
|
||||||
| (aticks << 21) | (aticks << 24));
|
| (aticks << 21) | (aticks << 24));
|
||||||
ADC1->SMPR2 = (aticks | (aticks << 3) | (aticks << 6) | (aticks << 9)
|
adc->SMPR2 = (aticks | (aticks << 3) | (aticks << 6) | (aticks << 9)
|
||||||
| (aticks << 12) | (aticks << 15) | (aticks << 18)
|
| (aticks << 12) | (aticks << 15) | (aticks << 18)
|
||||||
| (aticks << 21) | (aticks << 24) | (aticks << 27));
|
| (aticks << 21) | (aticks << 24) | (aticks << 27));
|
||||||
ADC1->CR2 = CR2_FLAGS;
|
adc->CR2 = CR2_FLAGS;
|
||||||
|
|
||||||
#if CONFIG_MACH_STM32F1
|
#if CONFIG_MACH_STM32F1
|
||||||
// Perform calibration
|
// Perform calibration
|
||||||
udelay(timer_from_us(1));
|
udelay(timer_from_us(1));
|
||||||
ADC1->CR2 = ADC_CR2_CAL | CR2_FLAGS;
|
adc->CR2 = ADC_CR2_CAL | CR2_FLAGS;
|
||||||
while (ADC1->CR2 & ADC_CR2_CAL)
|
while (adc->CR2 & ADC_CR2_CAL)
|
||||||
;
|
;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
gpio_peripheral(pin, GPIO_ANALOG, 0);
|
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
|
// Try to sample a value. Returns zero if sample ready, otherwise
|
||||||
|
@ -72,17 +90,18 @@ gpio_adc_setup(uint32_t pin)
|
||||||
uint32_t
|
uint32_t
|
||||||
gpio_adc_sample(struct gpio_adc g)
|
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_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
|
// Conversion still in progress or busy on another channel
|
||||||
goto need_delay;
|
goto need_delay;
|
||||||
// Conversion ready
|
// Conversion ready
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Start sample
|
// Start sample
|
||||||
ADC1->SQR3 = g.chan;
|
adc->SQR3 = g.chan;
|
||||||
ADC1->CR2 = ADC_CR2_SWSTART | CR2_FLAGS;
|
adc->CR2 = ADC_CR2_SWSTART | CR2_FLAGS;
|
||||||
|
|
||||||
need_delay:
|
need_delay:
|
||||||
return timer_from_us(10);
|
return timer_from_us(10);
|
||||||
|
@ -92,16 +111,18 @@ need_delay:
|
||||||
uint16_t
|
uint16_t
|
||||||
gpio_adc_read(struct gpio_adc g)
|
gpio_adc_read(struct gpio_adc g)
|
||||||
{
|
{
|
||||||
ADC1->SR = ~ADC_SR_STRT;
|
ADC_TypeDef *adc = g.adc;
|
||||||
return ADC1->DR;
|
adc->SR = ~ADC_SR_STRT;
|
||||||
|
return adc->DR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel a sample that may have been started with gpio_adc_sample()
|
// Cancel a sample that may have been started with gpio_adc_sample()
|
||||||
void
|
void
|
||||||
gpio_adc_cancel_sample(struct gpio_adc g)
|
gpio_adc_cancel_sample(struct gpio_adc g)
|
||||||
{
|
{
|
||||||
|
ADC_TypeDef *adc = g.adc;
|
||||||
irqstatus_t flag = irq_save();
|
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);
|
gpio_adc_read(g);
|
||||||
irq_restore(flag);
|
irq_restore(flag);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
uint8_t gpio_in_read(struct gpio_in g);
|
||||||
|
|
||||||
struct gpio_adc {
|
struct gpio_adc {
|
||||||
|
void *adc;
|
||||||
uint32_t chan;
|
uint32_t chan;
|
||||||
};
|
};
|
||||||
struct gpio_adc gpio_adc_setup(uint32_t pin);
|
struct gpio_adc gpio_adc_setup(uint32_t pin);
|
||||||
|
|
Loading…
Reference in New Issue