1 /***************************************************************************//**
2 * @file
3 * @brief Low Energy Sensor (LESENSE) Peripheral API
4 * @author Energy Micro AS
5 * @version 3.0.0
6 *******************************************************************************
7 * @section License
8 * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
9 *******************************************************************************
10 *
11 * Permission is granted to anyone to use this software for any purpose,
12 * including commercial applications, and to alter it and redistribute it
13 * freely, subject to the following restrictions:
14 *
15 * 1. The origin of this software must not be misrepresented; you must not
16 * claim that you wrote the original software.
17 * 2. Altered source versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software.
19 * 3. This notice may not be removed or altered from any source distribution.
20 *
21 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
22 * obligation to support this Software. Energy Micro AS is providing the
23 * Software "AS IS", with no express or implied warranties of any kind,
24 * including, but not limited to, any implied warranties of merchantability
25 * or fitness for any particular purpose or warranties against infringement
26 * of any proprietary rights of a third party.
27 *
28 * Energy Micro AS will not be liable for any consequential, incidental, or
29 * special damages, or any other relief, or for any claim by any third party,
30 * arising from your use of this Software.
31 *
32 ******************************************************************************/
33 #include "em_lesense.h"
34 #if defined(LESENSE_COUNT) && (LESENSE_COUNT > 0)
35 #include "em_assert.h"
36 #include "em_bitband.h"
37 #include "em_cmu.h"
38
39 /***************************************************************************//**
40 * @addtogroup EM_Library
41 * @{
42 ******************************************************************************/
43
44 /***************************************************************************//**
45 * @addtogroup LESENSE
46 * @brief Low Energy Sensor (LESENSE) Peripheral API
47 * @{
48 ******************************************************************************/
49
50 /*******************************************************************************
51 ************************** LOCAL FUNCTIONS ********************************
52 ******************************************************************************/
53
54
55 /*******************************************************************************
56 ************************** GLOBAL FUNCTIONS *******************************
57 ******************************************************************************/
58
59 /***************************************************************************//**
60 * @brief
61 * Initialize the LESENSE module.
62 *
63 * @details
64 * This function configures the main parameters of the LESENSE interface.
65 * Please refer to the initialization parameter type definition
66 * (LESENSE_Init_TypeDef) for more details.
67 *
68 * @note
69 * LESENSE_Init() has been designed for initializing LESENSE once in an
70 * operation cycle. Be aware of the effects of reconfiguration if using this
71 * function from multiple sources in your code. This function has not been
72 * designed to be re-entrant.
73 * Requesting reset by setting @p reqReset to true is required in each reset
74 * or power-on cycle in order to configure the default values of the RAM
75 * mapped LESENSE registers.
76 * Notice that GPIO pins used by the LESENSE module must be properly
77 * configured by the user explicitly, in order for the LESENSE to work as
78 * intended.
79 * (When configuring pins, one should remember to consider the sequence of
80 * configuration, in order to avoid unintended pulses/glitches on output
81 * pins.)
82 *
83 * @param[in] init
84 * LESENSE initialization structure.
85 *
86 * @param[in] reqReset
87 * Request to call LESENSE_Reset() first in order to initialize all LESENSE
88 * registers with the default value.
89 ******************************************************************************/
LESENSE_Init(LESENSE_Init_TypeDef const * init,bool const reqReset)90 void LESENSE_Init(LESENSE_Init_TypeDef const *init, bool const reqReset)
91 {
92 /* Sanity check of initialization values */
93 EFM_ASSERT((uint32_t)init->timeCtrl.startDelay < 4U);
94 EFM_ASSERT((uint32_t)init->perCtrl.dacPresc < 32U);
95
96 /* Reset LESENSE registers if requested. */
97 if (reqReset)
98 {
99 LESENSE_Reset();
100 }
101
102 /* Set sensor start delay for each channel. */
103 LESENSE_StartDelaySet((uint32_t)init->timeCtrl.startDelay);
104
105 /* LESENSE core control configuration.
106 * Set PRS source, SCANCONF register usage strategy, interrupt and
107 * DMA trigger level condition, DMA wakeup condition, bias mode,
108 * enable/disable to sample both ACMPs simultaneously, enable/disable to store
109 * SCANRES in CNT_RES after each scan, enable/disable to always write to the
110 * result buffer, even if it is full, enable/disable LESENSE running in debug
111 * mode. */
112 LESENSE->CTRL = ((uint32_t)init->coreCtrl.prsSel <<
113 _LESENSE_CTRL_PRSSEL_SHIFT) |
114 (uint32_t)init->coreCtrl.scanConfSel |
115 (uint32_t)init->coreCtrl.bufTrigLevel |
116 (uint32_t)init->coreCtrl.wakeupOnDMA |
117 ((uint32_t)init->coreCtrl.invACMP0 <<
118 _LESENSE_CTRL_ACMP0INV_SHIFT) |
119 ((uint32_t)init->coreCtrl.invACMP1 <<
120 _LESENSE_CTRL_ACMP1INV_SHIFT) |
121 ((uint32_t)init->coreCtrl.dualSample <<
122 _LESENSE_CTRL_DUALSAMPLE_SHIFT) |
123 ((uint32_t)init->coreCtrl.storeScanRes <<
124 _LESENSE_CTRL_STRSCANRES_SHIFT) |
125 ((uint32_t)init->coreCtrl.bufOverWr <<
126 _LESENSE_CTRL_BUFOW_SHIFT) |
127 ((uint32_t)init->coreCtrl.debugRun <<
128 _LESENSE_CTRL_DEBUGRUN_SHIFT);
129
130 /* Set scan mode in the CTRL register using the provided function, don't
131 * start scanning immediately. */
132 LESENSE_ScanModeSet((LESENSE_ScanMode_TypeDef)init->coreCtrl.scanStart, false);
133
134 /* LESENSE peripheral control configuration.
135 * Set DAC0 and DAC1 data source, conversion mode, output mode. Set DAC
136 * prescaler and reference. Set ACMP0 and ACMP1 control mode. Set ACMP and DAC
137 * duty cycle (warm up) mode. */
138 LESENSE->PERCTRL = ((uint32_t)init->perCtrl.dacCh0Data <<
139 _LESENSE_PERCTRL_DACCH0DATA_SHIFT) |
140 ((uint32_t)init->perCtrl.dacCh0ConvMode <<
141 _LESENSE_PERCTRL_DACCH0CONV_SHIFT) |
142 ((uint32_t)init->perCtrl.dacCh0OutMode <<
143 _LESENSE_PERCTRL_DACCH0OUT_SHIFT) |
144 ((uint32_t)init->perCtrl.dacCh1Data <<
145 _LESENSE_PERCTRL_DACCH1DATA_SHIFT) |
146 ((uint32_t)init->perCtrl.dacCh1ConvMode <<
147 _LESENSE_PERCTRL_DACCH1CONV_SHIFT) |
148 ((uint32_t)init->perCtrl.dacCh1OutMode <<
149 _LESENSE_PERCTRL_DACCH1OUT_SHIFT) |
150 ((uint32_t)init->perCtrl.dacPresc <<
151 _LESENSE_PERCTRL_DACPRESC_SHIFT) |
152 (uint32_t)init->perCtrl.dacRef |
153 ((uint32_t)init->perCtrl.acmp0Mode <<
154 _LESENSE_PERCTRL_ACMP0MODE_SHIFT) |
155 ((uint32_t)init->perCtrl.acmp1Mode <<
156 _LESENSE_PERCTRL_ACMP1MODE_SHIFT) |
157 (uint32_t)init->perCtrl.warmupMode;
158
159 /* LESENSE decoder general control configuration.
160 * Set decoder input source, select PRS input for decoder bits.
161 * Enable/disable the decoder to check the present state.
162 * Enable/disable decoder to channel interrupt mapping.
163 * Enable/disable decoder hysteresis on PRS output.
164 * Enable/disable decoder hysteresis on count events.
165 * Enable/disable decoder hysteresis on interrupt requests.
166 * Enable/disable count mode on LESPRS0 and LESPRS1. */
167 LESENSE->DECCTRL = (uint32_t)init->decCtrl.decInput |
168 ((uint32_t)init->decCtrl.prsChSel0 <<
169 _LESENSE_DECCTRL_PRSSEL0_SHIFT) |
170 ((uint32_t)init->decCtrl.prsChSel1 <<
171 _LESENSE_DECCTRL_PRSSEL1_SHIFT) |
172 ((uint32_t)init->decCtrl.prsChSel2 <<
173 _LESENSE_DECCTRL_PRSSEL2_SHIFT) |
174 ((uint32_t)init->decCtrl.prsChSel3 <<
175 _LESENSE_DECCTRL_PRSSEL3_SHIFT) |
176 ((uint32_t)init->decCtrl.chkState <<
177 _LESENSE_DECCTRL_ERRCHK_SHIFT) |
178 ((uint32_t)init->decCtrl.intMap <<
179 _LESENSE_DECCTRL_INTMAP_SHIFT) |
180 ((uint32_t)init->decCtrl.hystPRS0 <<
181 _LESENSE_DECCTRL_HYSTPRS0_SHIFT) |
182 ((uint32_t)init->decCtrl.hystPRS1 <<
183 _LESENSE_DECCTRL_HYSTPRS1_SHIFT) |
184 ((uint32_t)init->decCtrl.hystPRS2 <<
185 _LESENSE_DECCTRL_HYSTPRS2_SHIFT) |
186 ((uint32_t)init->decCtrl.hystIRQ <<
187 _LESENSE_DECCTRL_HYSTIRQ_SHIFT) |
188 ((uint32_t)init->decCtrl.prsCount <<
189 _LESENSE_DECCTRL_PRSCNT_SHIFT);
190
191 /* Set initial LESENSE decoder state. */
192 LESENSE_DecoderStateSet((uint32_t)init->decCtrl.initState);
193
194 /* LESENSE bias control configuration. */
195 LESENSE->BIASCTRL = (uint32_t)init->coreCtrl.biasMode;
196 }
197
198
199 /***************************************************************************//**
200 * @brief
201 * Set scan frequency for periodic scanning.
202 *
203 * @details
204 * This function only applies to LESENSE if period counter is being used as
205 * a trigger for scan start.
206 * The calculation is based on the following formula:
207 * Fscan = LFACLKles / ((1+PCTOP)*2^PCPRESC)
208 *
209 * @note
210 * Note that the calculation does not necessarily result in the requested
211 * scan frequency due to integer division. Check the return value for the
212 * resulted scan frequency.
213 *
214 * @param[in] refFreq
215 * Select reference LFACLK clock frequency in Hz. If set to 0, the current
216 * clock frequency is being used as a reference.
217 *
218 * @param[in] scanFreq
219 * Set the desired scan frequency in Hz.
220 *
221 * @return
222 * Frequency in Hz calculated and set by this function. Users can use this to
223 * compare the requested and set values.
224 ******************************************************************************/
LESENSE_ScanFreqSet(uint32_t refFreq,uint32_t const scanFreq)225 uint32_t LESENSE_ScanFreqSet(uint32_t refFreq, uint32_t const scanFreq)
226 {
227 uint32_t tmp;
228 uint32_t pcPresc = 0UL; /* Period counter prescaler. */
229 uint32_t clkDiv = 1UL; /* Clock divisor value (2^pcPresc). */
230 uint32_t pcTop = 63UL; /* Period counter top value (max. 63). */
231 uint32_t calcScanFreq; /* Variable for testing the calculation algorithm. */
232
233
234 /* If refFreq is set to 0, the currently configured reference clock is
235 * assumed. */
236 if (!refFreq)
237 {
238 refFreq = CMU_ClockFreqGet(cmuClock_LESENSE);
239 }
240
241 /* Max. value of pcPresc is 128, thus using reference frequency less than
242 * 33554431Hz (33.554431MHz), the frequency calculation in the while loop
243 * below will not overflow. */
244 EFM_ASSERT(refFreq < ((uint32_t)UINT32_MAX / 128UL));
245
246 /* Sanity check of scan frequency value. */
247 EFM_ASSERT((scanFreq > 0U) && (scanFreq <= refFreq));
248
249 /* Calculate the minimum necessary prescaler value in order to provide the
250 * biggest possible resolution for setting scan frequency.
251 * Maximum number of calculation cycles is 7 (value of lesenseClkDiv_128). */
252 while ((refFreq / ((uint32_t)scanFreq * clkDiv) > (pcTop + 1UL)) &&
253 (pcPresc < lesenseClkDiv_128))
254 {
255 ++pcPresc;
256 clkDiv = (uint32_t)1UL << pcPresc;
257 }
258
259 /* Calculate pcTop value. */
260 pcTop = ((uint32_t)refFreq / ((uint32_t)scanFreq * clkDiv)) - 1UL;
261
262 /* Clear current PCPRESC and PCTOP settings. Be aware of the effect of
263 * non-atomic Read-Modify-Write on LESENSE->TIMCRTL. */
264 tmp = LESENSE->TIMCTRL & (~(_LESENSE_TIMCTRL_PCPRESC_MASK)&
265 ~(_LESENSE_TIMCTRL_PCTOP_MASK));
266
267 /* Set new values in tmp while reserving other settings. */
268 tmp |= ((uint32_t)pcPresc << _LESENSE_TIMCTRL_PCPRESC_SHIFT) |
269 ((uint32_t)pcTop << _LESENSE_TIMCTRL_PCTOP_SHIFT);
270
271 /* Set values in LESENSE_TIMCTRL register. */
272 LESENSE->TIMCTRL = tmp;
273
274 /* For testing the calculation algorithm. */
275 calcScanFreq = ((uint32_t)refFreq / ((uint32_t)(1UL + pcTop) * clkDiv));
276
277 return calcScanFreq;
278 }
279
280
281 /***************************************************************************//**
282 * @brief
283 * Set scan mode of the LESENSE channels.
284 *
285 * @details
286 * This function configures how the scan start is being triggered. It can be
287 * used for re-configuring the scan mode while running the application but it
288 * is also used by LESENSE_Init() for initialization.
289 *
290 * @note
291 * Users can configure the scan mode by LESENSE_Init() function, but only with
292 * a significant overhead. This simple function serves the purpose of
293 * controlling this parameter after the channel has been configured.
294 * Please be aware the effects of the non-atomic Read-Modify-Write cycle!
295 *
296 * @param[in] scanMode
297 * Select where to map LESENSE alternate excitation channels.
298 * @li lesenseScanStartPeriodic - New scan is started each time the period
299 * counter overflows.
300 * @li lesenseScanStartOneShot - Single scan is performed when
301 * LESENSE_ScanStart() is called.
302 * @li lesenseScanStartPRS - New scan is triggered by pulse on PRS channel.
303 *
304 * @param[in] start
305 * If true, LESENSE_ScanStart() is immediately issued after configuration.
306 ******************************************************************************/
LESENSE_ScanModeSet(LESENSE_ScanMode_TypeDef const scanMode,bool const start)307 void LESENSE_ScanModeSet(LESENSE_ScanMode_TypeDef const scanMode,
308 bool const start)
309 {
310 uint32_t tmp; /* temporary storage of the CTRL register value */
311
312
313 /* Save the CTRL register value to tmp.
314 * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
315 tmp = LESENSE->CTRL & ~(_LESENSE_CTRL_SCANMODE_MASK);
316 /* Setting the requested scanMode to the CTRL register. Casting signed int
317 * (enum) to unsigned long (uint32_t). */
318 tmp |= (uint32_t)scanMode;
319
320 /* Write the new value to the CTRL register. */
321 LESENSE->CTRL = tmp;
322
323 /* Start sensor scanning if requested. */
324 if (start)
325 {
326 LESENSE_ScanStart();
327 }
328 }
329
330
331 /***************************************************************************//**
332 * @brief
333 * Set start delay of sensor interaction on each channel.
334 *
335 * @details
336 * This function sets start delay of sensor interaction on each channel.
337 * It can be used for adjusting the start delay while running the application
338 * but it is also used by LESENSE_Init() for initialization.
339 *
340 * @note
341 * Users can configure the start delay by LESENSE_Init() function, but only
342 * with a significant overhead. This simple function serves the purpose of
343 * controlling this parameter after the channel has been configured.
344 * Please be aware the effects of the non-atomic Read-Modify-Write cycle!
345 *
346 * @param[in] startDelay
347 * Number of LFACLK cycles to delay. Valid range: 0-3 (2 bit).
348 ******************************************************************************/
LESENSE_StartDelaySet(uint8_t const startDelay)349 void LESENSE_StartDelaySet(uint8_t const startDelay)
350 {
351 uint32_t tmp; /* temporary storage of the TIMCTRL register value */
352
353
354 /* Sanity check of startDelay. */
355 EFM_ASSERT(startDelay < 4U);
356
357 /* Save the TIMCTRL register value to tmp.
358 * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
359 tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_STARTDLY_MASK);
360 /* Setting the requested startDelay to the TIMCTRL register. */
361 tmp |= (uint32_t)startDelay << _LESENSE_TIMCTRL_STARTDLY_SHIFT;
362
363 /* Write the new value to the TIMCTRL register. */
364 LESENSE->TIMCTRL = tmp;
365 }
366
367
368 /***************************************************************************//**
369 * @brief
370 * Set clock division for LESENSE timers.
371 *
372 * @details
373 * Use this function to configure the clock division for the LESENSE timers
374 * used for excitation timing.
375 * The division setting is global, but the clock source can be selected for
376 * each channel using LESENSE_ChannelConfig() function, please refer to the
377 * documentation of it for more details.
378 *
379 * @note
380 * If AUXHFRCO is used for excitation timing, LFACLK can not exceed 500kHz.
381 * LFACLK can not exceed 50kHz if the ACMP threshold level (ACMPTHRES) is not
382 * equal for all channels.
383 *
384 * @param[in] clk
385 * Select clock to prescale.
386 * @li lesenseClkHF - set AUXHFRCO clock divisor for HF timer.
387 * @li lesenseClkLF - set LFACLKles clock divisor for LF timer.
388 *
389 * @param[in] clkDiv
390 * Clock divisor value. Valid range depends on the @p clk value.
391 ******************************************************************************/
LESENSE_ClkDivSet(LESENSE_ChClk_TypeDef const clk,LESENSE_ClkPresc_TypeDef const clkDiv)392 void LESENSE_ClkDivSet(LESENSE_ChClk_TypeDef const clk,
393 LESENSE_ClkPresc_TypeDef const clkDiv)
394 {
395 uint32_t tmp;
396
397
398 /* Select clock to prescale */
399 switch (clk)
400 {
401 case lesenseClkHF:
402 {
403 /* Sanity check of clock divisor for HF clock. */
404 EFM_ASSERT((uint32_t)clkDiv <= lesenseClkDiv_8);
405
406 /* Clear current AUXPRESC settings. */
407 tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_AUXPRESC_MASK);
408
409 /* Set new values in tmp while reserving other settings. */
410 tmp |= ((uint32_t)clkDiv << _LESENSE_TIMCTRL_AUXPRESC_SHIFT);
411
412 /* Set values in LESENSE_TIMCTRL register. */
413 LESENSE->TIMCTRL = tmp;
414 }
415 break;
416
417 case lesenseClkLF:
418 {
419 /* Clear current LFPRESC settings. */
420 tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_LFPRESC_MASK);
421
422 /* Set new values in tmp while reserving other settings. */
423 tmp |= ((uint32_t)clkDiv << _LESENSE_TIMCTRL_LFPRESC_SHIFT);
424
425 /* Set values in LESENSE_TIMCTRL register. */
426 LESENSE->TIMCTRL = tmp;
427 }
428 break;
429
430 default:
431 {
432 EFM_ASSERT(0);
433 }
434 break;
435 }
436 }
437
438
439 /***************************************************************************//**
440 * @brief
441 * Configure all (16) LESENSE sensor channels.
442 *
443 * @details
444 * This function configures all the sensor channels of LESENSE interface.
445 * Please refer to the configuration parameter type definition
446 * (LESENSE_ChAll_TypeDef) for more details.
447 *
448 * @note
449 * Channels can be configured individually using LESENSE_ChannelConfig()
450 * function.
451 * Notice that pins used by the LESENSE module must be properly configured
452 * by the user explicitly, in order for the LESENSE to work as intended.
453 * (When configuring pins, one should remember to consider the sequence of
454 * configuration, in order to avoid unintended pulses/glitches on output
455 * pins.)
456 *
457 * @param[in] confChAll
458 * Configuration structure for all (16) LESENSE sensor channels.
459 ******************************************************************************/
LESENSE_ChannelAllConfig(LESENSE_ChAll_TypeDef const * confChAll)460 void LESENSE_ChannelAllConfig(LESENSE_ChAll_TypeDef const *confChAll)
461 {
462 uint32_t i;
463
464
465 /* Iterate through all the 16 channels */
466 for (i = 0U; i < 16U; ++i)
467 {
468 /* Configure scan channels. */
469 LESENSE_ChannelConfig(&confChAll->Ch[i], i);
470 }
471 }
472
473
474 /***************************************************************************//**
475 * @brief
476 * Configure a single LESENSE sensor channel.
477 *
478 * @details
479 * This function configures a single sensor channel of the LESENSE interface.
480 * Please refer to the configuration parameter type definition
481 * (LESENSE_ChDesc_TypeDef) for more details.
482 *
483 * @note
484 * This function has been designed to minimize the effects of sensor channel
485 * reconfiguration while LESENSE is in operation, however one shall be aware
486 * of these effects and the right timing of calling this function.
487 * Parameter @p useAltEx must be true in the channel configuration in order to
488 * use alternate excitation pins.
489 *
490 * @param[in] confCh
491 * Configuration structure for a single LESENSE sensor channel.
492 *
493 * @param[in] chIdx
494 * Channel index to configure (0-15).
495 ******************************************************************************/
LESENSE_ChannelConfig(LESENSE_ChDesc_TypeDef const * confCh,uint32_t const chIdx)496 void LESENSE_ChannelConfig(LESENSE_ChDesc_TypeDef const *confCh,
497 uint32_t const chIdx)
498 {
499 uint32_t tmp; /* Service variable. */
500
501
502 /* Sanity check of configuration parameters */
503 EFM_ASSERT(chIdx < 16U);
504 EFM_ASSERT(confCh->exTime < 64U);
505 EFM_ASSERT(confCh->sampleDelay < 128U);
506 EFM_ASSERT(confCh->measDelay < 128U);
507 /* Not a complete assert, as the max. value of acmpThres depends on other
508 * configuration parameters, check the parameter description of acmpThres for
509 * for more details! */
510 EFM_ASSERT(confCh->acmpThres < 4096U);
511 EFM_ASSERT(!(confCh->chPinExMode == lesenseChPinExDACOut &&
512 (chIdx != 2U) && (chIdx != 3U) && (chIdx != 4U) && (chIdx != 5U)));
513 EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh1 &&
514 ((chIdx != 12U) && (chIdx != 13U) && (chIdx != 14U) && (chIdx != 15U))));
515 EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh0 &&
516 ((chIdx != 0U) && (chIdx != 1U) && (chIdx != 2U) && (chIdx != 3U))));
517
518
519 /* Configure chIdx setup in LESENSE idle phase.
520 * Read-modify-write in order to support reconfiguration during LESENSE
521 * operation. */
522 tmp = (LESENSE->IDLECONF & ~((uint32_t)0x3UL << (chIdx * 2UL)));
523 tmp |= ((uint32_t)confCh->chPinIdleMode << (chIdx * 2UL));
524 LESENSE->IDLECONF = tmp;
525
526 /* Channel specific timing configuration on scan channel chIdx.
527 * Set excitation time, sampling delay, measurement delay. */
528 LESENSE_ChannelTimingSet(chIdx,
529 (uint32_t)confCh->exTime,
530 (uint32_t)confCh->sampleDelay,
531 (uint32_t)confCh->measDelay);
532
533 /* Channel specific configuration of clocks, sample mode, excitation pin mode
534 * alternate excitation usage and interrupt mode on scan channel chIdx in
535 * LESENSE_CHchIdx_INTERACT. */
536 LESENSE->CH[chIdx].INTERACT = ((uint32_t)confCh->exClk <<
537 _LESENSE_CH_INTERACT_EXCLK_SHIFT) |
538 ((uint32_t)confCh->sampleClk <<
539 _LESENSE_CH_INTERACT_SAMPLECLK_SHIFT) |
540 (uint32_t)confCh->sampleMode |
541 (uint32_t)confCh->intMode |
542 (uint32_t)confCh->chPinExMode |
543 ((uint32_t)confCh->useAltEx <<
544 _LESENSE_CH_INTERACT_ALTEX_SHIFT);
545
546 /* Configure channel specific counter comparison mode, optional result
547 * forwarding to decoder, optional counter value storing and optional result
548 * inverting on scan channel chIdx in LESENSE_CHchIdx_EVAL. */
549 LESENSE->CH[chIdx].EVAL = (uint32_t)confCh->compMode |
550 ((uint32_t)confCh->shiftRes <<
551 _LESENSE_CH_EVAL_DECODE_SHIFT) |
552 ((uint32_t)confCh->storeCntRes <<
553 _LESENSE_CH_EVAL_STRSAMPLE_SHIFT) |
554 ((uint32_t)confCh->invRes <<
555 _LESENSE_CH_EVAL_SCANRESINV_SHIFT);
556
557 /* Configure analog comparator (ACMP) threshold and decision threshold for
558 * counter separately with the function provided for that. */
559 LESENSE_ChannelThresSet(chIdx,
560 (uint32_t)confCh->acmpThres,
561 (uint32_t)confCh->cntThres);
562
563 /* Enable/disable interrupts on channel.
564 * Note: BITBAND_Peripheral() function is used for setting/clearing single
565 * bit peripheral register bitfields. Read the function description in
566 * efm32_bitband.h for more details. */
567 BITBAND_Peripheral(&(LESENSE->IEN),
568 (uint32_t)chIdx,
569 (uint32_t)confCh->enaInt);
570
571 /* Enable/disable CHchIdx pin. */
572 BITBAND_Peripheral(&(LESENSE->ROUTE),
573 (uint32_t)chIdx,
574 (uint32_t)confCh->enaPin);
575
576 /* Enable/disable scan channel chIdx. */
577 BITBAND_Peripheral(&(LESENSE->CHEN),
578 (uint32_t)chIdx,
579 (uint32_t)confCh->enaScanCh);
580 }
581
582
583 /***************************************************************************//**
584 * @brief
585 * Configure the LESENSE alternate excitation pins.
586 *
587 * @details
588 * This function configures the alternate excitation channels of the LESENSE
589 * interface. Please refer to the configuration parameter type definition
590 * (LESENSE_ConfAltEx_TypeDef) for more details.
591 *
592 * @note
593 * Parameter @p useAltEx must be true in the channel configuration structrure
594 * (LESENSE_ChDesc_TypeDef) in order to use alternate excitation pins on the
595 * channel.
596 *
597 * @param[in] confAltEx
598 * Configuration structure for LESENSE alternate excitation pins.
599 ******************************************************************************/
LESENSE_AltExConfig(LESENSE_ConfAltEx_TypeDef const * confAltEx)600 void LESENSE_AltExConfig(LESENSE_ConfAltEx_TypeDef const *confAltEx)
601 {
602 uint32_t i;
603 uint32_t tmp;
604
605
606 /* Configure alternate excitation mapping.
607 * Atomic read-modify-write using BITBAND_Peripheral function in order to
608 * support reconfiguration during LESENSE operation. */
609 BITBAND_Peripheral(&(LESENSE->CTRL),
610 _LESENSE_CTRL_ALTEXMAP_SHIFT,
611 (uint32_t)confAltEx->altExMap);
612
613 /* Iterate through all the 8 alternate excitation channels */
614 for (i = 0U; i < 8U; ++i)
615 {
616 /* Enable/disable alternate excitation pin i.
617 * Atomic read-modify-write using BITBAND_Peripheral function in order to
618 * support reconfiguration during LESENSE operation. */
619 BITBAND_Peripheral(&(LESENSE->ROUTE),
620 (16UL + i),
621 (uint32_t)confAltEx->AltEx[i].enablePin);
622
623 /* Setup the idle phase state of alternate excitation pin i.
624 * Read-modify-write in order to support reconfiguration during LESENSE
625 * operation. */
626 tmp = (LESENSE->ALTEXCONF & ~((uint32_t)0x3UL << (i * 2UL)));
627 tmp |= ((uint32_t)confAltEx->AltEx[i].idleConf << (i * 2UL));
628 LESENSE->ALTEXCONF = tmp;
629
630 /* Enable/disable always excite on channel i */
631 BITBAND_Peripheral(&(LESENSE->ALTEXCONF),
632 (16UL + i),
633 (uint32_t)confAltEx->AltEx[i].alwaysEx);
634 }
635 }
636
637
638 /***************************************************************************//**
639 * @brief
640 * Enable/disable LESENSE scan channel and the pin assigned to it.
641 *
642 * @details
643 * Use this function to enable/disable a selected LESENSE scan channel and the
644 * pin assigned to.
645 *
646 * @note
647 * Users can enable/disable scan channels and the channel pin by
648 * LESENSE_ChannelConfig() function, but only with a significant overhead.
649 * This simple function serves the purpose of controlling these parameters
650 * after the channel has been configured.
651 *
652 * @param[in] chIdx
653 * Identifier of the scan channel. Valid range: 0-15.
654 *
655 * @param[in] enaScanCh
656 * Enable/disable the selected scan channel by setting this parameter to
657 * true/false respectively.
658 *
659 * @param[in] enaPin
660 * Enable/disable the pin assigned to the channel selected by @p chIdx.
661 ******************************************************************************/
LESENSE_ChannelEnable(uint8_t const chIdx,bool const enaScanCh,bool const enaPin)662 void LESENSE_ChannelEnable(uint8_t const chIdx,
663 bool const enaScanCh,
664 bool const enaPin)
665 {
666 /* Enable/disable the assigned pin of scan channel chIdx.
667 * Note: BITBAND_Peripheral() function is used for setting/clearing single
668 * bit peripheral register bitfields. Read the function description in
669 * efm32_bitband.h for more details. */
670 BITBAND_Peripheral(&(LESENSE->ROUTE),
671 (uint32_t)chIdx,
672 (uint32_t)enaPin);
673
674 /* Enable/disable scan channel chIdx. */
675 BITBAND_Peripheral(&(LESENSE->CHEN),
676 (uint32_t)chIdx,
677 (uint32_t)enaScanCh);
678 }
679
680
681 /***************************************************************************//**
682 * @brief
683 * Enable/disable LESENSE scan channel and the pin assigned to it.
684 *
685 * @details
686 * Use this function to enable/disable LESENSE scan channels and the pins
687 * assigned to them using a mask.
688 *
689 * @note
690 * Users can enable/disable scan channels and channel pins by using
691 * LESENSE_ChannelAllConfig() function, but only with a significant overhead.
692 * This simple function serves the purpose of controlling these parameters
693 * after the channel has been configured.
694 *
695 * @param[in] chMask
696 * Set the corresponding bit to 1 to enable, 0 to disable the selected scan
697 * channel.
698 *
699 * @param[in] pinMask
700 * Set the corresponding bit to 1 to enable, 0 to disable the pin on selected
701 * channel.
702 ******************************************************************************/
LESENSE_ChannelEnableMask(uint16_t chMask,uint16_t pinMask)703 void LESENSE_ChannelEnableMask(uint16_t chMask, uint16_t pinMask)
704 {
705 /* Enable/disable all channels at once according to the mask. */
706 LESENSE->CHEN = chMask;
707 /* Enable/disable all channel pins at once according to the mask. */
708 LESENSE->ROUTE = pinMask;
709 }
710
711
712 /***************************************************************************//**
713 * @brief
714 * Set LESENSE channel timing parameters.
715 *
716 * @details
717 * Use this function to set timing parameters on a selected LESENSE channel.
718 *
719 * @note
720 * Users can configure the channel timing parameters by
721 * LESENSE_ChannelConfig() function, but only with a significant overhead.
722 * This simple function serves the purpose of controlling these parameters
723 * after the channel has been configured.
724 *
725 * @param[in] chIdx
726 * Identifier of the scan channel. Valid range: 0-15.
727 *
728 * @param[in] exTime
729 * Excitation time on chIdx. Excitation will last exTime+1 excitation clock
730 * cycles. Valid range: 0-63 (6 bits).
731 *
732 * @param[in] sampleDelay
733 * Sample delay on chIdx. Sampling will occur after sampleDelay+1 sample clock
734 * cycles. Valid range: 0-127 (7 bits).
735 *
736 * @param[in] measDelay
737 * Measure delay on chIdx. Sensor measuring is delayed for measDelay+1
738 * excitation clock cycles. Valid range: 0-127 (7 bits).
739 ******************************************************************************/
LESENSE_ChannelTimingSet(uint8_t const chIdx,uint8_t const exTime,uint8_t const sampleDelay,uint8_t const measDelay)740 void LESENSE_ChannelTimingSet(uint8_t const chIdx,
741 uint8_t const exTime,
742 uint8_t const sampleDelay,
743 uint8_t const measDelay)
744 {
745 /* Sanity check of parameters. */
746 EFM_ASSERT(exTime < 64U);
747 EFM_ASSERT(sampleDelay < 128U);
748 EFM_ASSERT(measDelay < 128U);
749
750 /* Channel specific timing configuration on scan channel chIdx.
751 * Setting excitation time, sampling delay, measurement delay. */
752 LESENSE->CH[chIdx].TIMING = ((uint32_t)exTime <<
753 _LESENSE_CH_TIMING_EXTIME_SHIFT) |
754 ((uint32_t)sampleDelay <<
755 _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT) |
756 ((uint32_t)measDelay <<
757 _LESENSE_CH_TIMING_MEASUREDLY_SHIFT);
758 }
759
760
761 /***************************************************************************//**
762 * @brief
763 * Set LESENSE channel threshold parameters.
764 *
765 * @details
766 * Use this function to set threshold parameters on a selected LESENSE
767 * channel.
768 *
769 * @note
770 * Users can configure the channel threshold parameters by
771 * LESENSE_ChannelConfig() function, but only with a significant overhead.
772 * This simple function serves the purpose of controlling these parameters
773 * after the channel has been configured.
774 *
775 * @param[in] chIdx
776 * Identifier of the scan channel. Valid range: 0-15.
777 *
778 * @param[in] acmpThres
779 * ACMP threshold.
780 * @li If perCtrl.dacCh0Data or perCtrl.dacCh1Data is set to
781 * #lesenseDACIfData, acmpThres defines the 12-bit DAC data in the
782 * corresponding data register of the DAC interface (DACn_CH0DATA and
783 * DACn_CH1DATA). In this case, the valid range is: 0-4095 (12 bits).
784 *
785 * @li If perCtrl.dacCh0Data or perCtrl.dacCh1Data is set to
786 * #lesenseACMPThres, acmpThres defines the 6-bit Vdd scaling factor of ACMP
787 * negative input (VDDLEVEL in ACMP_INPUTSEL register). In this case, the
788 * valid range is: 0-63 (6 bits).
789 *
790 * @param[in] cntThres
791 * Decision threshold for counter comparison.
792 * Valid range: 0-65535 (16 bits).
793 ******************************************************************************/
LESENSE_ChannelThresSet(uint8_t const chIdx,uint16_t const acmpThres,uint16_t const cntThres)794 void LESENSE_ChannelThresSet(uint8_t const chIdx,
795 uint16_t const acmpThres,
796 uint16_t const cntThres)
797 {
798 uint32_t tmp; /* temporary storage */
799
800
801 /* Sanity check for acmpThres only, cntThres is 16bit value. */
802 EFM_ASSERT(acmpThres < 4096U);
803 /* Sanity check for LESENSE channel id. */
804 EFM_ASSERT(chIdx < 16);
805
806 /* Save the INTERACT register value of channel chIdx to tmp.
807 * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
808 tmp = LESENSE->CH[chIdx].INTERACT & ~(_LESENSE_CH_INTERACT_ACMPTHRES_MASK);
809 /* Set the ACMP threshold value to the INTERACT register of channel chIdx. */
810 tmp |= (uint32_t)acmpThres << _LESENSE_CH_INTERACT_ACMPTHRES_SHIFT;
811 /* Write the new value to the INTERACT register. */
812 LESENSE->CH[chIdx].INTERACT = tmp;
813
814 /* Save the EVAL register value of channel chIdx to tmp.
815 * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
816 tmp = LESENSE->CH[chIdx].EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK);
817 /* Set the counter threshold value to the INTERACT register of channel chIdx. */
818 tmp |= (uint32_t)cntThres << _LESENSE_CH_EVAL_COMPTHRES_SHIFT;
819 /* Write the new value to the EVAL register. */
820 LESENSE->CH[chIdx].EVAL = tmp;
821 }
822
823
824 /***************************************************************************//**
825 * @brief
826 * Configure all LESENSE decoder states.
827 *
828 * @details
829 * This function configures all the decoder states of the LESENSE interface.
830 * Please refer to the configuration parameter type definition
831 * (LESENSE_DecStAll_TypeDef) for more details.
832 *
833 * @note
834 * Decoder states can be configured individually using
835 * LESENSE_DecoderStateConfig() function.
836 *
837 * @param[in] confDecStAll
838 * Configuration structure for all (16) LESENSE decoder states.
839 ******************************************************************************/
LESENSE_DecoderStateAllConfig(LESENSE_DecStAll_TypeDef const * confDecStAll)840 void LESENSE_DecoderStateAllConfig(LESENSE_DecStAll_TypeDef const *confDecStAll)
841 {
842 uint32_t i;
843
844
845 /* Iterate through all the 16 decoder states. */
846 for (i = 0U; i < 16U; ++i)
847 {
848 /* Configure decoder state i. */
849 LESENSE_DecoderStateConfig(&confDecStAll->St[i], i);
850 }
851 }
852
853
854 /***************************************************************************//**
855 * @brief
856 * Configure a single LESENSE decoder state.
857 *
858 * @details
859 * This function configures a single decoder state of the LESENSE interface.
860 * Please refer to the configuration parameter type definition
861 * (LESENSE_DecStDesc_TypeDef) for more details.
862 *
863 * @param[in] confDecSt
864 * Configuration structure for a single LESENSE decoder state.
865 *
866 * @param[in] decSt
867 * Decoder state index to configure (0-15).
868 ******************************************************************************/
LESENSE_DecoderStateConfig(LESENSE_DecStDesc_TypeDef const * confDecSt,uint32_t const decSt)869 void LESENSE_DecoderStateConfig(LESENSE_DecStDesc_TypeDef const *confDecSt,
870 uint32_t const decSt)
871 {
872 /* Sanity check of configuration parameters */
873 EFM_ASSERT(decSt < 16U);
874 EFM_ASSERT((uint32_t)confDecSt->confA.compMask < 16U);
875 EFM_ASSERT((uint32_t)confDecSt->confA.compVal < 16U);
876 EFM_ASSERT((uint32_t)confDecSt->confA.nextState < 16U);
877 EFM_ASSERT((uint32_t)confDecSt->confB.compMask < 16U);
878 EFM_ASSERT((uint32_t)confDecSt->confB.compVal < 16U);
879 EFM_ASSERT((uint32_t)confDecSt->confB.nextState < 16U);
880
881 /* Configure state descriptor A (LESENSE_STi_TCONFA) for decoder state i.
882 * Setting sensor compare value, sensor mask, next state index,
883 * transition action, interrupt flag option and state descriptor chaining
884 * configurations. */
885 LESENSE->ST[decSt].TCONFA = (uint32_t)confDecSt->confA.prsAct |
886 ((uint32_t)confDecSt->confA.compMask <<
887 _LESENSE_ST_TCONFA_MASK_SHIFT) |
888 ((uint32_t)confDecSt->confA.compVal <<
889 _LESENSE_ST_TCONFA_COMP_SHIFT) |
890 ((uint32_t)confDecSt->confA.nextState <<
891 _LESENSE_ST_TCONFA_NEXTSTATE_SHIFT) |
892 ((uint32_t)confDecSt->confA.setInt <<
893 _LESENSE_ST_TCONFA_SETIF_SHIFT) |
894 ((uint32_t)confDecSt->chainDesc <<
895 _LESENSE_ST_TCONFA_CHAIN_SHIFT);
896
897 /* Configure state descriptor Bi (LESENSE_STi_TCONFB).
898 * Setting sensor compare value, sensor mask, next state index, transition
899 * action and interrupt flag option configurations. */
900 LESENSE->ST[decSt].TCONFB = (uint32_t)confDecSt->confB.prsAct |
901 ((uint32_t)confDecSt->confB.compMask <<
902 _LESENSE_ST_TCONFB_MASK_SHIFT) |
903 ((uint32_t)confDecSt->confB.compVal <<
904 _LESENSE_ST_TCONFB_COMP_SHIFT) |
905 ((uint32_t)confDecSt->confB.nextState <<
906 _LESENSE_ST_TCONFB_NEXTSTATE_SHIFT) |
907 ((uint32_t)confDecSt->confB.setInt <<
908 _LESENSE_ST_TCONFB_SETIF_SHIFT);
909 }
910
911
912 /***************************************************************************//**
913 * @brief
914 * Set LESENSE decoder state.
915 *
916 * @details
917 * This function can be used for setting the initial state of the LESENSE
918 * decoder.
919 *
920 * @note
921 * Make sure the LESENSE decoder state is initialized by this function before
922 * enabling the decoder!
923 *
924 * @param[in] decSt
925 * Decoder state to set as current state. Valid range: 0-15
926 ******************************************************************************/
LESENSE_DecoderStateSet(uint32_t decSt)927 void LESENSE_DecoderStateSet(uint32_t decSt)
928 {
929 EFM_ASSERT(decSt < 16U);
930
931 LESENSE->DECSTATE = decSt & _LESENSE_DECSTATE_DECSTATE_MASK;
932 }
933
934
935 /***************************************************************************//**
936 * @brief
937 * Get the current state of the LESENSE decoder.
938 *
939 * @return
940 * This function returns the value of LESENSE_DECSTATE register that
941 * represents the current state of the LESENSE decoder.
942 ******************************************************************************/
LESENSE_DecoderStateGet(void)943 uint32_t LESENSE_DecoderStateGet(void)
944 {
945 return LESENSE->DECSTATE & _LESENSE_DECSTATE_DECSTATE_MASK;
946 }
947
948
949 /***************************************************************************//**
950 * @brief
951 * Reset the LESENSE module.
952 *
953 * @details
954 * Use this function to reset the LESENSE registers.
955 *
956 * @note
957 * Resetting LESENSE registers is required in each reset or power-on cycle in
958 * order to configure the default values of the RAM mapped LESENSE registers.
959 * LESENSE_Reset() can be called on initialization by setting the @p reqReset
960 * parameter to true in LESENSE_Init().
961 ******************************************************************************/
LESENSE_Reset(void)962 void LESENSE_Reset(void)
963 {
964 uint32_t i;
965
966
967 /* Disable all LESENSE interrupts first */
968 LESENSE->IEN = _LESENSE_IEN_RESETVALUE;
969
970 /* Clear all pending LESENSE interrupts */
971 LESENSE->IFC = _LESENSE_IFC_MASK;
972
973 /* Stop the decoder */
974 LESENSE->DECCTRL |= LESENSE_DECCTRL_DISABLE;
975
976 /* Stop sensor scan and clear result buffer */
977 LESENSE->CMD = (LESENSE_CMD_STOP | LESENSE_CMD_CLEARBUF);
978
979 /* Reset LESENSE configuration registers */
980 LESENSE->CTRL = _LESENSE_CTRL_RESETVALUE;
981 LESENSE->PERCTRL = _LESENSE_PERCTRL_RESETVALUE;
982 LESENSE->DECCTRL = _LESENSE_DECCTRL_RESETVALUE;
983 LESENSE->BIASCTRL = _LESENSE_BIASCTRL_RESETVALUE;
984 LESENSE->CHEN = _LESENSE_CHEN_RESETVALUE;
985 LESENSE->IDLECONF = _LESENSE_IDLECONF_RESETVALUE;
986 LESENSE->ALTEXCONF = _LESENSE_ALTEXCONF_RESETVALUE;
987
988 /* Disable LESENSE to control GPIO pins */
989 LESENSE->ROUTE = _LESENSE_ROUTE_RESETVALUE;
990
991 /* Reset all channel configuration registers */
992 for (i = 0U; i < 16U; ++i)
993 {
994 LESENSE->CH[i].TIMING = _LESENSE_CH_TIMING_RESETVALUE;
995 LESENSE->CH[i].INTERACT = _LESENSE_CH_INTERACT_RESETVALUE;
996 LESENSE->CH[i].EVAL = _LESENSE_CH_EVAL_RESETVALUE;
997 }
998
999 /* Reset all decoder state configuration registers */
1000 for (i = 0U; i < 16U; ++i)
1001 {
1002 LESENSE->ST[i].TCONFA = _LESENSE_ST_TCONFA_RESETVALUE;
1003 LESENSE->ST[i].TCONFB = _LESENSE_ST_TCONFB_RESETVALUE;
1004 }
1005 }
1006
1007
1008 /** @} (end addtogroup LESENSE) */
1009 /** @} (end addtogroup EM_Library) */
1010
1011 #endif /* defined(LESENSE_COUNT) && (LESENSE_COUNT > 0) */
1012