2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_ADC ADC Functions
6 * @brief STM32F30x ADC PIOS interface
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
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
32 #ifdef PIOS_INCLUDE_ADC
34 #include <pios_adc_priv.h>
37 #if !defined(PIOS_ADC_MAX_SAMPLES)
38 #define PIOS_ADC_MAX_SAMPLES 0
41 #if !defined(PIOS_ADC_MAX_OVERSAMPLING)
42 #define PIOS_ADC_MAX_OVERSAMPLING 0
45 #if !defined(PIOS_ADC_USE_ADC2)
46 #define PIOS_ADC_USE_ADC2 0
49 #if !defined(PIOS_ADC_NUM_CHANNELS)
50 #define PIOS_ADC_NUM_CHANNELS 0
53 struct pios_adc_pin_config
{
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)
66 enum pios_adc_dev_magic
{
67 PIOS_ADC_DEV_MAGIC
= 0x58375124,
70 struct adc_accumulator
{
76 const struct pios_adc_cfg
*cfg
;
77 ADCCallback callback_function
;
78 #if defined(PIOS_INCLUDE_FREERTOS)
79 xQueueHandle data_queue
;
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
;
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
) {
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 ... */
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
);
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
,
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
)
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
));
224 memset(adc_dev
, 0, sizeof(*adc_dev
));
226 adc_dev
->magic
= PIOS_ADC_DEV_MAGIC
;
230 #error Not implemented
231 static struct pios_adc_dev
*PIOS_ADC_Allocate()
233 return (struct pios_adc_dev
*)NULL
;
238 * @brief Init the ADC.
240 int32_t PIOS_ADC_Init(const struct pios_adc_cfg
*cfg
)
244 pios_adc_dev
= PIOS_ADC_Allocate();
245 if (pios_adc_dev
== NULL
) {
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
;
256 init_pins(pios_adc_dev
);
257 init_dma(pios_adc_dev
);
258 init_adc(pios_adc_dev
);
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
)
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
)
284 /* Check if pin exists */
285 if (pin
>= PIOS_ADC_NUM_PINS
) {
289 if (pios_adc_dev
->accumulator
[pin
].accumulator
<= 0) {
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;
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
;
328 * @brief Return the address of the downsampled data buffer
329 * @note Not currently supported.
331 float *PIOS_ADC_GetBuffer(void)
337 * @brief Return the address of the raw data data buffer
338 * @note Not currently supported.
340 int16_t *PIOS_ADC_GetRawBuffer(void)
346 * @brief Return the amount of over sampling
347 * @note Not currently supported (always returns 1)
349 uint8_t PIOS_ADC_GetOverSampling(void)
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
)
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);
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
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
);
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
)) {
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]);
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 */