LP-602 significant change to USB layer. force complete USB stack reset on replug...
[librepilot.git] / flight / pios / stm32f4xx / pios_adc.c
blob3bd13534a62d09351bd2cd7835dd527b4746ff93
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 pios_adc_pin_config {
103 GPIO_TypeDef *port;
104 uint32_t pin;
105 uint32_t channel;
106 bool initialize;
109 struct adc_accumulator {
110 uint32_t accumulator;
111 uint32_t count;
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];
122 #endif
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) {
129 continue;
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);
165 /* enable DMA */
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);
177 ADC_DeInit();
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,
207 config[i].channel,
208 i + 1,
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)
223 if (dev == NULL) {
224 return false;
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));
236 if (!adc_dev) {
237 return NULL;
240 adc_dev->magic = PIOS_ADC_DEV_MAGIC;
241 return adc_dev;
243 #else
244 #if defined(PIOS_INCLUDE_ADC)
245 #error Not implemented
246 #endif
247 static struct pios_adc_dev *PIOS_ADC_Allocate()
249 return (struct pios_adc_dev *)NULL;
251 #endif
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) {
260 return -1;
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;
268 #endif
270 #if defined(PIOS_INCLUDE_ADC)
271 init_pins();
272 init_dma();
273 init_adc();
274 #endif
276 return 0;
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)
285 /* we ignore this */
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)
299 int32_t result;
301 /* Check if pin exists */
302 if (pin >= PIOS_ADC_NUM_PINS) {
303 return -1;
306 if (accumulator[pin].accumulator <= 0) {
307 return -2;
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;
315 return result;
317 #endif
318 return -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;
345 #endif
348 * @brief Return the address of the downsampled data buffer
349 * @note Not currently supported.
351 float *PIOS_ADC_GetBuffer(void)
353 return NULL;
357 * @brief Return the address of the raw data data buffer
358 * @note Not currently supported.
360 int16_t *PIOS_ADC_GetRawBuffer(void)
362 return NULL;
366 * @brief Return the amount of over sampling
367 * @note Not currently supported (always returns 1)
369 uint8_t PIOS_ADC_GetOverSampling(void)
371 return 1;
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)
384 // not implemented
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.
398 while (count--) {
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
404 * make more space.
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);
421 #endif
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)) {
436 return;
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);
448 #endif
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 */
467 * @}
468 * @}