From be5896f5b33fa913163048d04e1f0fa391238f0f Mon Sep 17 00:00:00 2001 From: dongie Date: Thu, 1 May 2014 19:03:58 +0900 Subject: [PATCH] updated ADC driver to use more of available inputs, as well as made input selection more sane --- src/drv_adc.c | 88 +++++++++++++++++++++++++++++++++------------------ src/drv_adc.h | 9 ++++-- 2 files changed, 63 insertions(+), 34 deletions(-) diff --git a/src/drv_adc.c b/src/drv_adc.c index 022cc74619..98da373a76 100755 --- a/src/drv_adc.c +++ b/src/drv_adc.c @@ -1,45 +1,71 @@ #include "board.h" -#define ADC_BATTERY 0 -#define ADC_CURRENT 1 +// Driver for STM32F103CB onboard ADC +// VBAT is connected to PA4 (ADC1_IN4) with 10k:1k divider +// rev.5 hardware has PA5 (ADC1_IN5) on breakout pad on bottom of board +// Additional channel can be stolen from RC_CH2 (PA1, ADC1_IN1) or +// RC_CH8 (PB1, ADC1_IN9) by using set power_adc_channel=1|9 -// static volatile uint16_t adc1Ch4Value = 0; -static volatile uint16_t adcValues[2]; +typedef struct adc_config_t { + uint8_t adcChannel; // ADC1_INxx channel number + uint8_t dmaIndex; // index into DMA buffer in case of sparse channels +} adc_config_t; + +static adc_config_t adcConfig[ADC_CHANNEL_MAX]; +static volatile uint16_t adcValues[ADC_CHANNEL_MAX]; void adcInit(drv_adc_config_t *init) { - ADC_InitTypeDef ADC_InitStructure; - DMA_InitTypeDef DMA_InitStructure; - bool multiChannel = init->powerAdcChannel > 0; + ADC_InitTypeDef adc; + DMA_InitTypeDef dma; + int numChannels = 1, i; - // ADC assumes all the GPIO was already placed in 'AIN' mode + // configure always-present battery index (ADC4) + adcConfig[ADC_BATTERY].adcChannel = ADC_Channel_4; + adcConfig[ADC_BATTERY].dmaIndex = numChannels - 1; + + // optional ADC5 input on rev.5 hardware + if (hse_value == 12000000) { + numChannels++; + adcConfig[ADC_EXTERNAL1].adcChannel = ADC_Channel_5; + adcConfig[ADC_EXTERNAL1].dmaIndex = numChannels - 1; + } + // another channel can be stolen from PWM for current measurement or other things + if (init->powerAdcChannel > 0) { + numChannels++; + adcConfig[ADC_EXTERNAL2].adcChannel = init->powerAdcChannel; + adcConfig[ADC_EXTERNAL2].dmaIndex = numChannels - 1; + } + + // ADC driver assumes all the GPIO was already placed in 'AIN' mode DMA_DeInit(DMA1_Channel1); - DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; - DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adcValues; - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; - DMA_InitStructure.DMA_BufferSize = multiChannel ? 2 : 1; - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = multiChannel ? DMA_MemoryInc_Enable : DMA_MemoryInc_Disable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; - DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; - DMA_InitStructure.DMA_Priority = DMA_Priority_High; - DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; - DMA_Init(DMA1_Channel1, &DMA_InitStructure); - /* Enable DMA1 channel1 */ + dma.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; + dma.DMA_MemoryBaseAddr = (uint32_t)adcValues; + dma.DMA_DIR = DMA_DIR_PeripheralSRC; + dma.DMA_BufferSize = numChannels; + dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + dma.DMA_MemoryInc = numChannels > 1 ? DMA_MemoryInc_Enable : DMA_MemoryInc_Disable; + dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; + dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; + dma.DMA_Mode = DMA_Mode_Circular; + dma.DMA_Priority = DMA_Priority_High; + dma.DMA_M2M = DMA_M2M_Disable; + DMA_Init(DMA1_Channel1, &dma); DMA_Cmd(DMA1_Channel1, ENABLE); - ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; - ADC_InitStructure.ADC_ScanConvMode = multiChannel ? ENABLE : DISABLE; - ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; - ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; - ADC_InitStructure.ADC_NbrOfChannel = multiChannel ? 2 : 1; - ADC_Init(ADC1, &ADC_InitStructure); + adc.ADC_Mode = ADC_Mode_Independent; + adc.ADC_ScanConvMode = numChannels > 1 ? ENABLE : DISABLE; + adc.ADC_ContinuousConvMode = ENABLE; + adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; + adc.ADC_DataAlign = ADC_DataAlign_Right; + adc.ADC_NbrOfChannel = numChannels; + ADC_Init(ADC1, &adc); + // fixed ADC4 ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_28Cycles5); - if (multiChannel) - ADC_RegularChannelConfig(ADC1, init->powerAdcChannel, 2, ADC_SampleTime_28Cycles5); + // configure any additional ADC channels (2 + n) + for (i = 1; i < numChannels; i++) + ADC_RegularChannelConfig(ADC1, adcConfig[i].adcChannel, i + 1, ADC_SampleTime_28Cycles5); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); @@ -56,5 +82,5 @@ void adcInit(drv_adc_config_t *init) uint16_t adcGetChannel(uint8_t channel) { - return adcValues[channel]; + return adcValues[adcConfig[channel].dmaIndex]; } diff --git a/src/drv_adc.h b/src/drv_adc.h index e33d6923f7..ad43533076 100755 --- a/src/drv_adc.h +++ b/src/drv_adc.h @@ -1,13 +1,16 @@ #pragma once -#define ADC_BATTERY 0 -#define ADC_CURRENT 1 +typedef enum { + ADC_BATTERY = 0, + ADC_EXTERNAL1 = 1, + ADC_EXTERNAL2 = 2, + ADC_CHANNEL_MAX = 3 +} AdcChannel; typedef struct drv_adc_config_t { uint8_t powerAdcChannel; // which channel used for current monitor, allowed PA1, PB1 (ADC_Channel_1, ADC_Channel_9) } drv_adc_config_t; - void adcInit(drv_adc_config_t *init); uint16_t adcGetChannel(uint8_t channel); #ifdef FY90Q