PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/flight/pios/stm32f0x/pios_adc.c

https://gitlab.com/sonium/librepilot
C | 391 lines | 228 code | 57 blank | 106 comment | 24 complexity | 3bef62634dbf6eccdfc6483096f831d3 MD5 | raw file
  1. /**
  2. ******************************************************************************
  3. * @addtogroup PIOS PIOS Core hardware abstraction layer
  4. * @{
  5. * @addtogroup PIOS_ADC ADC Functions
  6. * @brief STM32 ADC PIOS interface
  7. * @{
  8. *
  9. * @file pios_adc.c
  10. * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
  11. * @brief Analog to Digital converstion routines
  12. * @see The GNU Public License (GPL) Version 3
  13. *****************************************************************************/
  14. /*
  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.
  19. *
  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.
  24. *
  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
  28. */
  29. #include "pios.h"
  30. #ifdef PIOS_INCLUDE_ADC
  31. #include <pios_adc_priv.h>
  32. // Private types
  33. enum pios_adc_dev_magic {
  34. PIOS_ADC_DEV_MAGIC = 0x58375124,
  35. };
  36. struct pios_adc_dev {
  37. const struct pios_adc_cfg *cfg;
  38. ADCCallback callback_function;
  39. #if defined(PIOS_INCLUDE_FREERTOS)
  40. xQueueHandle data_queue;
  41. #endif
  42. volatile int16_t *valid_data_buffer;
  43. volatile uint8_t adc_oversample;
  44. uint8_t dma_block_size;
  45. uint16_t dma_half_buffer_size;
  46. #if defined(PIOS_INCLUDE_ADC)
  47. int16_t fir_coeffs[PIOS_ADC_MAX_SAMPLES + 1] __attribute__((aligned(4)));
  48. volatile int16_t raw_data_buffer[PIOS_ADC_MAX_SAMPLES] __attribute__((aligned(4))); // Double buffer that DMA just used
  49. float downsampled_buffer[PIOS_ADC_NUM_CHANNELS] __attribute__((aligned(4)));
  50. #endif
  51. enum pios_adc_dev_magic magic;
  52. };
  53. float PIOS_ADC_PinGetVolt(uint32_t pin)
  54. {
  55. return ((float)PIOS_ADC_PinGet(pin)) * PIOS_ADC_VOLTAGE_SCALE;
  56. }
  57. #if defined(PIOS_INCLUDE_FREERTOS)
  58. struct pios_adc_dev *pios_adc_dev;
  59. #endif
  60. // Private functions
  61. void PIOS_ADC_downsample_data();
  62. static struct pios_adc_dev *PIOS_ADC_Allocate();
  63. static bool PIOS_ADC_validate(struct pios_adc_dev *);
  64. /* Local Variables */
  65. static GPIO_TypeDef *ADC_GPIO_PORT[PIOS_ADC_NUM_PINS] = PIOS_ADC_PORTS;
  66. static const uint32_t ADC_GPIO_PIN[PIOS_ADC_NUM_PINS] = PIOS_ADC_PINS;
  67. static const uint32_t ADC_CHANNEL[PIOS_ADC_NUM_PINS] = PIOS_ADC_CHANNELS;
  68. static ADC_TypeDef *ADC_MAPPING[PIOS_ADC_NUM_PINS] = PIOS_ADC_MAPPING;
  69. static const uint32_t ADC_CHANNEL_MAPPING[PIOS_ADC_NUM_PINS] = PIOS_ADC_CHANNEL_MAPPING;
  70. static bool PIOS_ADC_validate(struct pios_adc_dev *dev)
  71. {
  72. if (dev == NULL) {
  73. return false;
  74. }
  75. return dev->magic == PIOS_ADC_DEV_MAGIC;
  76. }
  77. #if defined(PIOS_INCLUDE_FREERTOS)
  78. static struct pios_adc_dev *PIOS_ADC_Allocate()
  79. {
  80. struct pios_adc_dev *adc_dev;
  81. adc_dev = (struct pios_adc_dev *)pvPortMalloc(sizeof(*adc_dev));
  82. if (!adc_dev) {
  83. return NULL;
  84. }
  85. adc_dev->magic = PIOS_ADC_DEV_MAGIC;
  86. return adc_dev;
  87. }
  88. #else
  89. #error Not implemented
  90. #endif
  91. /**
  92. * @brief Initialise the ADC Peripheral, configure to run at the max oversampling
  93. */
  94. int32_t PIOS_ADC_Init(const struct pios_adc_cfg *cfg)
  95. {
  96. pios_adc_dev = PIOS_ADC_Allocate();
  97. if (pios_adc_dev == NULL) {
  98. return -1;
  99. }
  100. pios_adc_dev->cfg = cfg;
  101. pios_adc_dev->callback_function = NULL;
  102. #if defined(PIOS_INCLUDE_FREERTOS)
  103. pios_adc_dev->data_queue = NULL;
  104. #endif
  105. /* Setup analog pins */
  106. GPIO_InitTypeDef GPIO_InitStructure;
  107. GPIO_StructInit(&GPIO_InitStructure);
  108. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  109. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  110. /* Enable each ADC pin in the array */
  111. for (int32_t i = 0; i < PIOS_ADC_NUM_PINS; i++) {
  112. GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN[i];
  113. GPIO_Init(ADC_GPIO_PORT[i], &GPIO_InitStructure);
  114. }
  115. PIOS_ADC_Config(PIOS_ADC_MAX_OVERSAMPLING);
  116. return 0;
  117. }
  118. /**
  119. * @brief Configure the ADC to run at a fixed oversampling
  120. * @param[in] oversampling the amount of oversampling to run at
  121. */
  122. void PIOS_ADC_Config(uint32_t oversampling)
  123. {
  124. pios_adc_dev->adc_oversample = (oversampling > PIOS_ADC_MAX_OVERSAMPLING) ? PIOS_ADC_MAX_OVERSAMPLING : oversampling;
  125. ADC_DeInit(ADC1);
  126. ADC_DeInit(ADC2);
  127. /* Disable interrupts */
  128. DMA_ITConfig(pios_adc_dev->cfg->dma.rx.channel, pios_adc_dev->cfg->dma.irq.flags, DISABLE);
  129. /* Enable ADC clocks */
  130. PIOS_ADC_CLOCK_FUNCTION;
  131. /* Map channels to conversion slots depending on the channel selection mask */
  132. for (int32_t i = 0; i < PIOS_ADC_NUM_PINS; i++) {
  133. ADC_RegularChannelConfig(ADC_MAPPING[i], ADC_CHANNEL[i],
  134. ADC_CHANNEL_MAPPING[i],
  135. PIOS_ADC_SAMPLE_TIME);
  136. }
  137. #if (PIOS_ADC_USE_TEMP_SENSOR)
  138. ADC_TempSensorVrefintCmd(ENABLE);
  139. ADC_RegularChannelConfig(PIOS_ADC_TEMP_SENSOR_ADC, ADC_Channel_16,
  140. PIOS_ADC_TEMP_SENSOR_ADC_CHANNEL,
  141. PIOS_ADC_SAMPLE_TIME);
  142. #endif
  143. // return
  144. /* Configure ADCs */
  145. ADC_InitTypeDef ADC_InitStructure;
  146. ADC_StructInit(&ADC_InitStructure);
  147. ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;
  148. ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  149. ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  150. ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  151. ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  152. ADC_InitStructure.ADC_NbrOfChannel = ((PIOS_ADC_NUM_CHANNELS + 1) >> 1);
  153. ADC_Init(ADC1, &ADC_InitStructure);
  154. #if (PIOS_ADC_USE_ADC2)
  155. ADC_Init(ADC2, &ADC_InitStructure);
  156. /* Enable ADC2 external trigger conversion (to synch with ADC1) */
  157. ADC_ExternalTrigConvCmd(ADC2, ENABLE);
  158. #endif
  159. RCC_ADCCLKConfig(PIOS_ADC_ADCCLK);
  160. /* Enable ADC1->DMA request */
  161. ADC_DMACmd(ADC1, ENABLE);
  162. /* ADC1 calibration */
  163. ADC_Cmd(ADC1, ENABLE);
  164. ADC_ResetCalibration(ADC1);
  165. while (ADC_GetResetCalibrationStatus(ADC1)) {
  166. ;
  167. }
  168. ADC_StartCalibration(ADC1);
  169. while (ADC_GetCalibrationStatus(ADC1)) {
  170. ;
  171. }
  172. #if (PIOS_ADC_USE_ADC2)
  173. /* ADC2 calibration */
  174. ADC_Cmd(ADC2, ENABLE);
  175. ADC_ResetCalibration(ADC2);
  176. while (ADC_GetResetCalibrationStatus(ADC2)) {
  177. ;
  178. }
  179. ADC_StartCalibration(ADC2);
  180. while (ADC_GetCalibrationStatus(ADC2)) {
  181. ;
  182. }
  183. #endif
  184. /* This makes sure we have an even number of transfers if using ADC2 */
  185. pios_adc_dev->dma_block_size = ((PIOS_ADC_NUM_CHANNELS + PIOS_ADC_USE_ADC2) >> PIOS_ADC_USE_ADC2) << PIOS_ADC_USE_ADC2;
  186. pios_adc_dev->dma_half_buffer_size = pios_adc_dev->dma_block_size * pios_adc_dev->adc_oversample;
  187. /* Configure DMA channel */
  188. DMA_InitTypeDef dma_init = pios_adc_dev->cfg->dma.rx.init;
  189. dma_init.DMA_MemoryBaseAddr = (uint32_t)&pios_adc_dev->raw_data_buffer[0];
  190. dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
  191. dma_init.DMA_BufferSize = pios_adc_dev->dma_half_buffer_size; /* x2 for double buffer /2 for 32-bit xfr */
  192. DMA_Init(pios_adc_dev->cfg->dma.rx.channel, &dma_init);
  193. DMA_Cmd(pios_adc_dev->cfg->dma.rx.channel, ENABLE);
  194. /* Trigger interrupt when for half conversions too to indicate double buffer */
  195. DMA_ITConfig(pios_adc_dev->cfg->dma.rx.channel, DMA_IT_TC, ENABLE);
  196. DMA_ITConfig(pios_adc_dev->cfg->dma.rx.channel, DMA_IT_HT, ENABLE);
  197. /* Configure DMA interrupt */
  198. NVIC_Init(&pios_adc_dev->cfg->dma.irq.init);
  199. /* Finally start initial conversion */
  200. ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  201. /* Use simple averaging filter for now */
  202. for (int32_t i = 0; i < pios_adc_dev->adc_oversample; i++) {
  203. pios_adc_dev->fir_coeffs[i] = 1;
  204. }
  205. pios_adc_dev->fir_coeffs[pios_adc_dev->adc_oversample] = pios_adc_dev->adc_oversample;
  206. /* Enable DMA1 clock */
  207. RCC_AHBPeriphClockCmd(pios_adc_dev->cfg->dma.ahb_clk, ENABLE);
  208. }
  209. /**
  210. * Returns value of an ADC Pin
  211. * \param[in] pin number
  212. * \return ADC pin value - resolution depends on the selected oversampling rate
  213. * \return -1 if pin doesn't exist
  214. */
  215. int32_t PIOS_ADC_PinGet(uint32_t pin)
  216. {
  217. /* Check if pin exists */
  218. if (pin >= PIOS_ADC_NUM_CHANNELS) {
  219. return -1;
  220. }
  221. /* Return last conversion result */
  222. return pios_adc_dev->downsampled_buffer[pin];
  223. }
  224. /**
  225. * @brief Set a callback function that is executed whenever
  226. * the ADC double buffer swaps
  227. */
  228. void PIOS_ADC_SetCallback(ADCCallback new_function)
  229. {
  230. pios_adc_dev->callback_function = new_function;
  231. }
  232. #if defined(PIOS_INCLUDE_FREERTOS)
  233. /**
  234. * @brief Register a queue to add data to when downsampled
  235. */
  236. void PIOS_ADC_SetQueue(xQueueHandle data_queue)
  237. {
  238. pios_adc_dev->data_queue = data_queue;
  239. }
  240. #endif
  241. /**
  242. * @brief Return the address of the downsampled data buffer
  243. */
  244. float *PIOS_ADC_GetBuffer(void)
  245. {
  246. return pios_adc_dev->downsampled_buffer;
  247. }
  248. /**
  249. * @brief Return the address of the raw data data buffer
  250. */
  251. int16_t *PIOS_ADC_GetRawBuffer(void)
  252. {
  253. return (int16_t *)pios_adc_dev->valid_data_buffer;
  254. }
  255. /**
  256. * @brief Return the amount of over sampling
  257. */
  258. uint8_t PIOS_ADC_GetOverSampling(void)
  259. {
  260. return pios_adc_dev->adc_oversample;
  261. }
  262. /**
  263. * @brief Set the fir coefficients. Takes as many samples as the
  264. * current filter order plus one (normalization)
  265. *
  266. * @param new_filter Array of adc_oversampling floats plus one for the
  267. * filter coefficients
  268. */
  269. void PIOS_ADC_SetFIRCoefficients(float *new_filter)
  270. {
  271. // Less than or equal to get normalization constant
  272. for (int i = 0; i <= pios_adc_dev->adc_oversample; i++) {
  273. pios_adc_dev->fir_coeffs[i] = new_filter[i];
  274. }
  275. }
  276. /**
  277. * @brief Downsample the data for each of the channels then call
  278. * callback function if installed
  279. */
  280. void PIOS_ADC_downsample_data()
  281. {
  282. uint16_t chan;
  283. uint16_t sample;
  284. float *downsampled_buffer = &pios_adc_dev->downsampled_buffer[0];
  285. for (chan = 0; chan < PIOS_ADC_NUM_CHANNELS; chan++) {
  286. int32_t sum = 0;
  287. for (sample = 0; sample < pios_adc_dev->adc_oversample; sample++) {
  288. sum += pios_adc_dev->valid_data_buffer[chan + sample * pios_adc_dev->dma_block_size] * pios_adc_dev->fir_coeffs[sample];
  289. }
  290. downsampled_buffer[chan] = (float)sum / pios_adc_dev->fir_coeffs[pios_adc_dev->adc_oversample];
  291. }
  292. #if defined(PIOS_INCLUDE_FREERTOS)
  293. if (pios_adc_dev->data_queue) {
  294. static portBASE_TYPE xHigherPriorityTaskWoken;
  295. xQueueSendFromISR(pios_adc_dev->data_queue, pios_adc_dev->downsampled_buffer, &xHigherPriorityTaskWoken);
  296. portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
  297. }
  298. #endif
  299. if (pios_adc_dev->callback_function) {
  300. pios_adc_dev->callback_function(pios_adc_dev->downsampled_buffer);
  301. }
  302. }
  303. /**
  304. * @brief Interrupt for half and full buffer transfer
  305. *
  306. * This interrupt handler swaps between the two halfs of the double buffer to make
  307. * sure the ahrs uses the most recent data. Only swaps data when AHRS is idle, but
  308. * really this is a pretense of a sanity check since the DMA engine is consantly
  309. * running in the background. Keep an eye on the ekf_too_slow variable to make sure
  310. * it's keeping up.
  311. */
  312. void PIOS_ADC_DMA_Handler(void)
  313. {
  314. if (!PIOS_ADC_validate(pios_adc_dev)) {
  315. return;
  316. }
  317. if (DMA_GetFlagStatus(pios_adc_dev->cfg->full_flag /*DMA1_IT_TC1*/)) { // whole double buffer filled
  318. pios_adc_dev->valid_data_buffer = &pios_adc_dev->raw_data_buffer[pios_adc_dev->dma_half_buffer_size];
  319. DMA_ClearFlag(pios_adc_dev->cfg->full_flag);
  320. PIOS_ADC_downsample_data();
  321. } else if (DMA_GetFlagStatus(pios_adc_dev->cfg->half_flag /*DMA1_IT_HT1*/)) {
  322. pios_adc_dev->valid_data_buffer = &pios_adc_dev->raw_data_buffer[0];
  323. DMA_ClearFlag(pios_adc_dev->cfg->half_flag);
  324. PIOS_ADC_downsample_data();
  325. } else {
  326. // This should not happen, probably due to transfer errors
  327. DMA_ClearFlag(pios_adc_dev->cfg->dma.irq.flags /*DMA1_FLAG_GL1*/);
  328. }
  329. }
  330. #endif /* PIOS_INCLUDE_ADC */
  331. /**
  332. * @}
  333. * @}
  334. */