2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_ADC ADC Functions
6 * @brief STM32F4xx ADC PIOS interface
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
11 * @author Michael Smith Copyright (C) 2011.
12 * @brief Analog to Digital converstion routines
13 * @see The GNU Public License (GPL) Version 3
14 *****************************************************************************/
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 * @note This is a stripped-down ADC driver intended primarily for sampling
33 * voltage and current values. Samples are averaged over the period between
34 * fetches so that relatively accurate measurements can be obtained without
35 * forcing higher-level logic to poll aggressively.
37 * @todo This module needs more work to be more generally useful. It should
38 * almost certainly grow callback support so that e.g. voltage and current readings
39 * can be shipped out for coulomb counting purposes. The F1xx interface presumes
40 * use with analog sensors, but that implementation largely dominates the ADC
41 * resources. Rather than commit to a new API without a defined use case, we
42 * should stick to our lightweight subset until we have a better idea of what's needed.
47 #ifdef PIOS_INCLUDE_ADC
49 #include <pios_adc_priv.h>
52 #if !defined(PIOS_ADC_MAX_SAMPLES)
53 #define PIOS_ADC_MAX_SAMPLES 0
56 #if !defined(PIOS_ADC_MAX_OVERSAMPLING)
57 #define PIOS_ADC_MAX_OVERSAMPLING 0
60 #if !defined(PIOS_ADC_USE_ADC2)
61 #define PIOS_ADC_USE_ADC2 0
64 #if !defined(PIOS_ADC_NUM_CHANNELS)
65 #define PIOS_ADC_NUM_CHANNELS 0
69 enum pios_adc_dev_magic
{
70 PIOS_ADC_DEV_MAGIC
= 0x58375124,
74 const struct pios_adc_cfg
*cfg
;
75 ADCCallback callback_function
;
76 #if defined(PIOS_INCLUDE_FREERTOS)
77 xQueueHandle data_queue
;
79 volatile int16_t *valid_data_buffer
;
80 volatile uint8_t adc_oversample
;
81 uint8_t dma_block_size
;
82 uint16_t dma_half_buffer_size
;
83 // int16_t fir_coeffs[PIOS_ADC_MAX_SAMPLES+1] __attribute__ ((aligned(4)));
84 // volatile int16_t raw_data_buffer[PIOS_ADC_MAX_SAMPLES] __attribute__ ((aligned(4)));
85 // float downsampled_buffer[PIOS_ADC_NUM_CHANNELS] __attribute__ ((aligned(4)));
86 enum pios_adc_dev_magic magic
;
89 struct pios_adc_dev
*pios_adc_dev
;
92 void PIOS_ADC_downsample_data();
93 static struct pios_adc_dev
*PIOS_ADC_Allocate();
94 static bool PIOS_ADC_validate(struct pios_adc_dev
*);
96 #if defined(PIOS_INCLUDE_ADC)
97 static void init_pins(void);
98 static void init_dma(void);
99 static void init_adc(void);
102 struct pios_adc_pin_config
{
109 struct adc_accumulator
{
110 uint32_t accumulator
;
114 #if defined(PIOS_INCLUDE_ADC)
115 static const struct pios_adc_pin_config config
[] = PIOS_DMA_PIN_CONFIG
;
116 #define PIOS_ADC_NUM_PINS (sizeof(config) / sizeof(config[0]))
118 static struct adc_accumulator accumulator
[PIOS_ADC_NUM_PINS
];
120 // Two buffers here for double buffering
121 static uint16_t adc_raw_buffer
[2][PIOS_ADC_MAX_SAMPLES
][PIOS_ADC_NUM_PINS
];
124 #if defined(PIOS_INCLUDE_ADC)
125 static void init_pins(void)
127 for (uint32_t i
= 0; i
< PIOS_ADC_NUM_PINS
; ++i
) {
128 if (!config
[i
].initialize
) {
131 PIOS_ADC_PinSetup(i
);
135 static void init_dma(void)
137 /* Disable interrupts */
138 DMA_ITConfig(pios_adc_dev
->cfg
->dma
.rx
.channel
, pios_adc_dev
->cfg
->dma
.irq
.flags
, DISABLE
);
140 /* Configure DMA channel */
141 DMA_DeInit(pios_adc_dev
->cfg
->dma
.rx
.channel
);
142 DMA_InitTypeDef DMAInit
= pios_adc_dev
->cfg
->dma
.rx
.init
;
143 DMAInit
.DMA_Memory0BaseAddr
= (uint32_t)&adc_raw_buffer
[0];
144 DMAInit
.DMA_BufferSize
= sizeof(adc_raw_buffer
[0]) / sizeof(uint16_t);
145 DMAInit
.DMA_DIR
= DMA_DIR_PeripheralToMemory
;
146 DMAInit
.DMA_PeripheralInc
= DMA_PeripheralInc_Disable
;
147 DMAInit
.DMA_MemoryInc
= DMA_MemoryInc_Enable
;
148 DMAInit
.DMA_PeripheralDataSize
= DMA_PeripheralDataSize_HalfWord
;
149 DMAInit
.DMA_MemoryDataSize
= DMA_MemoryDataSize_HalfWord
;
150 DMAInit
.DMA_Mode
= DMA_Mode_Circular
;
151 DMAInit
.DMA_Priority
= DMA_Priority_Low
;
152 DMAInit
.DMA_FIFOMode
= DMA_FIFOMode_Disable
;
153 DMAInit
.DMA_FIFOThreshold
= DMA_FIFOThreshold_HalfFull
;
154 DMAInit
.DMA_MemoryBurst
= DMA_MemoryBurst_Single
;
155 DMAInit
.DMA_PeripheralBurst
= DMA_PeripheralBurst_Single
;
157 DMA_Init(pios_adc_dev
->cfg
->dma
.rx
.channel
, &DMAInit
); /* channel is actually stream ... */
159 /* configure for double-buffered mode and interrupt on every buffer flip */
160 DMA_DoubleBufferModeConfig(pios_adc_dev
->cfg
->dma
.rx
.channel
, (uint32_t)&adc_raw_buffer
[1], DMA_Memory_0
);
161 DMA_DoubleBufferModeCmd(pios_adc_dev
->cfg
->dma
.rx
.channel
, ENABLE
);
162 DMA_ITConfig(pios_adc_dev
->cfg
->dma
.rx
.channel
, DMA_IT_TC
, ENABLE
);
163 // DMA_ITConfig(pios_adc_dev->cfg->dma.rx.channel, DMA_IT_HT, ENABLE);
166 DMA_Cmd(pios_adc_dev
->cfg
->dma
.rx
.channel
, ENABLE
);
168 /* Configure DMA interrupt */
169 NVIC_InitTypeDef NVICInit
= pios_adc_dev
->cfg
->dma
.irq
.init
;
170 NVIC_Init(&NVICInit
);
173 static void init_adc(void)
175 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1
, ENABLE
);
179 /* turn on VREFInt in case we need it */
180 ADC_TempSensorVrefintCmd(ENABLE
);
182 /* Do common ADC init */
183 ADC_CommonInitTypeDef ADC_CommonInitStructure
;
184 ADC_CommonStructInit(&ADC_CommonInitStructure
);
185 ADC_CommonInitStructure
.ADC_Mode
= ADC_Mode_Independent
;
186 ADC_CommonInitStructure
.ADC_Prescaler
= ADC_Prescaler_Div8
;
187 ADC_CommonInitStructure
.ADC_DMAAccessMode
= ADC_DMAAccessMode_Disabled
;
188 ADC_CommonInitStructure
.ADC_TwoSamplingDelay
= ADC_TwoSamplingDelay_5Cycles
;
189 ADC_CommonInit(&ADC_CommonInitStructure
);
191 ADC_InitTypeDef ADC_InitStructure
;
192 ADC_StructInit(&ADC_InitStructure
);
193 ADC_InitStructure
.ADC_Resolution
= ADC_Resolution_12b
;
194 ADC_InitStructure
.ADC_ScanConvMode
= ENABLE
;
195 ADC_InitStructure
.ADC_ContinuousConvMode
= ENABLE
;
196 ADC_InitStructure
.ADC_ExternalTrigConvEdge
= ADC_ExternalTrigConvEdge_None
;
197 ADC_InitStructure
.ADC_DataAlign
= ADC_DataAlign_Right
;
198 ADC_InitStructure
.ADC_NbrOfConversion
= ((PIOS_ADC_NUM_PINS
) /* >> 1*/);
199 ADC_Init(pios_adc_dev
->cfg
->adc_dev
, &ADC_InitStructure
);
201 /* Enable DMA request */
202 ADC_DMACmd(pios_adc_dev
->cfg
->adc_dev
, ENABLE
);
204 /* Configure input scan */
205 for (uint32_t i
= 0; i
< PIOS_ADC_NUM_PINS
; i
++) {
206 ADC_RegularChannelConfig(pios_adc_dev
->cfg
->adc_dev
,
209 ADC_SampleTime_56Cycles
); /* XXX this is totally arbitrary... */
212 ADC_DMARequestAfterLastTransferCmd(pios_adc_dev
->cfg
->adc_dev
, ENABLE
);
214 /* Finally start initial conversion */
215 ADC_Cmd(pios_adc_dev
->cfg
->adc_dev
, ENABLE
);
216 ADC_ContinuousModeCmd(pios_adc_dev
->cfg
->adc_dev
, ENABLE
);
217 ADC_SoftwareStartConv(pios_adc_dev
->cfg
->adc_dev
);
219 #endif /* if defined(PIOS_INCLUDE_ADC) */
221 static bool PIOS_ADC_validate(struct pios_adc_dev
*dev
)
227 return dev
->magic
== PIOS_ADC_DEV_MAGIC
;
230 #if defined(PIOS_INCLUDE_FREERTOS)
231 static struct pios_adc_dev
*PIOS_ADC_Allocate()
233 struct pios_adc_dev
*adc_dev
;
235 adc_dev
= (struct pios_adc_dev
*)pios_malloc(sizeof(*adc_dev
));
240 adc_dev
->magic
= PIOS_ADC_DEV_MAGIC
;
244 #if defined(PIOS_INCLUDE_ADC)
245 #error Not implemented
247 static struct pios_adc_dev
*PIOS_ADC_Allocate()
249 return (struct pios_adc_dev
*)NULL
;
254 * @brief Init the ADC.
256 int32_t PIOS_ADC_Init(const struct pios_adc_cfg
*cfg
)
258 pios_adc_dev
= PIOS_ADC_Allocate();
259 if (pios_adc_dev
== NULL
) {
263 pios_adc_dev
->cfg
= cfg
;
264 pios_adc_dev
->callback_function
= NULL
;
266 #if defined(PIOS_INCLUDE_FREERTOS)
267 pios_adc_dev
->data_queue
= NULL
;
270 #if defined(PIOS_INCLUDE_ADC)
280 * @brief Configure the ADC to run at a fixed oversampling
281 * @param[in] oversampling the amount of oversampling to run at
283 void PIOS_ADC_Config(__attribute__((unused
)) uint32_t oversampling
)
289 * Returns value of an ADC Pin
290 * @param[in] pin number
291 * @return ADC pin value averaged over the set of samples since the last reading.
292 * @return -1 if pin doesn't exist
293 * @return -2 if no data acquired since last read
295 int32_t last_conv_value
;
296 int32_t PIOS_ADC_PinGet(uint32_t pin
)
298 #if defined(PIOS_INCLUDE_ADC)
301 /* Check if pin exists */
302 if (pin
>= PIOS_ADC_NUM_PINS
) {
306 if (accumulator
[pin
].accumulator
<= 0) {
310 /* return accumulated result and clear accumulator */
311 result
= accumulator
[pin
].accumulator
/ (accumulator
[pin
].count
? : 1);
312 accumulator
[pin
].accumulator
= result
;
313 accumulator
[pin
].count
= 1;
321 float PIOS_ADC_PinGetVolt(uint32_t pin
)
323 return ((float)PIOS_ADC_PinGet(pin
)) * PIOS_ADC_VOLTAGE_SCALE
;
327 * @brief Set a callback function that is executed whenever
328 * the ADC double buffer swaps
329 * @note Not currently supported.
331 void PIOS_ADC_SetCallback(ADCCallback new_function
)
333 pios_adc_dev
->callback_function
= new_function
;
336 #if defined(PIOS_INCLUDE_FREERTOS)
338 * @brief Register a queue to add data to when downsampled
339 * @note Not currently supported.
341 void PIOS_ADC_SetQueue(xQueueHandle data_queue
)
343 pios_adc_dev
->data_queue
= data_queue
;
348 * @brief Return the address of the downsampled data buffer
349 * @note Not currently supported.
351 float *PIOS_ADC_GetBuffer(void)
357 * @brief Return the address of the raw data data buffer
358 * @note Not currently supported.
360 int16_t *PIOS_ADC_GetRawBuffer(void)
366 * @brief Return the amount of over sampling
367 * @note Not currently supported (always returns 1)
369 uint8_t PIOS_ADC_GetOverSampling(void)
375 * @brief Set the fir coefficients. Takes as many samples as the
376 * current filter order plus one (normalization)
378 * @param new_filter Array of adc_oversampling floats plus one for the
379 * filter coefficients
380 * @note Not currently supported.
382 void PIOS_ADC_SetFIRCoefficients(__attribute__((unused
)) float *new_filter
)
388 * @brief accumulate the data for each of the channels.
390 void accumulate(uint16_t *buffer
, uint32_t count
)
392 #if defined(PIOS_INCLUDE_ADC)
393 uint16_t *sp
= buffer
;
396 * Accumulate sampled values.
399 for (uint32_t i
= 0; i
< PIOS_ADC_NUM_PINS
; ++i
) {
400 accumulator
[i
].accumulator
+= *sp
++;
401 accumulator
[i
].count
++;
403 * If the accumulator reaches half-full, rescale in order to
406 if (accumulator
[i
].accumulator
>= (((uint32_t)1) << 31)) {
407 accumulator
[i
].accumulator
/= 2;
408 accumulator
[i
].count
/= 2;
413 #if defined(PIOS_INCLUDE_FREERTOS)
414 // XXX should do something with this
415 if (pios_adc_dev
->data_queue
) {
416 static portBASE_TYPE xHigherPriorityTaskWoken
;
417 // xQueueSendFromISR(pios_adc_dev->data_queue, pios_adc_dev->downsampled_buffer, &xHigherPriorityTaskWoken);
418 portEND_SWITCHING_ISR(xHigherPriorityTaskWoken
);
422 #endif /* if defined(PIOS_INCLUDE_ADC) */
424 // if(pios_adc_dev->callback_function)
425 // pios_adc_dev->callback_function(pios_adc_dev->downsampled_buffer);
429 * @brief Interrupt on buffer flip.
431 * The hardware is done with the 'other' buffer, so we can pass it to the accumulator.
433 void PIOS_ADC_DMA_Handler(void)
435 if (!PIOS_ADC_validate(pios_adc_dev
)) {
439 #if defined(PIOS_INCLUDE_ADC)
440 /* terminal count, buffer has flipped */
441 if (DMA_GetITStatus(pios_adc_dev
->cfg
->dma
.rx
.channel
, pios_adc_dev
->cfg
->full_flag
)) {
442 DMA_ClearITPendingBit(pios_adc_dev
->cfg
->dma
.rx
.channel
, pios_adc_dev
->cfg
->full_flag
);
444 /* accumulate results from the buffer that was just completed */
445 accumulate(&adc_raw_buffer
[DMA_GetCurrentMemoryTarget(pios_adc_dev
->cfg
->dma
.rx
.channel
) ? 0 : 1][0][0],
446 PIOS_ADC_MAX_SAMPLES
);
451 void PIOS_ADC_PinSetup(uint32_t pin
)
453 if (config
[pin
].port
!= NULL
&& pin
< PIOS_ADC_NUM_PINS
) {
454 /* Setup analog pin */
455 GPIO_InitTypeDef GPIO_InitStructure
;
457 GPIO_StructInit(&GPIO_InitStructure
);
458 GPIO_InitStructure
.GPIO_Speed
= GPIO_Speed_2MHz
;
459 GPIO_InitStructure
.GPIO_Mode
= GPIO_Mode_AN
;
460 GPIO_InitStructure
.GPIO_Pin
= config
[pin
].pin
;
461 GPIO_Init(config
[pin
].port
, &GPIO_InitStructure
);
464 #endif /* PIOS_INCLUDE_ADC */