update credits
[librepilot.git] / flight / pios / stm32f30x / pios_adc.c
blob66b852f9e711b2b797b5bbae625d3eb6c775657e
1 /**
2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
4 * @{
5 * @addtogroup PIOS_ADC ADC Functions
6 * @brief STM32F30x ADC PIOS interface
7 * @{
9 * @file pios_adc.c
10 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
11 * @brief Analog to Digital conversion routines
12 * @see The GNU Public License (GPL) Version 3
13 *****************************************************************************/
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 3 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 * for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "pios.h"
32 #ifdef PIOS_INCLUDE_ADC
34 #include <pios_adc_priv.h>
35 #include <pios_adc.h>
37 #if !defined(PIOS_ADC_MAX_SAMPLES)
38 #define PIOS_ADC_MAX_SAMPLES 0
39 #endif
41 #if !defined(PIOS_ADC_MAX_OVERSAMPLING)
42 #define PIOS_ADC_MAX_OVERSAMPLING 0
43 #endif
45 #if !defined(PIOS_ADC_USE_ADC2)
46 #define PIOS_ADC_USE_ADC2 0
47 #endif
49 #if !defined(PIOS_ADC_NUM_CHANNELS)
50 #define PIOS_ADC_NUM_CHANNELS 0
51 #endif
53 struct pios_adc_pin_config {
54 GPIO_TypeDef *port;
55 uint32_t pin;
56 uint32_t channel;
57 bool initialize;
60 static const struct pios_adc_pin_config config[] = PIOS_DMA_PIN_CONFIG;
61 #define PIOS_ADC_NUM_PINS (sizeof(config) / sizeof(config[0]))
63 #define PIOS_ADC_DMA_BUFFER_SIZE (PIOS_ADC_MAX_SAMPLES * PIOS_ADC_NUM_PINS)
65 // Private types
66 enum pios_adc_dev_magic {
67 PIOS_ADC_DEV_MAGIC = 0x58375124,
70 struct adc_accumulator {
71 uint32_t accumulator;
72 uint32_t count;
75 struct pios_adc_dev {
76 const struct pios_adc_cfg *cfg;
77 ADCCallback callback_function;
78 #if defined(PIOS_INCLUDE_FREERTOS)
79 xQueueHandle data_queue;
80 #endif
81 enum pios_adc_dev_magic magic;
82 volatile uint16_t raw_data_buffer[PIOS_ADC_DMA_BUFFER_SIZE] __attribute__((aligned(4))); // Double buffer that DMA just used
83 struct adc_accumulator accumulator[PIOS_ADC_NUM_PINS];
86 struct pios_adc_dev *pios_adc_dev;
88 // Private functions
89 void PIOS_ADC_downsample_data();
90 static struct pios_adc_dev *PIOS_ADC_Allocate();
91 static bool PIOS_ADC_validate(struct pios_adc_dev *);
93 static void init_pins(struct pios_adc_dev *adc_dev);
94 static void init_dma(struct pios_adc_dev *adc_dev);
95 static void init_adc(struct pios_adc_dev *adc_dev);
97 static void init_pins(__attribute__((unused)) struct pios_adc_dev *adc_dev)
99 for (uint32_t i = 0; i < PIOS_ADC_NUM_PINS; ++i) {
100 if (!config[i].initialize) {
101 continue;
103 PIOS_ADC_PinSetup(i);
107 static void init_dma(struct pios_adc_dev *adc_dev)
109 /* Disable interrupts */
110 DMA_ITConfig(pios_adc_dev->cfg->dma.rx.channel, pios_adc_dev->cfg->dma.irq.flags, DISABLE);
112 /* Configure DMA channel */
113 DMA_DeInit(adc_dev->cfg->dma.rx.channel);
114 DMA_InitTypeDef DMAInit = adc_dev->cfg->dma.rx.init;
115 DMAInit.DMA_PeripheralBaseAddr = (uint32_t)&adc_dev->cfg->adc_dev->DR;
117 DMAInit.DMA_MemoryBaseAddr = (uint32_t)&pios_adc_dev->raw_data_buffer[0];
118 DMAInit.DMA_BufferSize = PIOS_ADC_DMA_BUFFER_SIZE;
119 DMAInit.DMA_DIR = DMA_DIR_PeripheralSRC;
120 DMAInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
121 DMAInit.DMA_MemoryInc = DMA_MemoryInc_Enable;
122 DMAInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
123 DMAInit.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
124 DMAInit.DMA_Mode = DMA_Mode_Circular;
125 DMAInit.DMA_M2M = DMA_M2M_Disable;
127 DMA_Init(adc_dev->cfg->dma.rx.channel, &DMAInit); /* channel is actually stream ... */
129 /* enable DMA */
130 DMA_Cmd(adc_dev->cfg->dma.rx.channel, ENABLE);
132 /* Trigger interrupt when for half conversions too to indicate double buffer */
133 DMA_ITConfig(adc_dev->cfg->dma.rx.channel, DMA_IT_TC, ENABLE);
134 DMA_ITConfig(adc_dev->cfg->dma.rx.channel, DMA_IT_HT, ENABLE);
136 /* Configure DMA interrupt */
137 NVIC_InitTypeDef NVICInit = adc_dev->cfg->dma.irq.init;
138 NVIC_Init(&NVICInit);
141 static void init_adc(struct pios_adc_dev *adc_dev)
143 ADC_DeInit(adc_dev->cfg->adc_dev);
145 if (adc_dev->cfg->adc_dev == ADC1 || adc_dev->cfg->adc_dev == ADC2) {
146 RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div32);
147 } else {
148 RCC_ADCCLKConfig(RCC_ADC34PLLCLK_Div32);
151 ADC_VoltageRegulatorCmd(adc_dev->cfg->adc_dev, ENABLE);
152 PIOS_DELAY_WaituS(10);
153 ADC_SelectCalibrationMode(adc_dev->cfg->adc_dev, ADC_CalibrationMode_Single);
154 ADC_StartCalibration(adc_dev->cfg->adc_dev);
155 while (ADC_GetCalibrationStatus(adc_dev->cfg->adc_dev) != RESET) {
159 /* Do common ADC init */
160 ADC_CommonInitTypeDef ADC_CommonInitStructure;
161 ADC_CommonStructInit(&ADC_CommonInitStructure);
163 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
164 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
166 ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;
167 ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_Circular;
168 ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0;
169 ADC_DMAConfig(adc_dev->cfg->adc_dev, ADC_DMAMode_Circular);
170 ADC_CommonInit(adc_dev->cfg->adc_dev, &ADC_CommonInitStructure);
172 ADC_InitTypeDef ADC_InitStructure;
173 ADC_StructInit(&ADC_InitStructure);
174 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
175 ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable;
176 ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;
177 ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;
178 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
180 ADC_InitStructure.ADC_NbrOfRegChannel = ((PIOS_ADC_NUM_PINS) /* >> 1*/);
182 ADC_Init(adc_dev->cfg->adc_dev, &ADC_InitStructure);
184 /* Enable DMA request */
185 ADC_DMACmd(adc_dev->cfg->adc_dev, ENABLE);
187 /* Configure input scan */
189 for (uint32_t i = 0; i < PIOS_ADC_NUM_PINS; i++) {
190 ADC_RegularChannelConfig(adc_dev->cfg->adc_dev,
191 config[i].channel,
192 i + 1,
193 ADC_SampleTime_61Cycles5); /* XXX this is totally arbitrary... */
196 ADC_Cmd(adc_dev->cfg->adc_dev, ENABLE);
198 while (!ADC_GetFlagStatus(adc_dev->cfg->adc_dev, ADC_FLAG_RDY)) {
202 ADC_StartConversion(adc_dev->cfg->adc_dev);
205 static bool PIOS_ADC_validate(struct pios_adc_dev *dev)
207 if (dev == NULL) {
208 return false;
211 return dev->magic == PIOS_ADC_DEV_MAGIC;
214 #if defined(PIOS_INCLUDE_FREERTOS)
215 static struct pios_adc_dev *PIOS_ADC_Allocate()
217 struct pios_adc_dev *adc_dev;
219 adc_dev = (struct pios_adc_dev *)pios_malloc(sizeof(*adc_dev));
220 if (!adc_dev) {
221 return NULL;
224 memset(adc_dev, 0, sizeof(*adc_dev));
226 adc_dev->magic = PIOS_ADC_DEV_MAGIC;
227 return adc_dev;
229 #else
230 #error Not implemented
231 static struct pios_adc_dev *PIOS_ADC_Allocate()
233 return (struct pios_adc_dev *)NULL;
235 #endif
238 * @brief Init the ADC.
240 int32_t PIOS_ADC_Init(const struct pios_adc_cfg *cfg)
242 PIOS_Assert(cfg);
244 pios_adc_dev = PIOS_ADC_Allocate();
245 if (pios_adc_dev == NULL) {
246 return -1;
249 pios_adc_dev->cfg = cfg;
250 pios_adc_dev->callback_function = NULL;
252 #if defined(PIOS_INCLUDE_FREERTOS)
253 pios_adc_dev->data_queue = NULL;
254 #endif
256 init_pins(pios_adc_dev);
257 init_dma(pios_adc_dev);
258 init_adc(pios_adc_dev);
260 return 0;
264 * @brief Configure the ADC to run at a fixed oversampling
265 * @param[in] oversampling the amount of oversampling to run at
267 void PIOS_ADC_Config(__attribute__((unused)) uint32_t oversampling)
269 /* we ignore this */
273 * Returns value of an ADC Pin
274 * @param[in] pin number
275 * @return ADC pin value averaged over the set of samples since the last reading.
276 * @return -1 if pin doesn't exist
277 * @return -2 if no data acquired since last read
279 int32_t last_conv_value;
280 int32_t PIOS_ADC_PinGet(uint32_t pin)
282 int32_t result;
284 /* Check if pin exists */
285 if (pin >= PIOS_ADC_NUM_PINS) {
286 return -1;
289 if (pios_adc_dev->accumulator[pin].accumulator <= 0) {
290 return -2;
293 /* return accumulated result and clear accumulator */
294 result = pios_adc_dev->accumulator[pin].accumulator / (pios_adc_dev->accumulator[pin].count ? : 1);
295 pios_adc_dev->accumulator[pin].accumulator = result;
296 pios_adc_dev->accumulator[pin].count = 1;
298 return result;
301 float PIOS_ADC_PinGetVolt(uint32_t pin)
303 return ((float)PIOS_ADC_PinGet(pin)) * PIOS_ADC_VOLTAGE_SCALE;
307 * @brief Set a callback function that is executed whenever
308 * the ADC double buffer swaps
309 * @note Not currently supported.
311 void PIOS_ADC_SetCallback(ADCCallback new_function)
313 pios_adc_dev->callback_function = new_function;
316 #if defined(PIOS_INCLUDE_FREERTOS)
318 * @brief Register a queue to add data to when downsampled
319 * @note Not currently supported.
321 void PIOS_ADC_SetQueue(xQueueHandle data_queue)
323 pios_adc_dev->data_queue = data_queue;
325 #endif
328 * @brief Return the address of the downsampled data buffer
329 * @note Not currently supported.
331 float *PIOS_ADC_GetBuffer(void)
333 return NULL;
337 * @brief Return the address of the raw data data buffer
338 * @note Not currently supported.
340 int16_t *PIOS_ADC_GetRawBuffer(void)
342 return NULL;
346 * @brief Return the amount of over sampling
347 * @note Not currently supported (always returns 1)
349 uint8_t PIOS_ADC_GetOverSampling(void)
351 return 1;
355 * @brief Set the fir coefficients. Takes as many samples as the
356 * current filter order plus one (normalization)
358 * @param new_filter Array of adc_oversampling floats plus one for the
359 * filter coefficients
360 * @note Not currently supported.
362 void PIOS_ADC_SetFIRCoefficients(__attribute__((unused)) float *new_filter)
364 // not implemented
368 * @brief accumulate the data for each of the channels.
370 void accumulate(struct pios_adc_dev *dev, volatile uint16_t *buffer)
372 volatile uint16_t *sp = buffer;
375 * Accumulate sampled values.
378 int count = (PIOS_ADC_MAX_SAMPLES / 2);
380 while (count--) {
381 for (uint32_t i = 0; i < PIOS_ADC_NUM_PINS; ++i) {
382 dev->accumulator[i].accumulator += *sp++;
383 dev->accumulator[i].count++;
385 * If the accumulator reaches half-full, rescale in order to
386 * make more space.
388 if (dev->accumulator[i].accumulator >= (((uint32_t)1) << 31)) {
389 dev->accumulator[i].accumulator /= 2;
390 dev->accumulator[i].count /= 2;
395 #if defined(PIOS_INCLUDE_FREERTOS)
396 // XXX should do something with this
397 if (pios_adc_dev->data_queue) {
398 static portBASE_TYPE xHigherPriorityTaskWoken;
399 // xQueueSendFromISR(pios_adc_dev->data_queue, pios_adc_dev->downsampled_buffer, &xHigherPriorityTaskWoken);
400 portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
403 #endif
405 // if(pios_adc_dev->callback_function)
406 // pios_adc_dev->callback_function(pios_adc_dev->downsampled_buffer);
410 * @brief Interrupt on buffer flip.
412 * The hardware is done with the 'other' buffer, so we can pass it to the accumulator.
414 void PIOS_ADC_DMA_Handler(void)
416 if (!PIOS_ADC_validate(pios_adc_dev)) {
417 return;
420 if (DMA_GetFlagStatus(pios_adc_dev->cfg->full_flag)) { // whole double buffer filled
421 DMA_ClearFlag(pios_adc_dev->cfg->full_flag);
422 accumulate(pios_adc_dev, &pios_adc_dev->raw_data_buffer[PIOS_ADC_DMA_BUFFER_SIZE / 2]);
423 } else if (DMA_GetFlagStatus(pios_adc_dev->cfg->half_flag)) {
424 DMA_ClearFlag(pios_adc_dev->cfg->half_flag);
425 accumulate(pios_adc_dev, &pios_adc_dev->raw_data_buffer[0]);
426 } else {
427 // This should not happen, probably due to transfer errors
428 DMA_ClearFlag(pios_adc_dev->cfg->dma.irq.flags);
432 void PIOS_ADC_PinSetup(uint32_t pin)
434 if (config[pin].port != NULL && pin < PIOS_ADC_NUM_PINS) {
435 /* Setup analog pin */
436 GPIO_InitTypeDef GPIO_InitStructure;
438 GPIO_StructInit(&GPIO_InitStructure);
439 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
440 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
441 GPIO_InitStructure.GPIO_Pin = config[pin].pin;
442 GPIO_Init(config[pin].port, &GPIO_InitStructure);
445 #endif /* PIOS_INCLUDE_ADC */
448 * @}
449 * @}