source: test2.git/Adc.c

Last change on this file was b6aa0ba, checked in by andib <andi.b@…>, 2 years ago

test with more files

  • Property mode set to 100644
File size: 15.1 KB
RevLine 
[b6aa0ba]1/*******************************************************************************
2MODULE : Adc.c
3 Starting with JADE ADC is configured to run in EM2 without any CPU
4 intervention. LETIMER0 is used to trigger ADC via PRS and LDMA transfers
5 results into adcBuffer. LETIMER0 runs at 1kHz. So every 1ms new ADC samples
6 are transferd to the buffer. Based on github adc_scan_letimer_prs_dma sample
7
8 ToDo: Check aquisition time, accuracy and influence from neighbor channels
9
1020110530 AB Initial
1120150407 AB Adapted for USV_BatteryMonitor Slave, remove LEDs and Testpins
1220191212 AB JADE EFM32JG1B test with lot of channels
13*******************************************************************************/
14
15// --- Includes ---------------------------------------------------------------
16#define LOGGING_TOKEN ADC_LOGGING
17#include "TraceLeUart.h"
18
19#include "em_device.h"
20#include <em_chip.h>
21#include <em_emu.h>
22#include <em_cmu.h>
23//#include <em_dma.h>
24#include <em_adc.h>
25#include <em_gpio.h>
26#include "em_letimer.h"
27#include "em_ldma.h"
28#include "em_prs.h"
29
30#include "types.h"
31#include "Adc.h"
32#include "Leds.h"
33
34// --- Pin Definitions --------------------------------------------------------
35// Testpin PF6, pinX (for search in project - Testpin_on)
36#define PORT gpioPortF
37#define PORT_BIT 6
38#define TESTPIN_INIT() { GPIO_PinModeSet(PORT, PORT_BIT, gpioModePushPull, 0);}
39#define TESTPIN( x ) { if ( x ) GPIO->P[PORT].DOUT |= ( 1 << PORT_BIT ); \
40 else GPIO->P[PORT].DOUT &= ~( 1 << PORT_BIT ); }
41
42// --- Defines ----------------------------------------------------------------
43#define ADC_BUFFER_SIZE 14 // Change this to set number of samples per interrupt
44 // AB usually same as number ob ADC channels
45#define ADC_DVL 1 // Change this to set how many samples get sent at once
46 // AB means sample sets, 1 = one time ADC_BUFFER_SIZE channels
47 // AB and then sent via DMA to BUFFER
48#define ADC_FREQ 1000000 // 16000000 is max ADC clock for Series 1
49#define letimerDesired 1000 // Desired letimer interrupt frequency (in Hz)
50 // AB max: 2300 with channels=14, FREQ=1MHz, AquTim=4
51 // AB max: ~490 with channels=14, FREQ=1MHz, AquTim=64
52 // AB max: ~1600 with channels=14, FREQ=1MHz, AquTim=32
53 // AB --> SM-C channels=10, ok
54
55#define ADC_MV( x ) ( ((adcBuffer[ x ] + 1) * 1250 << 8) / ( 4095 << 8 ) ) // 32 bit needed
56
57#define LDMA_CHANNEL 0
58#define PRS_CHANNEL 0
59
60LDMA_TransferCfg_t trans;
61LDMA_Descriptor_t descr;
62
63// --- Typedefs ---------------------------------------------------------------
64
65// --- PUBLIC Variables -------------------------------------------------------
66
67// --- Variables --------------------------------------------------------------
68static volatile BOOL bAdcIsRunning;
69static int iAdc[16]; // filtered values
70static BOOL bAdcContinousTrace;
71
72uint32_t adcBuffer[ADC_BUFFER_SIZE];
73uint32_t topValue;
74
75// --- Macros -----------------------------------------------------------------
76
77// --- Functionprototypes -----------------------------------------------------
78void AdcTrace (int iLevel);
79;
80// --- Code -------------------------------------------------------------------
81
82/**************************************************************************//**
83 * @brief LDMA Handler
84 *****************************************************************************/
85void LDMA_IRQHandler(void)
86 {
87 // Clear interrupt flag
88 TESTPIN(1);
89 LDMA_IntClear((1 << LDMA_CHANNEL) << _LDMA_IFC_DONE_SHIFT);
90 TESTPIN(0);
91
92 // check for DMA error
93 EFM_ASSERT( (LDMA_IntGet() & 0x80000000) == 0);
94 }
95
96/**************************************************************************//**
97 * @brief LETIMER initialization
98 *****************************************************************************/
99void initLetimer(void)
100 {
101 // Start LFRCO and wait until it is stable
102 CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
103
104 // Enable clock to the interface of the low energy modules
105 CMU_ClockEnable(cmuClock_HFLE, true);
106
107 // Route the LFRCO clock to LFA (LETIMER0)
108 CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
109
110 // Enable clock for LETIMER0
111 CMU_ClockEnable(cmuClock_LETIMER0, true);
112
113 LETIMER_Init_TypeDef letimerInit = LETIMER_INIT_DEFAULT;
114
115 // Reload COMP0 on underflow, pulse output, and run in repeat mode
116 letimerInit.comp0Top = true;
117 letimerInit.ufoa0 = letimerUFOAPulse;
118 letimerInit.repMode = letimerRepeatFree;
119
120 // Initialize LETIMER
121 LETIMER_Init(LETIMER0, &letimerInit);
122
123 // Need REP0 != 0 to pulse on underflow
124 LETIMER_RepeatSet(LETIMER0, 0, 1);
125
126 // calculate the topValue
127 topValue = CMU_ClockFreqGet(cmuClock_LETIMER0) / letimerDesired;
128
129 // Compare on wake-up interval count
130 LETIMER_CompareSet(LETIMER0, 0, topValue);
131
132 // Use LETIMER0 as async PRS to trigger ADC in EM2
133 CMU_ClockEnable(cmuClock_PRS, true);
134
135 PRS_SourceAsyncSignalSet(PRS_CHANNEL, PRS_CH_CTRL_SOURCESEL_LETIMER0, PRS_CH_CTRL_SIGSEL_LETIMER0CH0);
136 }
137
138/**************************************************************************//**
139 * @brief LDMA initialization
140 *****************************************************************************/
141void initLdma(void)
142 {
143 // Enable LDMA clock
144 CMU_ClockEnable(cmuClock_LDMA, true);
145
146 // Basic LDMA configuration
147 LDMA_Init_t ldmaInit = LDMA_INIT_DEFAULT;
148
149 LDMA_Init(&ldmaInit);
150
151 // Transfer triggers on ADC Scan conversion complete
152 trans = (LDMA_TransferCfg_t)LDMA_TRANSFER_CFG_PERIPHERAL(ldmaPeripheralSignal_ADC0_SCAN);
153
154 descr = (LDMA_Descriptor_t)LDMA_DESCRIPTOR_LINKREL_P2M_BYTE(
155 &(ADC0->SCANDATA), // source
156 adcBuffer, // destination
157 ADC_BUFFER_SIZE, // data transfer size
158 0); // link relative offset (links to self)
159
160 descr.xfer.blockSize = ADC_DVL-1; // transfers ADC_DVL number of units per arbitration cycle
161 descr.xfer.ignoreSrec = true; // ignores single requests to reduce energy usage
162 descr.xfer.size = ldmaCtrlSizeWord; // transfers words instead of bytes
163
164 // Initialize LDMA transfer
165 LDMA_StartTransfer(LDMA_CHANNEL, &trans, &descr);
166
167 // Clear pending and enable interrupts for channel
168 NVIC_ClearPendingIRQ(LDMA_IRQn);
169 NVIC_SetPriority(LDMA_IRQn, 6);
170 NVIC_EnableIRQ(LDMA_IRQn);
171 }
172
173
174/******************************************************************************
175void AdcInit (void)
176 Initializes ADC module
177******************************************************************************/
178void AdcInit (void)
179 {
180 uint32_t i;
181
182 TRACE("ADC: init");
183 TESTPIN_INIT();
184
185 // Declare init structs
186 ADC_Init_TypeDef init = ADC_INIT_DEFAULT;
187 ADC_InitScan_TypeDef initScan = ADC_INITSCAN_DEFAULT;
188
189 // Enable ADC clock
190 CMU_ClockEnable(cmuClock_ADC0, true);
191 CMU_ClockEnable(cmuClock_HFPER, true);
192
193 // Select AUXHFRCO for ADC ASYNC mode so it can run in EM2
194 CMU->ADCCTRL = CMU_ADCCTRL_ADC0CLKSEL_AUXHFRCO;
195
196 // Set AUXHFRCO frequency and use it to setup the ADC
197 CMU_AUXHFRCOFreqSet(cmuAUXHFRCOFreq_4M0Hz);
198 init.timebase = ADC_TimebaseCalc(CMU_AUXHFRCOBandGet());
199 init.prescale = ADC_PrescaleCalc(ADC_FREQ, CMU_AUXHFRCOBandGet());
200
201 // Let the ADC enable its clock on demand in EM2
202 init.em2ClockConfig = adcEm2ClockOnDemand;
203
204 // add ADC channels, sorted by groups and channels, this is the same order as they show
205 // up in the destination ADC buffer
206 // PORT to GROUP assignment is restricted by chip hardware, see reference manual and
207 // check assertEFM() in ADC_ScanSingleEndedInputAdd() (debug builds only)
208 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup0, adcPosSelAPORT3XCH8); /* PA0 */ // option
209 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup0, adcPosSelAPORT3YCH9); /* PA1 */ // Ext. Driven on STK //option
210 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup0, adcPosSelAPORT3XCH10); /* PA2 */
211 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup0, adcPosSelAPORT3YCH11); /* PA3 */ // Ext. Driven on STK
212 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup0, adcPosSelAPORT3XCH12); /* PA4 */
213 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup0, adcPosSelAPORT3YCH13); /* PA5 */
214
215 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup1, adcPosSelAPORT3YCH1); /* PD9 */
216 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup1, adcPosSelAPORT3XCH2); /* PD10 */
217 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup1, adcPosSelAPORT3YCH3); /* PD11 */
218
219 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup2, adcPosSelAPORT1XCH6); /* PC6 */ // option
220 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup2, adcPosSelAPORT1YCH7); /* PC7 */
221
222 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup3, adcPosSelAPORT1XCH8); /* PC8 */
223 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup3, adcPosSelAPORT1YCH9); /* PC9 */
224 ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup3, adcPosSelAPORT1XCH10); /* PC10 */ // Ext. Driven on STK
225
226// not possible, no more groups ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup3, adcPosSelAPORT1XCH22); /* PF6 */ // option
227// not possible, no more groups ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup3, adcPosSelAPORT1YCH21); /* PF5 */ // option
228// not possible, no more groups ADC_ScanSingleEndedInputAdd(&initScan, adcScanInputGroup3, adcPosSelAPORT1YCH23); /* PF7 */ // option
229
230 // Basic ADC scan configuration
231 initScan.diff = false; // single-ended
232 initScan.reference = adcRef1V25; // 1.25V reference
233 initScan.resolution = adcRes12Bit; // 12-bit resolution
234 initScan.acqTime = adcAcqTime32; // set acquisition time to meet minimum requirements
235 // 64 to much for 14 channels and 1ms, use adcAcqTime32
236
237 // DMA is available in EM2 for processing SCANFIFO DVL request
238 initScan.scanDmaEm2Wu = 1;
239
240 // Enable PRS trigger and select channel 0
241 initScan.prsEnable = true;
242 initScan.prsSel = (ADC_PRSSEL_TypeDef) PRS_CHANNEL;
243
244 // Initialize ADC
245 ADC_Init(ADC0, &init);
246 ADC_InitScan(ADC0, &initScan);
247
248 // Set scan data valid level (DVL)
249 ADC0->SCANCTRLX = (ADC0->SCANCTRLX & ~_ADC_SCANCTRLX_DVL_MASK) | (((ADC_DVL - 1) << _ADC_SCANCTRLX_DVL_SHIFT) & _ADC_SCANCTRLX_DVL_MASK);
250
251 // Clear the SCAN FIFO
252 ADC0->SCANFIFOCLEAR = ADC_SCANFIFOCLEAR_SCANFIFOCLEAR;
253
254 bAdcContinousTrace = ON;
255
256 // fill buffers with known values, nice for debugging
257 for (i = 0; i < (sizeof(adcBuffer) / sizeof(adcBuffer[0])); i++)
258 {
259 adcBuffer[i] = i;
260 }
261 for (i = 0; i < (sizeof(iAdc) / sizeof(iAdc[0])); i++)
262 {
263 iAdc[i] = i;
264 }
265
266
267 // Setup DMA to move ADC results to user memory
268 initLdma();
269 // Set up LETIMER to trigger ADC via PRS in periodic intervals
270 initLetimer();
271
272 }
273
274/******************************************************************************
275void AdcTrace (int iLevel)
276 Traces ADC values to debug out, iLevel defines verbosity
277 3 is continous logging
278******************************************************************************/
279void AdcTrace (int iLevel)
280 {
281 int i;
282
283 bAdcContinousTrace = OFF;
284 switch(iLevel)
285 {
286 case 0:
287 TRACE("ADC:%6u%6u%6u%6u%6u%6u%6u%6u", adcBuffer[0], adcBuffer[1], adcBuffer[2], adcBuffer[3], \
288 adcBuffer[4], adcBuffer[5], adcBuffer[6], adcBuffer[7]);
289 break;
290
291 case 2:
292 TRACE("ADC: PA0 PA1 PA2 PA3 PA4 PA5 PD9 PD10 PD11 PC6 PC7 PC8 PC9 PC10");
293 TRACE("ADC:%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u [mV]", ADC_MV(0), ADC_MV(1), ADC_MV(2), \
294 ADC_MV(3), ADC_MV(4), ADC_MV(5), ADC_MV(6), ADC_MV(7), ADC_MV(8), ADC_MV(9), ADC_MV(10),\
295 ADC_MV(11), ADC_MV(12), ADC_MV(13) );
296 break;
297
298 case 4:
299 TRACE("ADC:%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u [mV]", ADC_MV(0), ADC_MV(1), ADC_MV(2), \
300 ADC_MV(3), ADC_MV(4), ADC_MV(5), ADC_MV(6), ADC_MV(7), ADC_MV(8), ADC_MV(9), ADC_MV(10),\
301 ADC_MV(11), ADC_MV(12), ADC_MV(13) );
302 break;
303
304 case 3:
305 bAdcContinousTrace = ON;
306 break;
307
308 case 1:
309 // fall through
310 default:
311 TESTPIN(1);
312 TRACE("ADC: CH 0 CH 1 CH 2 CH 3 CH 4 CH 5 CH 6 CH 7 CH 8 CH 9 CH10 CH11 CH12 CH13");
313 TRACE(" %6u%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u%6u", adcBuffer[0], adcBuffer[1], adcBuffer[2], \
314 adcBuffer[3], adcBuffer[4], adcBuffer[5], adcBuffer[6], adcBuffer[7], adcBuffer[8], \
315 adcBuffer[9], adcBuffer[10], adcBuffer[11], adcBuffer[12], adcBuffer[13]);
316 // takes less than 3ms for 14 channels
317 TESTPIN(0);
318
319 // test conversion speed
320 TESTPIN(1);
321 for (i = 0; i < 14; i++)
322 {
323 iAdc[i] = ADC_MV(i);
324 }
325 // converting 14 channels to mV takes 27us
326 TESTPIN(0);
327 break;
328 }
329 return;
330 }
331
332/******************************************************************************
333void AdcTicker10ms (void)
334 Periodically 10ms tasks
335******************************************************************************/
336void AdcTicker10ms (void)
337 {
338 return;
339 }
340
341/******************************************************************************
342void AdcTicker50ms (void)
343 Periodically 50ms tasks
344******************************************************************************/
345void AdcTicker50ms (void)
346 {
347 return;
348 }
349
350/******************************************************************************
351void AdcTicker100ms (void)
352 Periodically 100ms tasks
353******************************************************************************/
354void AdcTicker100ms (void)
355 {
356 return;
357 }
358
359/******************************************************************************
360void AdcTicker200ms (void)
361 Periodically 200ms tasks
362******************************************************************************/
363void AdcTicker200ms (void)
364 {
365 if (bAdcContinousTrace) {
366 AdcTrace(4);
367 bAdcContinousTrace = TRUE;
368 }
369 return;
370 }
371
372/******************************************************************************
373void AdcTicker500ms (void)
374 Periodically 500ms tasks
375******************************************************************************/
376void AdcTicker500ms (void)
377 {
378 return;
379 }
380
381/******************************************************************************
382void AdcTicker1s (void)
383 Periodically 1s tasks
384******************************************************************************/
385void AdcTicker1s (void)
386 {
387
388 //TRACE("ADC: PA3%5umV", ADC_MV(3));
389 return;
390 }
391
392/******************************************************************************
393int AdcGet (int iChannel)
394
395Returns last conversion value for specified channel.
396 Range 0..4095, full scale..1.25V (reference set to internal 1.25V)
397******************************************************************************/
398int AdcGet (int iChannel)
399 {
400 return adcBuffer[iChannel];
401 }
402
403/******************************************************************************
404int AdcGetMv (int iChannel)
405
406Returns voltage on selected channel in mV
407 Range 0..1250
408******************************************************************************/
409int AdcGetMv (int iChannel)
410 {
411 return ADC_MV(iChannel);
412 }
413
414
415
Note: See TracBrowser for help on using the repository browser.