dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_internal_adc.c
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  */
30 
31 /*
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.
36  *
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.
43  */
44 
45 #include "pios.h"
46 #include <pios_internal_adc_priv.h>
47 
48 #if defined(PIOS_INCLUDE_ADC)
49 
50 #include "pios_queue.h"
51 
52 // Private types
53 enum pios_adc_dev_magic {
54  PIOS_INTERNAL_ADC_DEV_MAGIC = 0x58375124,
55 };
56 
57 struct pios_internal_adc_dev {
58  enum pios_adc_dev_magic magic;
59  const struct pios_internal_adc_cfg * cfg;
60 };
61 
62 static struct pios_internal_adc_dev * pios_adc_dev;
63 
64 // Private functions
65 static struct pios_internal_adc_dev * PIOS_INTERNAL_ADC_Allocate(const struct pios_internal_adc_cfg * cfg);
66 static bool PIOS_INTERNAL_ADC_validate(struct pios_internal_adc_dev *);
67 
68 #if defined(PIOS_INCLUDE_ADC)
69 static void init_pins(void);
70 static void init_dma(void);
71 static void init_adc(void);
72 #endif
73 static int32_t PIOS_INTERNAL_ADC_PinGet(uintptr_t internal_adc_id, uint32_t pin);
74 static uint8_t PIOS_INTERNAL_ADC_Number_of_Channels(uintptr_t internal_adc_id);
75 static float PIOS_INTERNAL_ADC_LSB_Voltage(uintptr_t internal_adc_id);
76 
78  .get_pin = PIOS_INTERNAL_ADC_PinGet,
79  .number_of_channels = PIOS_INTERNAL_ADC_Number_of_Channels,
80  .lsb_voltage = PIOS_INTERNAL_ADC_LSB_Voltage,
81 };
82 
83 struct adc_accumulator {
84  volatile uint32_t accumulator, count;
85 };
86 
87 // Buffers to hold the ADC data
88 static struct adc_accumulator * accumulator;
89 static uint16_t * adc_raw_buffer_0;
90 static uint16_t * adc_raw_buffer_1;
91 
92 
93 static void init_pins(void)
94 {
95  if (!PIOS_INTERNAL_ADC_validate(pios_adc_dev)) {
96  return;
97  }
98 
99  /* Setup analog pins */
100  GPIO_InitTypeDef GPIO_InitStructure;
101  GPIO_StructInit(&GPIO_InitStructure);
102  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
103  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
104 
105  for (int32_t i = 0; i < pios_adc_dev->cfg->adc_pin_count; i++) {
106  if (pios_adc_dev->cfg->adc_pins[i].port == NULL)
107  continue;
108  GPIO_InitStructure.GPIO_Pin = pios_adc_dev->cfg->adc_pins[i].pin;
109  GPIO_Init(pios_adc_dev->cfg->adc_pins[i].port, &GPIO_InitStructure);
110  }
111 }
112 
113 static void init_dma(void)
114 {
115  if (!PIOS_INTERNAL_ADC_validate(pios_adc_dev)) {
116  return;
117  }
118 
119  /* Disable interrupts */
120  DMA_ITConfig(pios_adc_dev->cfg->dma.rx.channel, pios_adc_dev->cfg->dma.irq.flags, DISABLE);
121 
122  /* Configure DMA channel */
123  DMA_DeInit(pios_adc_dev->cfg->dma.rx.channel);
124  DMA_InitTypeDef DMAInit = pios_adc_dev->cfg->dma.rx.init;
125  DMAInit.DMA_Memory0BaseAddr = (uint32_t)&adc_raw_buffer_0[0];
126  DMAInit.DMA_BufferSize = PIOS_ADC_MAX_OVERSAMPLING * pios_adc_dev->cfg->adc_pin_count;
127  DMAInit.DMA_DIR = DMA_DIR_PeripheralToMemory;
128  DMAInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
129  DMAInit.DMA_MemoryInc = DMA_MemoryInc_Enable;
130  DMAInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
131  DMAInit.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
132  DMAInit.DMA_Mode = DMA_Mode_Circular;
133  DMAInit.DMA_Priority = DMA_Priority_Low;
134  DMAInit.DMA_FIFOMode = DMA_FIFOMode_Disable;
135  DMAInit.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
136  DMAInit.DMA_MemoryBurst = DMA_MemoryBurst_Single;
137  DMAInit.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
138 
139  DMA_Init(pios_adc_dev->cfg->dma.rx.channel, &DMAInit); /* channel is actually stream ... */
140 
141  /* configure for double-buffered mode and interrupt on every buffer flip */
142  DMA_DoubleBufferModeConfig(pios_adc_dev->cfg->dma.rx.channel, (uint32_t)&adc_raw_buffer_1[0], DMA_Memory_0);
143  DMA_DoubleBufferModeCmd(pios_adc_dev->cfg->dma.rx.channel, ENABLE);
144  DMA_ITConfig(pios_adc_dev->cfg->dma.rx.channel, DMA_IT_TC, ENABLE);
145 
146  /* enable DMA */
147  DMA_Cmd(pios_adc_dev->cfg->dma.rx.channel, ENABLE);
148 
149  /* Configure DMA interrupt */
150  NVIC_InitTypeDef NVICInit = pios_adc_dev->cfg->dma.irq.init;
151  NVIC_Init(&NVICInit);
152 }
153 
154 static void init_adc(void)
155 {
156  if (!PIOS_INTERNAL_ADC_validate(pios_adc_dev)) {
157  return;
158  }
159 
160  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
161 
162  ADC_DeInit();
163 
164  /* turn on VREFInt in case we need it */
165  ADC_TempSensorVrefintCmd(ENABLE);
166 
167  /* Do common ADC init */
168  ADC_CommonInitTypeDef ADC_CommonInitStructure;
169  ADC_CommonStructInit(&ADC_CommonInitStructure);
170  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
171  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8;
172  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
173  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
174  ADC_CommonInit(&ADC_CommonInitStructure);
175 
176  ADC_InitTypeDef ADC_InitStructure;
177  ADC_StructInit(&ADC_InitStructure);
178  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
179  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
180  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
181  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
182  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
183  ADC_InitStructure.ADC_NbrOfConversion = pios_adc_dev->cfg->adc_pin_count;
184  ADC_Init(pios_adc_dev->cfg->adc_dev_master, &ADC_InitStructure);
185 
186  /* Enable DMA request */
187  ADC_DMACmd(pios_adc_dev->cfg->adc_dev_master, ENABLE);
188 
189  /* Configure input scan */
190  for (int32_t i = 0; i < pios_adc_dev->cfg->adc_pin_count; i++) {
191  ADC_RegularChannelConfig(pios_adc_dev->cfg->adc_dev_master,
192  pios_adc_dev->cfg->adc_pins[i].adc_channel,
193  i+1,
194  ADC_SampleTime_480Cycles);
195  }
196 
197  /* After one scan, keep generating requests */
198  ADC_DMARequestAfterLastTransferCmd(pios_adc_dev->cfg->adc_dev_master, ENABLE);
199 
200  /* Finally start initial conversion */
201  ADC_Cmd(pios_adc_dev->cfg->adc_dev_master, ENABLE);
202  ADC_ContinuousModeCmd(pios_adc_dev->cfg->adc_dev_master, ENABLE);
203  ADC_SoftwareStartConv(pios_adc_dev->cfg->adc_dev_master);
204 }
205 
206 static bool PIOS_INTERNAL_ADC_validate(struct pios_internal_adc_dev * dev)
207 {
208  if (dev == NULL)
209  return false;
210 
211  return (dev->magic == PIOS_INTERNAL_ADC_DEV_MAGIC);
212 }
213 
214 static struct pios_internal_adc_dev * PIOS_INTERNAL_ADC_Allocate(const struct pios_internal_adc_cfg * cfg)
215 {
216  struct pios_internal_adc_dev * adc_dev;
217 
218  adc_dev = (struct pios_internal_adc_dev *)PIOS_malloc_no_dma(sizeof(*adc_dev));
219  if (!adc_dev) {
220  return NULL;
221  }
222 
223  accumulator = (struct adc_accumulator *)PIOS_malloc_no_dma(cfg->adc_pin_count * sizeof(struct adc_accumulator));
224  if (!accumulator) {
225  PIOS_free(adc_dev);
226  return NULL;
227  }
228 
229  adc_raw_buffer_0 = (uint16_t *)PIOS_malloc(PIOS_ADC_MAX_OVERSAMPLING * cfg->adc_pin_count * sizeof(uint16_t));
230  if (!adc_raw_buffer_0) {
231  PIOS_free(adc_dev);
232  PIOS_free(accumulator);
233  return NULL;
234  }
235 
236  adc_raw_buffer_1 = (uint16_t *)PIOS_malloc(PIOS_ADC_MAX_OVERSAMPLING * cfg->adc_pin_count * sizeof(uint16_t));
237  if (!adc_raw_buffer_1) {
238  PIOS_free(adc_dev);
239  PIOS_free(accumulator);
240  PIOS_free(adc_raw_buffer_0);
241  return NULL;
242  }
243 
244  adc_dev->magic = PIOS_INTERNAL_ADC_DEV_MAGIC;
245  return(adc_dev);
246 }
247 
251 int32_t PIOS_INTERNAL_ADC_Init(uintptr_t * internal_adc_id, const struct pios_internal_adc_cfg * cfg)
252 {
253  pios_adc_dev = PIOS_INTERNAL_ADC_Allocate(cfg);
254  if (pios_adc_dev == NULL)
255  return -1;
256 
257  pios_adc_dev->cfg = cfg;
258 
259 #if defined(PIOS_INCLUDE_ADC)
260  init_pins();
261  init_dma();
262  init_adc();
263 #endif
264  *internal_adc_id = (uintptr_t)pios_adc_dev;
265  return 0;
266 }
267 
277 static int32_t PIOS_INTERNAL_ADC_PinGet(uintptr_t internal_adc_id, uint32_t pin)
278 {
279 #if defined(PIOS_INCLUDE_ADC)
280  int32_t result;
281 
282  if (!PIOS_INTERNAL_ADC_validate(pios_adc_dev)) {
283  return -1;
284  }
285 
286  /* Check if pin exists */
287  if (pin >= pios_adc_dev->cfg->adc_pin_count) {
288  return -2;
289  }
290 
291  if (accumulator[pin].accumulator <= 0) {
292  return -3;
293  }
294 
295  /* return accumulated result and clear accumulator */
296  result = accumulator[pin].accumulator /
297  (accumulator[pin].count ? accumulator[pin].count : 1);
298  accumulator[pin].accumulator = result;
299  accumulator[pin].count = 1;
300 
301  return result;
302 #endif
303  return -1;
304 }
305 
309 static inline void accumulate(uint16_t *buffer, uint32_t count)
310 {
311 #if defined(PIOS_INCLUDE_ADC)
312  uint16_t *sp = buffer;
313  if (!PIOS_INTERNAL_ADC_validate(pios_adc_dev)) {
314  return;
315  }
316 
317  /*
318  * Accumulate sampled values.
319  */
320  while (count--) {
321  for (int i = 0; i < pios_adc_dev->cfg->adc_pin_count; i++) {
322  accumulator[i].accumulator += *(sp++);
323  accumulator[i].count++;
324  /*
325  * If the accumulator reaches half-full, rescale in order to
326  * make more space.
327  */
328  if (accumulator[i].accumulator >= (1 << 31)) {
329  accumulator[i].accumulator /= 2;
330  accumulator[i].count /= 2;
331  }
332  }
333  }
334 
335 #endif
336 }
337 
344 {
346 
347  if (!PIOS_INTERNAL_ADC_validate(pios_adc_dev))
348  goto out;
349 
350 #if defined(PIOS_INCLUDE_ADC)
351  /* terminal count, buffer has flipped */
352  if (DMA_GetITStatus(pios_adc_dev->cfg->dma.rx.channel, pios_adc_dev->cfg->full_flag)) {
353  DMA_ClearITPendingBit(pios_adc_dev->cfg->dma.rx.channel, pios_adc_dev->cfg->full_flag);
354 
355  /* accumulate results from the buffer that was just completed */
356  if (DMA_GetCurrentMemoryTarget(pios_adc_dev->cfg->dma.rx.channel) == 0) {
357  accumulate(adc_raw_buffer_0, PIOS_ADC_MAX_OVERSAMPLING);
358  }
359  else {
360  accumulate(adc_raw_buffer_1, PIOS_ADC_MAX_OVERSAMPLING);
361  }
362  }
363 #endif
364 
365 out:
367 }
368 
374 static uint8_t PIOS_INTERNAL_ADC_Number_of_Channels(uintptr_t internal_adc_id)
375 {
376  struct pios_internal_adc_dev * adc_dev = (struct pios_internal_adc_dev *)internal_adc_id;
377  if(!PIOS_INTERNAL_ADC_validate(adc_dev))
378  return 0;
379  return adc_dev->cfg->adc_pin_count;
380 }
381 
385 static float PIOS_INTERNAL_ADC_LSB_Voltage(uintptr_t internal_adc_id)
386 {
387  struct pios_internal_adc_dev * adc_dev = (struct pios_internal_adc_dev *) internal_adc_id;
388  if (!PIOS_INTERNAL_ADC_validate(adc_dev)) {
389  return 0;
390  }
391  return VREF_PLUS / (((uint32_t)1 << 16) - 16);
392 }
393 #endif /* PIOS_INCLUDE_ADC */
394 
Main PiOS header to include all the compiled in PiOS options.
const uint8_t count
Definition: panel.c:515
int32_t PIOS_INTERNAL_ADC_Init(uintptr_t *internal_adc_id, const struct pios_internal_adc_cfg *cfg)
#define PIOS_IRQ_Epilogue()
Definition: pios_irq.h:46
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
void * PIOS_malloc_no_dma(size_t size)
Definition: pios_heap.c:166
void PIOS_INTERNAL_ADC_DMA_Handler()
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
const struct pios_adc_driver pios_internal_adc_driver
#define VREF_PLUS
Definition: pios_board.h:222
uint8_t i
Definition: msp_messages.h:97
ADC private definitions.
uint32_t magic
void PIOS_free(void *buf)
Definition: pios_heap.c:174
#define PIOS_ADC_MAX_OVERSAMPLING
Definition: pios_board.h:221
#define PIOS_IRQ_Prologue()
Definition: pios_irq.h:45
int32_t(* get_pin)(uintptr_t id, uint32_t pin)
Definition: pios_adc.h:41