EFM32 Happy Gecko Software Documentation  efm32hg-doc-5.1.2
em_lesense.c
Go to the documentation of this file.
1 /***************************************************************************/
33 #include "em_lesense.h"
34 
35 #if defined(LESENSE_COUNT) && (LESENSE_COUNT > 0)
36 #include "em_assert.h"
37 #include "em_bus.h"
38 #include "em_cmu.h"
39 
41 #if !defined(UINT32_MAX)
42 #define UINT32_MAX ((uint32_t)(0xFFFFFFFF))
43 #endif
44 
46 /***************************************************************************/
51 /***************************************************************************/
63 #if defined(_LESENSE_ROUTE_MASK)
64 #define GENERIC_LESENSE_ROUTE LESENSE->ROUTE
65 #else
66 #define GENERIC_LESENSE_ROUTE LESENSE->ROUTEPEN
67 #endif
68 
69 #if defined(_SILICON_LABS_32B_SERIES_0)
70 /* DACOUT mode only available on channel 0,1,2,3,12,13,14,15 */
71 #define DACOUT_SUPPORT 0xF00F
72 #else
73 /* DACOUT mode only available on channel 4,5,7,10,12,13 */
74 #define DACOUT_SUPPORT 0x34B0
75 #endif
76 
78 /*******************************************************************************
79  ************************** LOCAL FUNCTIONS ********************************
80  ******************************************************************************/
81 
82 
83 /*******************************************************************************
84  ************************** GLOBAL FUNCTIONS *******************************
85  ******************************************************************************/
86 
87 /***************************************************************************/
118 void LESENSE_Init(const LESENSE_Init_TypeDef * init, bool reqReset)
119 {
120  /* Sanity check of initialization values */
121  EFM_ASSERT((uint32_t)init->timeCtrl.startDelay < 4U);
122 #if defined(_LESENSE_PERCTRL_DACPRESC_MASK)
123  EFM_ASSERT((uint32_t)init->perCtrl.dacPresc < 32U);
124 #endif
125 
126  /* Reset LESENSE registers if requested. */
127  if (reqReset)
128  {
129  LESENSE_Reset();
130  }
131 
132  /* Set sensor start delay for each channel. */
133  LESENSE_StartDelaySet((uint32_t)init->timeCtrl.startDelay);
134 #if defined(_LESENSE_TIMCTRL_AUXSTARTUP_MASK)
135  /* Configure the AUXHRFCO startup delay. */
136  LESENSE->TIMCTRL = (LESENSE->TIMCTRL & (~_LESENSE_TIMCTRL_AUXSTARTUP_MASK))
137  | (init->timeCtrl.delayAuxStartup << _LESENSE_TIMCTRL_AUXSTARTUP_SHIFT);
138 #endif
139 
140  /* LESENSE core control configuration.
141  * Set PRS source, SCANCONF register usage strategy, interrupt and
142  * DMA trigger level condition, DMA wakeup condition, bias mode,
143  * enable/disable to sample both ACMPs simultaneously, enable/disable to store
144  * SCANRES in CNT_RES after each scan, enable/disable to always write to the
145  * result buffer, even if it is full, enable/disable LESENSE running in debug
146  * mode. */
147  LESENSE->CTRL =
148  ((uint32_t)init->coreCtrl.prsSel << _LESENSE_CTRL_PRSSEL_SHIFT)
149  | (uint32_t)init->coreCtrl.scanConfSel
150  | (uint32_t)init->coreCtrl.bufTrigLevel
151  | (uint32_t)init->coreCtrl.wakeupOnDMA
152 #if defined(_LESENSE_CTRL_ACMP0INV_MASK)
153  | ((uint32_t)init->coreCtrl.invACMP0 << _LESENSE_CTRL_ACMP0INV_SHIFT)
154  | ((uint32_t)init->coreCtrl.invACMP1 << _LESENSE_CTRL_ACMP1INV_SHIFT)
155 #endif
156  | ((uint32_t)init->coreCtrl.dualSample << _LESENSE_CTRL_DUALSAMPLE_SHIFT)
157  | ((uint32_t)init->coreCtrl.storeScanRes << _LESENSE_CTRL_STRSCANRES_SHIFT)
158  | ((uint32_t)init->coreCtrl.bufOverWr << _LESENSE_CTRL_BUFOW_SHIFT)
159  | ((uint32_t)init->coreCtrl.debugRun << _LESENSE_CTRL_DEBUGRUN_SHIFT);
160 
161  /* Set scan mode in the CTRL register using the provided function, don't
162  * start scanning immediately. */
163  LESENSE_ScanModeSet((LESENSE_ScanMode_TypeDef)init->coreCtrl.scanStart, false);
164 
165  /* LESENSE peripheral control configuration.
166  * Set DAC0 and DAC1 data source, conversion mode, output mode. Set DAC
167  * prescaler and reference. Set ACMP0 and ACMP1 control mode. Set ACMP and DAC
168  * duty cycle (warm up) mode. */
169  LESENSE->PERCTRL =
170  ((uint32_t)init->perCtrl.dacCh0Data << _LESENSE_PERCTRL_DACCH0DATA_SHIFT)
171  | ((uint32_t)init->perCtrl.dacCh1Data << _LESENSE_PERCTRL_DACCH1DATA_SHIFT)
172 #if defined(_LESENSE_PERCTRL_DACCH0CONV_MASK)
173  | ((uint32_t)init->perCtrl.dacCh0ConvMode << _LESENSE_PERCTRL_DACCH0CONV_SHIFT)
174  | ((uint32_t)init->perCtrl.dacCh0OutMode << _LESENSE_PERCTRL_DACCH0OUT_SHIFT)
175  | ((uint32_t)init->perCtrl.dacCh1ConvMode << _LESENSE_PERCTRL_DACCH1CONV_SHIFT)
176  | ((uint32_t)init->perCtrl.dacCh1OutMode << _LESENSE_PERCTRL_DACCH1OUT_SHIFT)
177  | ((uint32_t)init->perCtrl.dacPresc << _LESENSE_PERCTRL_DACPRESC_SHIFT)
178  | (uint32_t)init->perCtrl.dacRef
179 #endif
180  | ((uint32_t)init->perCtrl.acmp0Mode << _LESENSE_PERCTRL_ACMP0MODE_SHIFT)
181  | ((uint32_t)init->perCtrl.acmp1Mode << _LESENSE_PERCTRL_ACMP1MODE_SHIFT)
182 #if defined(_LESENSE_PERCTRL_ACMP0INV_MASK)
183  | ((uint32_t)init->coreCtrl.invACMP0 << _LESENSE_PERCTRL_ACMP0INV_SHIFT)
184  | ((uint32_t)init->coreCtrl.invACMP1 << _LESENSE_PERCTRL_ACMP1INV_SHIFT)
185 #endif
186 #if defined(_LESENSE_PERCTRL_DACCONVTRIG_MASK)
187  | ((uint32_t)init->perCtrl.dacScan << _LESENSE_PERCTRL_DACCONVTRIG_SHIFT)
188 #endif
189  | (uint32_t)init->perCtrl.warmupMode;
190 
191  /* LESENSE decoder general control configuration.
192  * Set decoder input source, select PRS input for decoder bits.
193  * Enable/disable the decoder to check the present state.
194  * Enable/disable decoder to channel interrupt mapping.
195  * Enable/disable decoder hysteresis on PRS output.
196  * Enable/disable decoder hysteresis on count events.
197  * Enable/disable decoder hysteresis on interrupt requests.
198  * Enable/disable count mode on LESPRS0 and LESPRS1. */
199  LESENSE->DECCTRL =
200  (uint32_t)init->decCtrl.decInput
201  | ((uint32_t)init->decCtrl.prsChSel0 << _LESENSE_DECCTRL_PRSSEL0_SHIFT)
202  | ((uint32_t)init->decCtrl.prsChSel1 << _LESENSE_DECCTRL_PRSSEL1_SHIFT)
203  | ((uint32_t)init->decCtrl.prsChSel2 << _LESENSE_DECCTRL_PRSSEL2_SHIFT)
204  | ((uint32_t)init->decCtrl.prsChSel3 << _LESENSE_DECCTRL_PRSSEL3_SHIFT)
205  | ((uint32_t)init->decCtrl.chkState << _LESENSE_DECCTRL_ERRCHK_SHIFT)
206  | ((uint32_t)init->decCtrl.intMap << _LESENSE_DECCTRL_INTMAP_SHIFT)
207  | ((uint32_t)init->decCtrl.hystPRS0 << _LESENSE_DECCTRL_HYSTPRS0_SHIFT)
208  | ((uint32_t)init->decCtrl.hystPRS1 << _LESENSE_DECCTRL_HYSTPRS1_SHIFT)
209  | ((uint32_t)init->decCtrl.hystPRS2 << _LESENSE_DECCTRL_HYSTPRS2_SHIFT)
210  | ((uint32_t)init->decCtrl.hystIRQ << _LESENSE_DECCTRL_HYSTIRQ_SHIFT)
211  | ((uint32_t)init->decCtrl.prsCount << _LESENSE_DECCTRL_PRSCNT_SHIFT);
212 
213  /* Set initial LESENSE decoder state. */
214  LESENSE_DecoderStateSet((uint32_t)init->decCtrl.initState);
215 
216  /* LESENSE bias control configuration. */
217  LESENSE->BIASCTRL = (uint32_t)init->coreCtrl.biasMode;
218 }
219 
220 
221 /***************************************************************************/
247 uint32_t LESENSE_ScanFreqSet(uint32_t refFreq, uint32_t scanFreq)
248 {
249  uint32_t tmp;
250  uint32_t pcPresc = 0UL; /* Period counter prescaler. */
251  uint32_t clkDiv = 1UL; /* Clock divisor value (2^pcPresc). */
252  uint32_t pcTop = 63UL; /* Period counter top value (max. 63). */
253  uint32_t calcScanFreq; /* Variable for testing the calculation algorithm. */
254 
255 
256  /* If refFreq is set to 0, the currently configured reference clock is
257  * assumed. */
258  if (!refFreq)
259  {
260  refFreq = CMU_ClockFreqGet(cmuClock_LESENSE);
261  }
262 
263  /* Max. value of pcPresc is 128, thus using reference frequency less than
264  * 33554431Hz (33.554431MHz), the frequency calculation in the while loop
265  * below will not overflow. */
266  EFM_ASSERT(refFreq < ((uint32_t)UINT32_MAX / 128UL));
267 
268  /* Sanity check of scan frequency value. */
269  EFM_ASSERT((scanFreq > 0U) && (scanFreq <= refFreq));
270 
271  /* Calculate the minimum necessary prescaler value in order to provide the
272  * biggest possible resolution for setting scan frequency.
273  * Maximum number of calculation cycles is 7 (value of lesenseClkDiv_128). */
274  while ((refFreq / ((uint32_t)scanFreq * clkDiv) > (pcTop + 1UL))
275  && (pcPresc < lesenseClkDiv_128))
276  {
277  ++pcPresc;
278  clkDiv = (uint32_t)1UL << pcPresc;
279  }
280 
281  /* Calculate pcTop value. */
282  pcTop = ((uint32_t)refFreq / ((uint32_t)scanFreq * clkDiv)) - 1UL;
283 
284  /* Clear current PCPRESC and PCTOP settings. Be aware of the effect of
285  * non-atomic Read-Modify-Write on LESENSE->TIMCRTL. */
286  tmp = LESENSE->TIMCTRL & (~_LESENSE_TIMCTRL_PCPRESC_MASK
287  & ~_LESENSE_TIMCTRL_PCTOP_MASK);
288 
289  /* Set new values in tmp while reserving other settings. */
290  tmp |= ((uint32_t)pcPresc << _LESENSE_TIMCTRL_PCPRESC_SHIFT)
291  | ((uint32_t)pcTop << _LESENSE_TIMCTRL_PCTOP_SHIFT);
292 
293  /* Set values in LESENSE_TIMCTRL register. */
294  LESENSE->TIMCTRL = tmp;
295 
296  /* For testing the calculation algorithm. */
297  calcScanFreq = ((uint32_t)refFreq / ((uint32_t)(1UL + pcTop) * clkDiv));
298 
299  return calcScanFreq;
300 }
301 
302 
303 /***************************************************************************/
329 void LESENSE_ScanModeSet(LESENSE_ScanMode_TypeDef scanMode,
330  bool start)
331 {
332  uint32_t tmp; /* temporary storage of the CTRL register value */
333 
334 
335  /* Save the CTRL register value to tmp.
336  * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
337  tmp = LESENSE->CTRL & ~(_LESENSE_CTRL_SCANMODE_MASK);
338  /* Setting the requested scanMode to the CTRL register. Casting signed int
339  * (enum) to unsigned long (uint32_t). */
340  tmp |= (uint32_t)scanMode;
341 
342  /* Write the new value to the CTRL register. */
343  LESENSE->CTRL = tmp;
344 
345  /* Start sensor scanning if requested. */
346  if (start)
347  {
348  LESENSE_ScanStart();
349  }
350 }
351 
352 
353 /***************************************************************************/
371 void LESENSE_StartDelaySet(uint8_t startDelay)
372 {
373  uint32_t tmp; /* temporary storage of the TIMCTRL register value */
374 
375 
376  /* Sanity check of startDelay. */
377  EFM_ASSERT(startDelay < 4U);
378 
379  /* Save the TIMCTRL register value to tmp.
380  * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
381  tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_STARTDLY_MASK);
382  /* Setting the requested startDelay to the TIMCTRL register. */
383  tmp |= (uint32_t)startDelay << _LESENSE_TIMCTRL_STARTDLY_SHIFT;
384 
385  /* Write the new value to the TIMCTRL register. */
386  LESENSE->TIMCTRL = tmp;
387 }
388 
389 
390 /***************************************************************************/
414 void LESENSE_ClkDivSet(LESENSE_ChClk_TypeDef clk,
415  LESENSE_ClkPresc_TypeDef clkDiv)
416 {
417  uint32_t tmp;
418 
419 
420  /* Select clock to prescale */
421  switch (clk)
422  {
423  case lesenseClkHF:
424  /* Sanity check of clock divisor for HF clock. */
425  EFM_ASSERT((uint32_t)clkDiv <= lesenseClkDiv_8);
426 
427  /* Clear current AUXPRESC settings. */
428  tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_AUXPRESC_MASK);
429 
430  /* Set new values in tmp while reserving other settings. */
431  tmp |= ((uint32_t)clkDiv << _LESENSE_TIMCTRL_AUXPRESC_SHIFT);
432 
433  /* Set values in LESENSE_TIMCTRL register. */
434  LESENSE->TIMCTRL = tmp;
435  break;
436 
437  case lesenseClkLF:
438  /* Clear current LFPRESC settings. */
439  tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_LFPRESC_MASK);
440 
441  /* Set new values in tmp while reserving other settings. */
442  tmp |= ((uint32_t)clkDiv << _LESENSE_TIMCTRL_LFPRESC_SHIFT);
443 
444  /* Set values in LESENSE_TIMCTRL register. */
445  LESENSE->TIMCTRL = tmp;
446  break;
447 
448  default:
449  EFM_ASSERT(0);
450  break;
451  }
452 }
453 
454 
455 /***************************************************************************/
476 void LESENSE_ChannelAllConfig(const LESENSE_ChAll_TypeDef * confChAll)
477 {
478  uint32_t i;
479 
480  /* Iterate through all the 16 channels */
481  for (i = 0U; i < LESENSE_NUM_CHANNELS; ++i)
482  {
483  /* Configure scan channels. */
484  LESENSE_ChannelConfig(&confChAll->Ch[i], i);
485  }
486 }
487 
488 
489 /***************************************************************************/
511 void LESENSE_ChannelConfig(const LESENSE_ChDesc_TypeDef * confCh,
512  uint32_t chIdx)
513 {
514  uint32_t tmp; /* Service variable. */
515 
516 
517  /* Sanity check of configuration parameters */
518  EFM_ASSERT(chIdx < LESENSE_NUM_CHANNELS);
519  EFM_ASSERT(confCh->exTime <= (_LESENSE_CH_TIMING_EXTIME_MASK >> _LESENSE_CH_TIMING_EXTIME_SHIFT));
520  EFM_ASSERT(confCh->measDelay <= (_LESENSE_CH_TIMING_MEASUREDLY_MASK >> _LESENSE_CH_TIMING_MEASUREDLY_SHIFT));
521 #if defined(_SILICON_LABS_32B_SERIES_0)
522  // Sample delay on other devices are 8 bits which fits perfectly in uint8_t
523  EFM_ASSERT(confCh->sampleDelay <= (_LESENSE_CH_TIMING_SAMPLEDLY_MASK >> _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT));
524 #endif
525 
526  /* Not a complete assert, as the max. value of acmpThres depends on other
527  * configuration parameters, check the parameter description of acmpThres for
528  * for more details! */
529  EFM_ASSERT(confCh->acmpThres < 4096U);
530  if (confCh->chPinExMode == lesenseChPinExDACOut)
531  {
532  EFM_ASSERT((0x1 << chIdx) & DACOUT_SUPPORT);
533  }
534 
535 #if defined(_LESENSE_IDLECONF_CH0_DACCH0)
536  EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh1
537  && ((chIdx != 12U)
538  && (chIdx != 13U)
539  && (chIdx != 14U)
540  && (chIdx != 15U))));
541  EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh0
542  && ((chIdx != 0U)
543  && (chIdx != 1U)
544  && (chIdx != 2U)
545  && (chIdx != 3U))));
546 #endif
547 
548  /* Configure chIdx setup in LESENSE idle phase.
549  * Read-modify-write in order to support reconfiguration during LESENSE
550  * operation. */
551  tmp = (LESENSE->IDLECONF & ~((uint32_t)0x3UL << (chIdx * 2UL)));
552  tmp |= ((uint32_t)confCh->chPinIdleMode << (chIdx * 2UL));
553  LESENSE->IDLECONF = tmp;
554 
555  /* Channel specific timing configuration on scan channel chIdx.
556  * Set excitation time, sampling delay, measurement delay. */
557  LESENSE_ChannelTimingSet(chIdx,
558  confCh->exTime,
559  confCh->sampleDelay,
560  confCh->measDelay);
561 
562  /* Channel specific configuration of clocks, sample mode, excitation pin mode
563  * alternate excitation usage and interrupt mode on scan channel chIdx in
564  * LESENSE_CHchIdx_INTERACT. */
565  LESENSE->CH[chIdx].INTERACT =
566  ((uint32_t)confCh->exClk << _LESENSE_CH_INTERACT_EXCLK_SHIFT)
567  | ((uint32_t)confCh->sampleClk << _LESENSE_CH_INTERACT_SAMPLECLK_SHIFT)
568  | (uint32_t)confCh->sampleMode
569  | (uint32_t)confCh->intMode
570  | (uint32_t)confCh->chPinExMode
571  | ((uint32_t)confCh->useAltEx << _LESENSE_CH_INTERACT_ALTEX_SHIFT);
572 
573  /* Configure channel specific counter comparison mode, optional result
574  * forwarding to decoder, optional counter value storing and optional result
575  * inverting on scan channel chIdx in LESENSE_CHchIdx_EVAL. */
576  LESENSE->CH[chIdx].EVAL =
577  (uint32_t)confCh->compMode
578  | ((uint32_t)confCh->shiftRes << _LESENSE_CH_EVAL_DECODE_SHIFT)
579  | ((uint32_t)confCh->storeCntRes << _LESENSE_CH_EVAL_STRSAMPLE_SHIFT)
580  | ((uint32_t)confCh->invRes << _LESENSE_CH_EVAL_SCANRESINV_SHIFT)
581 #if defined(_LESENSE_CH_EVAL_MODE_MASK)
582  | ((uint32_t)confCh->evalMode << _LESENSE_CH_EVAL_MODE_SHIFT)
583 #endif
584  ;
585 
586  /* Configure analog comparator (ACMP) threshold and decision threshold for
587  * counter separately with the function provided for that. */
588  LESENSE_ChannelThresSet(chIdx,
589  confCh->acmpThres,
590  confCh->cntThres);
591 
592  /* Enable/disable interrupts on channel */
593  BUS_RegBitWrite(&LESENSE->IEN, chIdx, confCh->enaInt);
594 
595  /* Enable/disable CHchIdx pin. */
596  BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE, chIdx, confCh->enaPin);
597 
598  /* Enable/disable scan channel chIdx. */
599  BUS_RegBitWrite(&LESENSE->CHEN, chIdx, confCh->enaScanCh);
600 }
601 
602 
603 /***************************************************************************/
620 void LESENSE_AltExConfig(const LESENSE_ConfAltEx_TypeDef * confAltEx)
621 {
622  uint32_t i;
623  uint32_t tmp;
624 
625 
626  /* Configure alternate excitation mapping.
627  * Atomic read-modify-write using BUS_RegBitWrite function in order to
628  * support reconfiguration during LESENSE operation. */
629  BUS_RegBitWrite(&LESENSE->CTRL,
630  _LESENSE_CTRL_ALTEXMAP_SHIFT,
631  confAltEx->altExMap);
632 
633  switch (confAltEx->altExMap)
634  {
635  case lesenseAltExMapALTEX:
636  /* Iterate through the 8 possible alternate excitation pin descriptors. */
637  for (i = 0U; i < 8U; ++i)
638  {
639  /* Enable/disable alternate excitation pin i.
640  * Atomic read-modify-write using BUS_RegBitWrite function in order to
641  * support reconfiguration during LESENSE operation. */
642  BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE,
643  (16UL + i),
644  confAltEx->AltEx[i].enablePin);
645 
646  /* Setup the idle phase state of alternate excitation pin i.
647  * Read-modify-write in order to support reconfiguration during LESENSE
648  * operation. */
649  tmp = (LESENSE->ALTEXCONF & ~((uint32_t)0x3UL << (i * 2UL)));
650  tmp |= ((uint32_t)confAltEx->AltEx[i].idleConf << (i * 2UL));
651  LESENSE->ALTEXCONF = tmp;
652 
653  /* Enable/disable always excite on channel i */
654  BUS_RegBitWrite(&LESENSE->ALTEXCONF,
655  (16UL + i),
656  confAltEx->AltEx[i].alwaysEx);
657  }
658  break;
659 
660 #if defined(_LESENSE_CTRL_ALTEXMAP_ACMP)
661  case lesenseAltExMapACMP:
662 #else
663  case lesenseAltExMapCH:
664 #endif
665  /* Iterate through all the 16 alternate excitation channels */
666  for (i = 0U; i < 16U; ++i)
667  {
668  /* Enable/disable alternate ACMP excitation channel pin i. */
669  /* Atomic read-modify-write using BUS_RegBitWrite function in order to
670  * support reconfiguration during LESENSE operation. */
671  BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE,
672  i,
673  confAltEx->AltEx[i].enablePin);
674  }
675  break;
676  default:
677  /* Illegal value. */
678  EFM_ASSERT(0);
679  break;
680  }
681 }
682 
683 
684 /***************************************************************************/
708 void LESENSE_ChannelEnable(uint8_t chIdx,
709  bool enaScanCh,
710  bool enaPin)
711 {
712  /* Enable/disable the assigned pin of scan channel chIdx.
713  * Note: BUS_RegBitWrite() function is used for setting/clearing single
714  * bit peripheral register bitfields. Read the function description in
715  * em_bus.h for more details. */
716  BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE, chIdx, enaPin);
717 
718  /* Enable/disable scan channel chIdx. */
719  BUS_RegBitWrite(&LESENSE->CHEN, chIdx, enaScanCh);
720 }
721 
722 
723 /***************************************************************************/
745 void LESENSE_ChannelEnableMask(uint16_t chMask, uint16_t pinMask)
746 {
747  /* Enable/disable all channels at once according to the mask. */
748  LESENSE->CHEN = chMask;
749  /* Enable/disable all channel pins at once according to the mask. */
750  GENERIC_LESENSE_ROUTE = pinMask;
751 }
752 
753 
754 /***************************************************************************/
782 void LESENSE_ChannelTimingSet(uint8_t chIdx,
783  uint8_t exTime,
784  uint8_t sampleDelay,
785  uint16_t measDelay)
786 {
787  /* Sanity check of parameters. */
788  EFM_ASSERT(exTime <= (_LESENSE_CH_TIMING_EXTIME_MASK >> _LESENSE_CH_TIMING_EXTIME_SHIFT));
789  EFM_ASSERT(measDelay <= (_LESENSE_CH_TIMING_MEASUREDLY_MASK >> _LESENSE_CH_TIMING_MEASUREDLY_SHIFT));
790 #if defined(_SILICON_LABS_32B_SERIES_0)
791  // Sample delay on other devices are 8 bits which fits perfectly in uint8_t
792  EFM_ASSERT(sampleDelay <= (_LESENSE_CH_TIMING_SAMPLEDLY_MASK >> _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT));
793 #endif
794 
795  /* Channel specific timing configuration on scan channel chIdx.
796  * Setting excitation time, sampling delay, measurement delay. */
797  LESENSE->CH[chIdx].TIMING =
798  ((uint32_t)exTime << _LESENSE_CH_TIMING_EXTIME_SHIFT)
799  | ((uint32_t)sampleDelay << _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT)
800  | ((uint32_t)measDelay << _LESENSE_CH_TIMING_MEASUREDLY_SHIFT);
801 }
802 
803 
804 /***************************************************************************/
837 void LESENSE_ChannelThresSet(uint8_t chIdx,
838  uint16_t acmpThres,
839  uint16_t cntThres)
840 {
841  uint32_t tmp; /* temporary storage */
842 
843 
844  /* Sanity check for acmpThres only, cntThres is 16bit value. */
845  EFM_ASSERT(acmpThres < 4096U);
846  /* Sanity check for LESENSE channel id. */
847  EFM_ASSERT(chIdx < LESENSE_NUM_CHANNELS);
848 
849  /* Save the INTERACT register value of channel chIdx to tmp.
850  * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
851  tmp = LESENSE->CH[chIdx].INTERACT & ~(0xFFF);
852  /* Set the ACMP threshold value to the INTERACT register of channel chIdx. */
853  tmp |= (uint32_t)acmpThres;
854  /* Write the new value to the INTERACT register. */
855  LESENSE->CH[chIdx].INTERACT = tmp;
856 
857  /* Save the EVAL register value of channel chIdx to tmp.
858  * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
859  tmp = LESENSE->CH[chIdx].EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK);
860  /* Set the counter threshold value to the INTERACT register of channel chIdx. */
861  tmp |= (uint32_t)cntThres << _LESENSE_CH_EVAL_COMPTHRES_SHIFT;
862  /* Write the new value to the EVAL register. */
863  LESENSE->CH[chIdx].EVAL = tmp;
864 }
865 
866 #if defined(_LESENSE_CH_EVAL_MODE_MASK)
867 /***************************************************************************/
892 void LESENSE_ChannelSlidingWindow(uint8_t chIdx,
893  uint32_t windowSize,
894  uint32_t initValue)
895 {
896  LESENSE_CH_TypeDef * ch = &LESENSE->CH[chIdx];
897 
898  LESENSE_WindowSizeSet(windowSize);
899  ch->EVAL = (ch->EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK | _LESENSE_CH_EVAL_MODE_MASK))
900  | (initValue << _LESENSE_CH_EVAL_COMPTHRES_SHIFT)
901  | LESENSE_CH_EVAL_MODE_SLIDINGWIN;
902 }
903 
904 /***************************************************************************/
929 void LESENSE_ChannelStepDetection(uint8_t chIdx,
930  uint32_t stepSize,
931  uint32_t initValue)
932 {
933  LESENSE_CH_TypeDef * ch = &LESENSE->CH[chIdx];
934 
935  LESENSE_StepSizeSet(stepSize);
936  ch->EVAL = (ch->EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK | _LESENSE_CH_EVAL_MODE_MASK))
937  | (initValue << _LESENSE_CH_EVAL_COMPTHRES_SHIFT)
938  | LESENSE_CH_EVAL_MODE_STEPDET;
939 }
940 
941 /***************************************************************************/
958 void LESENSE_WindowSizeSet(uint32_t windowSize)
959 {
960  LESENSE->EVALCTRL = (LESENSE->EVALCTRL & ~_LESENSE_EVALCTRL_WINSIZE_MASK)
961  | windowSize;
962 }
963 
964 /***************************************************************************/
977 void LESENSE_StepSizeSet(uint32_t stepSize)
978 {
979  LESENSE_WindowSizeSet(stepSize);
980 }
981 #endif
982 
983 /***************************************************************************/
999 void LESENSE_DecoderStateAllConfig(const LESENSE_DecStAll_TypeDef * confDecStAll)
1000 {
1001  uint32_t i;
1002 
1003  /* Iterate through all the 16 or 32 decoder states. */
1004  for (i = 0U; i < LESENSE_NUM_DECODER_STATES; ++i)
1005  {
1006  /* Configure decoder state i. */
1007  LESENSE_DecoderStateConfig(&confDecStAll->St[i], i);
1008  }
1009 }
1010 
1011 
1012 /***************************************************************************/
1027 void LESENSE_DecoderStateConfig(const LESENSE_DecStDesc_TypeDef * confDecSt,
1028  uint32_t decSt)
1029 {
1030  /* Sanity check of configuration parameters */
1031  EFM_ASSERT(decSt < LESENSE_NUM_DECODER_STATES);
1032  EFM_ASSERT((uint32_t)confDecSt->confA.compMask < 16U);
1033  EFM_ASSERT((uint32_t)confDecSt->confA.compVal < 16U);
1034  EFM_ASSERT((uint32_t)confDecSt->confA.nextState < LESENSE_NUM_DECODER_STATES);
1035  EFM_ASSERT((uint32_t)confDecSt->confB.compMask < 16U);
1036  EFM_ASSERT((uint32_t)confDecSt->confB.compVal < 16U);
1037  EFM_ASSERT((uint32_t)confDecSt->confB.nextState < LESENSE_NUM_DECODER_STATES);
1038 
1039  /* Configure state descriptor A (LESENSE_STi_TCONFA) for decoder state i.
1040  * Setting sensor compare value, sensor mask, next state index,
1041  * transition action, interrupt flag option and state descriptor chaining
1042  * configurations. */
1043  LESENSE->ST[decSt].TCONFA =
1044  (uint32_t)confDecSt->confA.prsAct
1045  | ((uint32_t)confDecSt->confA.compMask << _LESENSE_ST_TCONFA_MASK_SHIFT)
1046  | ((uint32_t)confDecSt->confA.compVal << _LESENSE_ST_TCONFA_COMP_SHIFT)
1047  | ((uint32_t)confDecSt->confA.nextState << _LESENSE_ST_TCONFA_NEXTSTATE_SHIFT)
1048  | ((uint32_t)confDecSt->confA.setInt << _LESENSE_ST_TCONFA_SETIF_SHIFT)
1049  | ((uint32_t)confDecSt->chainDesc << _LESENSE_ST_TCONFA_CHAIN_SHIFT);
1050 
1051  /* Configure state descriptor Bi (LESENSE_STi_TCONFB).
1052  * Setting sensor compare value, sensor mask, next state index, transition
1053  * action and interrupt flag option configurations. */
1054  LESENSE->ST[decSt].TCONFB =
1055  (uint32_t)confDecSt->confB.prsAct
1056  | ((uint32_t)confDecSt->confB.compMask << _LESENSE_ST_TCONFB_MASK_SHIFT)
1057  | ((uint32_t)confDecSt->confB.compVal << _LESENSE_ST_TCONFB_COMP_SHIFT)
1058  | ((uint32_t)confDecSt->confB.nextState << _LESENSE_ST_TCONFB_NEXTSTATE_SHIFT)
1059  | ((uint32_t)confDecSt->confB.setInt << _LESENSE_ST_TCONFB_SETIF_SHIFT);
1060 }
1061 
1062 
1063 /***************************************************************************/
1079 void LESENSE_DecoderStateSet(uint32_t decSt)
1080 {
1081  EFM_ASSERT(decSt <= _LESENSE_DECSTATE_DECSTATE_MASK);
1082 
1083  LESENSE->DECSTATE = decSt & _LESENSE_DECSTATE_DECSTATE_MASK;
1084 }
1085 
1086 
1087 /***************************************************************************/
1095 uint32_t LESENSE_DecoderStateGet(void)
1096 {
1097  return LESENSE->DECSTATE & _LESENSE_DECSTATE_DECSTATE_MASK;
1098 }
1099 
1100 #if defined(_LESENSE_PRSCTRL_MASK)
1101 /***************************************************************************/
1115 void LESENSE_DecoderPrsOut(bool enable, uint32_t decMask, uint32_t decVal)
1116 {
1117  LESENSE->PRSCTRL = (enable << _LESENSE_PRSCTRL_DECCMPEN_SHIFT)
1118  | (decMask << _LESENSE_PRSCTRL_DECCMPMASK_SHIFT)
1119  | (decVal << _LESENSE_PRSCTRL_DECCMPVAL_SHIFT);
1120 }
1121 #endif
1122 
1123 /***************************************************************************/
1136 void LESENSE_ScanStart(void)
1137 {
1138  /* Wait for any pending previous write operation to the CMD register to
1139  complete before accessing the CMD register. */
1140  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1141  ;
1142 
1143  /* Start scanning of sensors */
1144  LESENSE->CMD = LESENSE_CMD_START;
1145 
1146  /* Wait for the write operation to the CMD register to complete before
1147  returning. */
1148  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1149  ;
1150 }
1151 
1152 
1153 /***************************************************************************/
1169 void LESENSE_ScanStop(void)
1170 {
1171  /* Wait for any pending previous write operation to the CMD register to
1172  complete before accessing the CMD register. */
1173  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1174  ;
1175 
1176  /* Stop scanning of sensors */
1177  LESENSE->CMD = LESENSE_CMD_STOP;
1178 
1179  /* Wait for the write operation to the CMD register to complete before
1180  returning. */
1181  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1182  ;
1183 }
1184 
1185 
1186 /***************************************************************************/
1199 void LESENSE_DecoderStart(void)
1200 {
1201  /* Wait for any pending previous write operation to the CMD register to
1202  complete before accessing the CMD register. */
1203  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1204  ;
1205 
1206  /* Start decoder */
1207  LESENSE->CMD = LESENSE_CMD_DECODE;
1208 
1209  /* Wait for the write operation to the CMD register to complete before
1210  returning. */
1211  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1212  ;
1213 }
1214 
1215 
1216 /***************************************************************************/
1229 void LESENSE_ResultBufferClear(void)
1230 {
1231  /* Wait for any pending previous write operation to the CMD register to
1232  complete before accessing the CMD register. */
1233  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1234  ;
1235 
1236  LESENSE->CMD = LESENSE_CMD_CLEARBUF;
1237 
1238  /* Wait for the write operation to the CMD register to complete before
1239  returning. */
1240  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1241  ;
1242 }
1243 
1244 
1245 /***************************************************************************/
1258 void LESENSE_Reset(void)
1259 {
1260  uint32_t i;
1261 
1262  /* Disable all LESENSE interrupts first */
1263  LESENSE->IEN = _LESENSE_IEN_RESETVALUE;
1264 
1265  /* Clear all pending LESENSE interrupts */
1266  LESENSE->IFC = _LESENSE_IFC_MASK;
1267 
1268  /* Stop the decoder */
1269  LESENSE->DECCTRL |= LESENSE_DECCTRL_DISABLE;
1270 
1271  /* Wait for any pending previous write operation to the CMD register to
1272  complete before accessing the CMD register. */
1273  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1274  ;
1275 
1276  /* Stop sensor scan and clear result buffer */
1277  LESENSE->CMD = (LESENSE_CMD_STOP | LESENSE_CMD_CLEARBUF);
1278 
1279  /* Reset LESENSE configuration registers */
1280  LESENSE->CTRL = _LESENSE_CTRL_RESETVALUE;
1281  LESENSE->PERCTRL = _LESENSE_PERCTRL_RESETVALUE;
1282  LESENSE->DECCTRL = _LESENSE_DECCTRL_RESETVALUE;
1283  LESENSE->BIASCTRL = _LESENSE_BIASCTRL_RESETVALUE;
1284 #if defined(_LESENSE_EVALCTRL_MASK)
1285  LESENSE->EVALCTRL = _LESENSE_EVALCTRL_RESETVALUE;
1286  LESENSE->PRSCTRL = _LESENSE_PRSCTRL_RESETVALUE;
1287 #endif
1288  LESENSE->CHEN = _LESENSE_CHEN_RESETVALUE;
1289  LESENSE->IDLECONF = _LESENSE_IDLECONF_RESETVALUE;
1290  LESENSE->ALTEXCONF = _LESENSE_ALTEXCONF_RESETVALUE;
1291 
1292  /* Disable LESENSE to control GPIO pins */
1293 #if defined(_LESENSE_ROUTE_MASK)
1294  LESENSE->ROUTE = _LESENSE_ROUTE_RESETVALUE;
1295 #else
1296  LESENSE->ROUTEPEN = _LESENSE_ROUTEPEN_RESETVALUE;
1297 #endif
1298 
1299  /* Reset all channel configuration registers */
1300  for (i = 0U; i < LESENSE_NUM_CHANNELS; ++i)
1301  {
1302  LESENSE->CH[i].TIMING = _LESENSE_CH_TIMING_RESETVALUE;
1303  LESENSE->CH[i].INTERACT = _LESENSE_CH_INTERACT_RESETVALUE;
1304  LESENSE->CH[i].EVAL = _LESENSE_CH_EVAL_RESETVALUE;
1305  }
1306 
1307  /* Reset all decoder state configuration registers */
1308  for (i = 0U; i < LESENSE_NUM_DECODER_STATES; ++i)
1309  {
1310  LESENSE->ST[i].TCONFA = _LESENSE_ST_TCONFA_RESETVALUE;
1311  LESENSE->ST[i].TCONFB = _LESENSE_ST_TCONFB_RESETVALUE;
1312  }
1313 
1314  /* Wait for the write operation to the CMD register to complete before
1315  returning. */
1316  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1317  ;
1318 }
1319 
1320 
1324 #endif /* defined(LESENSE_COUNT) && (LESENSE_COUNT > 0) */
Clock management unit (CMU) API.
Emlib peripheral API "assert" implementation.
RAM and peripheral bit-field set and clear API.
Low Energy Sensor (LESENSE) peripheral API.
__STATIC_INLINE void BUS_RegBitWrite(volatile uint32_t *addr, unsigned int bit, unsigned int val)
Perform a single-bit write operation on a peripheral register.
Definition: em_bus.h:148
uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)
Get clock frequency for a clock point.
Definition: em_cmu.c:1550