dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_internal_adc_light.c
Go to the documentation of this file.
1 
13 /*
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  * for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, see <http://www.gnu.org/licenses/>
26  */
27 
28 #include <pios_internal_adc_priv.h>
29 
30 #if defined(PIOS_INCLUDE_ADC)
31 
32 static intptr_t PIOS_INTERNAL_ADC_PinConfig(uint32_t internal_adc_id);
33 static void PIOS_INTERNAL_DMAConfig(uintptr_t internal_adc_id);
34 intptr_t PIOS_INTERNAL_ADC_LIGHT_Init(uint32_t *internal_adc_id,
35  const struct pios_internal_adc_cfg *cfg,
36  uint16_t number_of_used_pins);
37 static void PIOS_INTERNAL_ADC_Converter_Config(uintptr_t internal_adc_id);
38 static intptr_t PIOS_INTERNAL_ADC_PinGet(uint32_t internal_adc_id, uint32_t pin);
39 static uint8_t PIOS_INTERNAL_ADC_NumberOfChannels(uintptr_t internal_adc_id);
40 static float PIOS_INTERNAL_ADC_LSB_Voltage(uintptr_t internal_adc_id);
41 
43  .get_pin = PIOS_INTERNAL_ADC_PinGet,
44  .number_of_channels = PIOS_INTERNAL_ADC_NumberOfChannels,
45  .lsb_voltage = PIOS_INTERNAL_ADC_LSB_Voltage,
46 };
47 
48 // Private types
49 enum pios_internal_adc_dev_magic {
50  PIOS_INTERNAL_ADC_DEV_MAGIC = 0xBD37C124,
51 };
52 
53 struct pios_internal_adc_dev {
54  const struct pios_internal_adc_cfg *cfg;
55  uint16_t number_of_used_pins;
56  uint16_t dma_transfer_size;
57  volatile uint16_t *raw_data_buffer;
58  enum pios_internal_adc_dev_magic magic;
59 };
60 
65 static bool PIOS_INTERNAL_ADC_validate(struct pios_internal_adc_dev * dev)
66 {
67  if(dev == NULL)
68  return false;
69 
70  return (dev->magic == PIOS_INTERNAL_ADC_DEV_MAGIC);
71 }
72 
76 static struct pios_internal_adc_dev * PIOS_INTERNAL_ADC_Allocate()
77 {
78  struct pios_internal_adc_dev *adc_dev = (struct pios_internal_adc_dev *)PIOS_malloc(sizeof(*adc_dev));
79  if(!adc_dev)
80  return (NULL );
81  adc_dev->magic = PIOS_INTERNAL_ADC_DEV_MAGIC;
82  return (adc_dev);
83 }
84 
89 static intptr_t PIOS_INTERNAL_ADC_PinConfig(uint32_t internal_adc_id)
90 {
91  struct pios_internal_adc_dev * adc_dev = (struct pios_internal_adc_dev *) internal_adc_id;
92  if(!PIOS_INTERNAL_ADC_validate(adc_dev)) {
93  return -1;
94  }
95 
96  /* Setup analog pins */
97  GPIO_InitTypeDef GPIO_InitStructure;
98  GPIO_StructInit(&GPIO_InitStructure);
99  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
100  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
101 
102  for(int32_t i = 0; i < adc_dev->number_of_used_pins; i++) {
103  if(adc_dev->cfg->adc_pins[i].port == NULL )
104  continue;
105  // This driver only supports ADC1
106  if(!adc_dev->cfg->adc_pins[i].is_master_channel)
107  return -2;
108  GPIO_InitStructure.GPIO_Pin = adc_dev->cfg->adc_pins[i].pin;
109  GPIO_Init(adc_dev->cfg->adc_pins[i].port, (GPIO_InitTypeDef*) &GPIO_InitStructure);
110  }
111 
112  return 0;
113 }
118 static void PIOS_INTERNAL_DMAConfig(uintptr_t internal_adc_id)
119 {
120  struct pios_internal_adc_dev * adc_dev = (struct pios_internal_adc_dev *) internal_adc_id;
121  if(!PIOS_INTERNAL_ADC_validate(adc_dev)) {
122  return;
123  }
124 
125  /* Disable interrupts */
126  DMA_ITConfig(adc_dev->cfg->dma.rx.channel, adc_dev->cfg->dma.irq.flags, DISABLE);
127 
128  /* Configure DMA channel */
129  DMA_DeInit(adc_dev->cfg->dma.rx.channel);
130 
131  RCC_AHBPeriphClockCmd(adc_dev->cfg->dma.ahb_clk, ENABLE);
132 
133  DMA_InitTypeDef DMAInit = adc_dev->cfg->dma.rx.init;
134 
135  DMAInit.DMA_PeripheralBaseAddr = (uint32_t) &adc_dev->cfg->adc_dev_master->DR;
136  DMAInit.DMA_MemoryBaseAddr = (uint32_t) adc_dev->raw_data_buffer;
137  DMAInit.DMA_BufferSize = adc_dev->dma_transfer_size;
138  DMAInit.DMA_DIR = DMA_DIR_PeripheralSRC;
139  DMAInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
140  DMAInit.DMA_MemoryInc = DMA_MemoryInc_Enable;
141  DMAInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
142  DMAInit.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
143  DMAInit.DMA_Mode = DMA_Mode_Circular;
144  DMAInit.DMA_M2M = DMA_M2M_Disable;
145 
146  DMA_Init(adc_dev->cfg->dma.rx.channel, &DMAInit); /* channel is actually stream ... */
147 
148  /* enable DMA */
149  DMA_Cmd(adc_dev->cfg->dma.rx.channel, ENABLE);
150 }
155 static void PIOS_INTERNAL_ADC_Converter_Config(uintptr_t internal_adc_id)
156 {
157  struct pios_internal_adc_dev * adc_dev = (struct pios_internal_adc_dev *) internal_adc_id;
158 
159  ADC_DeInit(adc_dev->cfg->adc_dev_master);
160 
161  if(adc_dev->cfg->adc_dev_master == ADC1)
162  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
163  else
164  return;
165 
166  RCC_ADCCLKConfig(RCC_PCLK2_Div8);
167 
168  for(int32_t i = 0; i < adc_dev->number_of_used_pins; i++) {
169  ADC_RegularChannelConfig(ADC1, adc_dev->cfg->adc_pins[i].adc_channel,
170  i + 1, ADC_SampleTime_239Cycles5);
171  }
172 
173  ADC_InitTypeDef ADC_InitStructure;
174  ADC_StructInit(&ADC_InitStructure);
175 
176  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
177  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
178  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
179  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
180  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
181  ADC_InitStructure.ADC_NbrOfChannel = adc_dev->number_of_used_pins;
182 
183  ADC_Init(adc_dev->cfg->adc_dev_master, &ADC_InitStructure);
184 
185  ADC_Cmd(adc_dev->cfg->adc_dev_master, ENABLE);
186 
187  PIOS_DELAY_WaituS(10);
188  ADC_ResetCalibration(adc_dev->cfg->adc_dev_master);
189  while(ADC_GetResetCalibrationStatus(adc_dev->cfg->adc_dev_master));
190  ADC_StartCalibration(adc_dev->cfg->adc_dev_master);
191  while (ADC_GetCalibrationStatus(adc_dev->cfg->adc_dev_master));
192 
193  /* Enable ADC->DMA request */
194  ADC_DMACmd(adc_dev->cfg->adc_dev_master, ENABLE);
195 
196  PIOS_DELAY_WaituS(10);
197  ADC_SoftwareStartConvCmd(adc_dev->cfg->adc_dev_master, ENABLE);
198 }
199 
203 intptr_t PIOS_INTERNAL_ADC_LIGHT_Init(uint32_t *internal_adc_id,
204  const struct pios_internal_adc_cfg *cfg,
205  uint16_t number_of_used_pins)
206 {
207  PIOS_DEBUG_Assert(internal_adc_id); PIOS_DEBUG_Assert(cfg);
208 
209  // Only ADC1 is supported by this driver
210  if(cfg->adc_dev_master != ADC1)
211  return -2;
212 
213  struct pios_internal_adc_dev * adc_dev;
214  adc_dev = PIOS_INTERNAL_ADC_Allocate();
215  if(adc_dev == NULL )
216  return -1;
217  adc_dev->cfg = cfg;
218  adc_dev->number_of_used_pins = number_of_used_pins;
219 
220  *internal_adc_id = (uint32_t) adc_dev;
221 
222  // DMA transfer size in units defined by DMA_PeripheralDataSize, 32bits for dual mode and 16bits for single mode
223  adc_dev->dma_transfer_size = adc_dev->number_of_used_pins;
224  adc_dev->raw_data_buffer = PIOS_malloc(adc_dev->dma_transfer_size * sizeof(uint16_t));
225  if (adc_dev->raw_data_buffer == NULL )
226  return -1;
227 
228  if(PIOS_INTERNAL_ADC_PinConfig((uint32_t) adc_dev) != 0)
229  return -3;
230 
231  PIOS_INTERNAL_DMAConfig((uint32_t) adc_dev);
232 
233  PIOS_INTERNAL_ADC_Converter_Config((uint32_t) adc_dev);
234  return 0;
235 }
236 
242 static uint8_t PIOS_INTERNAL_ADC_NumberOfChannels(uintptr_t internal_adc_id)
243 {
244  struct pios_internal_adc_dev * adc_dev = (struct pios_internal_adc_dev *) internal_adc_id;
245  if(!PIOS_INTERNAL_ADC_validate(adc_dev))
246  return 0;
247  return adc_dev->number_of_used_pins;
248 
249 }
250 
257 static intptr_t PIOS_INTERNAL_ADC_PinGet(uintptr_t internal_adc_id, uint32_t pin)
258 {
259  struct pios_internal_adc_dev * adc_dev = (struct pios_internal_adc_dev *) internal_adc_id;
260 
261  /* Check if pin exists */
262  if(pin >= adc_dev->number_of_used_pins) {
263  return -1;
264  }
265 
266  /* This results in a half-word load (2 cycles) of the volatile buffer location
267  written by DMA. The buffer is dynamically allocated and thus will always be aligned.
268  A barrier is not required for this on Cortex-M. See ARM App. Note 321 */
269  return adc_dev->raw_data_buffer[pin];
270 }
271 
275 static float PIOS_INTERNAL_ADC_LSB_Voltage(uintptr_t internal_adc_id)
276 {
277  struct pios_internal_adc_dev * adc_dev = (struct pios_internal_adc_dev *) internal_adc_id;
278  if(!PIOS_INTERNAL_ADC_validate(adc_dev)) {
279  return 0;
280  }
281  return VREF_PLUS / (((uint32_t)1 << 12) - 1);
282 }
283 #endif /* PIOS_INCLUDE_ADC */
284 
#define PIOS_DEBUG_Assert(test)
Definition: pios_debug.h:51
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
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
int32_t PIOS_INTERNAL_ADC_LIGHT_Init(uintptr_t *internal_adc_id, const struct pios_internal_adc_cfg *cfg, uint16_t number_of_used_pins)
int32_t(* get_pin)(uintptr_t id, uint32_t pin)
Definition: pios_adc.h:41
int32_t PIOS_DELAY_WaituS(uint32_t uS)
Definition: pios_delay.c:116