OP-1483 Added velocity filter to correct EKF's velocity estimate for static velocity...
[librepilot.git] / flight / pios / stm32f4xx / pios_adc.c
blobcaa6d9976eeb5dd303193a0ec485894ea8b4c249
1 /**
2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
4 * @{
5 * @addtogroup PIOS_ADC ADC Functions
6 * @brief STM32F4xx ADC PIOS interface
7 * @{
9 * @file pios_adc.c
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
24 * for more details.
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.
45 #include "pios.h"
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
54 #endif
56 #if !defined(PIOS_ADC_MAX_OVERSAMPLING)
57 #define PIOS_ADC_MAX_OVERSAMPLING 0
58 #endif
60 #if !defined(PIOS_ADC_USE_ADC2)
61 #define PIOS_ADC_USE_ADC2 0
62 #endif
64 #if !defined(PIOS_ADC_NUM_CHANNELS)
65 #define PIOS_ADC_NUM_CHANNELS 0
66 #endif
68 // Private types
69 enum pios_adc_dev_magic {
70 PIOS_ADC_DEV_MAGIC = 0x58375124,
73 struct pios_adc_dev {
74 const struct pios_adc_cfg *cfg;
75 ADCCallback callback_function;
76 #if defined(PIOS_INCLUDE_FREERTOS)
77 xQueueHandle data_queue;
78 #endif
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;
91 // Private functions
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);
100 #endif
102 struct dma_config {
103 GPIO_TypeDef *port;
104 uint32_t pin;
105 uint32_t channel;
108 struct adc_accumulator {
109 uint32_t accumulator;
110 uint32_t count;
113 #if defined(PIOS_INCLUDE_ADC)
114 static const struct dma_config config[] = PIOS_DMA_PIN_CONFIG;
115 #define PIOS_ADC_NUM_PINS (sizeof(config) / sizeof(config[0]))
117 static struct adc_accumulator accumulator[PIOS_ADC_NUM_PINS];
119 // Two buffers here for double buffering
120 static uint16_t adc_raw_buffer[2][PIOS_ADC_MAX_SAMPLES][PIOS_ADC_NUM_PINS];
121 #endif
123 #if defined(PIOS_INCLUDE_ADC)
124 static void init_pins(void)
126 /* Setup analog pins */
127 GPIO_InitTypeDef GPIO_InitStructure;
129 GPIO_StructInit(&GPIO_InitStructure);
130 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
131 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
132 for (uint32_t i = 0; i < PIOS_ADC_NUM_PINS; ++i) {
133 if (config[i].port == NULL) {
134 continue;
136 GPIO_InitStructure.GPIO_Pin = config[i].pin;
137 GPIO_Init(config[i].port, &GPIO_InitStructure);
141 static void init_dma(void)
143 /* Disable interrupts */
144 DMA_ITConfig(pios_adc_dev->cfg->dma.rx.channel, pios_adc_dev->cfg->dma.irq.flags, DISABLE);
146 /* Configure DMA channel */
147 DMA_DeInit(pios_adc_dev->cfg->dma.rx.channel);
148 DMA_InitTypeDef DMAInit = pios_adc_dev->cfg->dma.rx.init;
149 DMAInit.DMA_Memory0BaseAddr = (uint32_t)&adc_raw_buffer[0];
150 DMAInit.DMA_BufferSize = sizeof(adc_raw_buffer[0]) / sizeof(uint16_t);
151 DMAInit.DMA_DIR = DMA_DIR_PeripheralToMemory;
152 DMAInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
153 DMAInit.DMA_MemoryInc = DMA_MemoryInc_Enable;
154 DMAInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
155 DMAInit.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
156 DMAInit.DMA_Mode = DMA_Mode_Circular;
157 DMAInit.DMA_Priority = DMA_Priority_Low;
158 DMAInit.DMA_FIFOMode = DMA_FIFOMode_Disable;
159 DMAInit.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
160 DMAInit.DMA_MemoryBurst = DMA_MemoryBurst_Single;
161 DMAInit.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
163 DMA_Init(pios_adc_dev->cfg->dma.rx.channel, &DMAInit); /* channel is actually stream ... */
165 /* configure for double-buffered mode and interrupt on every buffer flip */
166 DMA_DoubleBufferModeConfig(pios_adc_dev->cfg->dma.rx.channel, (uint32_t)&adc_raw_buffer[1], DMA_Memory_0);
167 DMA_DoubleBufferModeCmd(pios_adc_dev->cfg->dma.rx.channel, ENABLE);
168 DMA_ITConfig(pios_adc_dev->cfg->dma.rx.channel, DMA_IT_TC, ENABLE);
169 // DMA_ITConfig(pios_adc_dev->cfg->dma.rx.channel, DMA_IT_HT, ENABLE);
171 /* enable DMA */
172 DMA_Cmd(pios_adc_dev->cfg->dma.rx.channel, ENABLE);
174 /* Configure DMA interrupt */
175 NVIC_InitTypeDef NVICInit = pios_adc_dev->cfg->dma.irq.init;
176 NVIC_Init(&NVICInit);
179 static void init_adc(void)
181 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
183 ADC_DeInit();
185 /* turn on VREFInt in case we need it */
186 ADC_TempSensorVrefintCmd(ENABLE);
188 /* Do common ADC init */
189 ADC_CommonInitTypeDef ADC_CommonInitStructure;
190 ADC_CommonStructInit(&ADC_CommonInitStructure);
191 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
192 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8;
193 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
194 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
195 ADC_CommonInit(&ADC_CommonInitStructure);
197 ADC_InitTypeDef ADC_InitStructure;
198 ADC_StructInit(&ADC_InitStructure);
199 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
200 ADC_InitStructure.ADC_ScanConvMode = ENABLE;
201 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
202 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
203 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
204 ADC_InitStructure.ADC_NbrOfConversion = ((PIOS_ADC_NUM_PINS) /* >> 1*/);
205 ADC_Init(pios_adc_dev->cfg->adc_dev, &ADC_InitStructure);
207 /* Enable DMA request */
208 ADC_DMACmd(pios_adc_dev->cfg->adc_dev, ENABLE);
210 /* Configure input scan */
211 for (uint32_t i = 0; i < PIOS_ADC_NUM_PINS; i++) {
212 ADC_RegularChannelConfig(pios_adc_dev->cfg->adc_dev,
213 config[i].channel,
214 i + 1,
215 ADC_SampleTime_56Cycles); /* XXX this is totally arbitrary... */
218 ADC_DMARequestAfterLastTransferCmd(pios_adc_dev->cfg->adc_dev, ENABLE);
220 /* Finally start initial conversion */
221 ADC_Cmd(pios_adc_dev->cfg->adc_dev, ENABLE);
222 ADC_ContinuousModeCmd(pios_adc_dev->cfg->adc_dev, ENABLE);
223 ADC_SoftwareStartConv(pios_adc_dev->cfg->adc_dev);
225 #endif /* if defined(PIOS_INCLUDE_ADC) */
227 static bool PIOS_ADC_validate(struct pios_adc_dev *dev)
229 if (dev == NULL) {
230 return false;
233 return dev->magic == PIOS_ADC_DEV_MAGIC;
236 #if defined(PIOS_INCLUDE_FREERTOS)
237 static struct pios_adc_dev *PIOS_ADC_Allocate()
239 struct pios_adc_dev *adc_dev;
241 adc_dev = (struct pios_adc_dev *)pios_malloc(sizeof(*adc_dev));
242 if (!adc_dev) {
243 return NULL;
246 adc_dev->magic = PIOS_ADC_DEV_MAGIC;
247 return adc_dev;
249 #else
250 #if defined(PIOS_INCLUDE_ADC)
251 #error Not implemented
252 #endif
253 static struct pios_adc_dev *PIOS_ADC_Allocate()
255 return (struct pios_adc_dev *)NULL;
257 #endif
260 * @brief Init the ADC.
262 int32_t PIOS_ADC_Init(const struct pios_adc_cfg *cfg)
264 pios_adc_dev = PIOS_ADC_Allocate();
265 if (pios_adc_dev == NULL) {
266 return -1;
269 pios_adc_dev->cfg = cfg;
270 pios_adc_dev->callback_function = NULL;
272 #if defined(PIOS_INCLUDE_FREERTOS)
273 pios_adc_dev->data_queue = NULL;
274 #endif
276 #if defined(PIOS_INCLUDE_ADC)
277 init_pins();
278 init_dma();
279 init_adc();
280 #endif
282 return 0;
286 * @brief Configure the ADC to run at a fixed oversampling
287 * @param[in] oversampling the amount of oversampling to run at
289 void PIOS_ADC_Config(__attribute__((unused)) uint32_t oversampling)
291 /* we ignore this */
295 * Returns value of an ADC Pin
296 * @param[in] pin number
297 * @return ADC pin value averaged over the set of samples since the last reading.
298 * @return -1 if pin doesn't exist
299 * @return -2 if no data acquired since last read
301 int32_t last_conv_value;
302 int32_t PIOS_ADC_PinGet(uint32_t pin)
304 #if defined(PIOS_INCLUDE_ADC)
305 int32_t result;
307 /* Check if pin exists */
308 if (pin >= PIOS_ADC_NUM_PINS) {
309 return -1;
312 if (accumulator[pin].accumulator <= 0) {
313 return -2;
316 /* return accumulated result and clear accumulator */
317 result = accumulator[pin].accumulator / (accumulator[pin].count ? : 1);
318 accumulator[pin].accumulator = result;
319 accumulator[pin].count = 1;
321 return result;
323 #endif
324 return -1;
327 float PIOS_ADC_PinGetVolt(uint32_t pin)
329 return ((float)PIOS_ADC_PinGet(pin)) * PIOS_ADC_VOLTAGE_SCALE;
333 * @brief Set a callback function that is executed whenever
334 * the ADC double buffer swaps
335 * @note Not currently supported.
337 void PIOS_ADC_SetCallback(ADCCallback new_function)
339 pios_adc_dev->callback_function = new_function;
342 #if defined(PIOS_INCLUDE_FREERTOS)
344 * @brief Register a queue to add data to when downsampled
345 * @note Not currently supported.
347 void PIOS_ADC_SetQueue(xQueueHandle data_queue)
349 pios_adc_dev->data_queue = data_queue;
351 #endif
354 * @brief Return the address of the downsampled data buffer
355 * @note Not currently supported.
357 float *PIOS_ADC_GetBuffer(void)
359 return NULL;
363 * @brief Return the address of the raw data data buffer
364 * @note Not currently supported.
366 int16_t *PIOS_ADC_GetRawBuffer(void)
368 return NULL;
372 * @brief Return the amount of over sampling
373 * @note Not currently supported (always returns 1)
375 uint8_t PIOS_ADC_GetOverSampling(void)
377 return 1;
381 * @brief Set the fir coefficients. Takes as many samples as the
382 * current filter order plus one (normalization)
384 * @param new_filter Array of adc_oversampling floats plus one for the
385 * filter coefficients
386 * @note Not currently supported.
388 void PIOS_ADC_SetFIRCoefficients(__attribute__((unused)) float *new_filter)
390 // not implemented
394 * @brief accumulate the data for each of the channels.
396 void accumulate(uint16_t *buffer, uint32_t count)
398 #if defined(PIOS_INCLUDE_ADC)
399 uint16_t *sp = buffer;
402 * Accumulate sampled values.
404 while (count--) {
405 for (uint32_t i = 0; i < PIOS_ADC_NUM_PINS; ++i) {
406 accumulator[i].accumulator += *sp++;
407 accumulator[i].count++;
409 * If the accumulator reaches half-full, rescale in order to
410 * make more space.
412 if (accumulator[i].accumulator >= (((uint32_t)1) << 31)) {
413 accumulator[i].accumulator /= 2;
414 accumulator[i].count /= 2;
419 #if defined(PIOS_INCLUDE_FREERTOS)
420 // XXX should do something with this
421 if (pios_adc_dev->data_queue) {
422 static portBASE_TYPE xHigherPriorityTaskWoken;
423 // xQueueSendFromISR(pios_adc_dev->data_queue, pios_adc_dev->downsampled_buffer, &xHigherPriorityTaskWoken);
424 portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
427 #endif
428 #endif /* if defined(PIOS_INCLUDE_ADC) */
430 // if(pios_adc_dev->callback_function)
431 // pios_adc_dev->callback_function(pios_adc_dev->downsampled_buffer);
435 * @brief Interrupt on buffer flip.
437 * The hardware is done with the 'other' buffer, so we can pass it to the accumulator.
439 void PIOS_ADC_DMA_Handler(void)
441 if (!PIOS_ADC_validate(pios_adc_dev)) {
442 return;
445 #if defined(PIOS_INCLUDE_ADC)
446 /* terminal count, buffer has flipped */
447 if (DMA_GetITStatus(pios_adc_dev->cfg->dma.rx.channel, pios_adc_dev->cfg->full_flag)) {
448 DMA_ClearITPendingBit(pios_adc_dev->cfg->dma.rx.channel, pios_adc_dev->cfg->full_flag);
450 /* accumulate results from the buffer that was just completed */
451 accumulate(&adc_raw_buffer[DMA_GetCurrentMemoryTarget(pios_adc_dev->cfg->dma.rx.channel) ? 0 : 1][0][0],
452 PIOS_ADC_MAX_SAMPLES);
454 #endif
457 #endif /* PIOS_INCLUDE_ADC */
460 * @}
461 * @}