1 /***************************************************************************//**
2  * @file
3  * @brief Low Energy Sensor (LESENSE) Peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #include "em_lesense.h"
32 
33 #if defined(LESENSE_COUNT) && (LESENSE_COUNT > 0)
34 #include "em_assert.h"
35 #include "em_bus.h"
36 #include "em_cmu.h"
37 
38 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
39 #if !defined(UINT32_MAX)
40 #define UINT32_MAX ((uint32_t)(0xFFFFFFFF))
41 #endif
42 /** @endcond */
43 
44 /***************************************************************************//**
45  * @addtogroup lesense LESENSE - Low Energy Sensor
46  * @brief Low Energy Sensor (LESENSE) Peripheral API
47  * @details
48  *  This module contains functions to control the LESENSE peripheral of Silicon
49  *  Labs 32-bit MCUs and SoCs. LESENSE is a low-energy sensor interface capable
50  *  of autonomously collecting and processing data from multiple sensors even
51  *  when in EM2.
52  * @{
53  ******************************************************************************/
54 
55 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
56 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
57 #if defined(_LESENSE_ROUTE_MASK)
58 #define GENERIC_LESENSE_ROUTE    LESENSE->ROUTE
59 #else
60 #define GENERIC_LESENSE_ROUTE    LESENSE->ROUTEPEN
61 #endif
62 #else
63 #define GENERIC_LESENSE_ROUTE    GPIO->LESENSEROUTE.ROUTEEN
64 #endif
65 
66 #if defined(_SILICON_LABS_32B_SERIES_0)
67 /* DACOUT mode only available on channel 0, 1, 2, 3, 12, 13, 14, 15 */
68 #define DACOUT_SUPPORT  0xF00F
69 #elif defined(_SILICON_LABS_32B_SERIES_1)
70 /* DACOUT mode only available on channel 4, 5, 7, 10, 12, 13 */
71 #define DACOUT_SUPPORT  0x34B0
72 #else
73 /* DACOUT mode only available on channel 0, 1, 2 */
74 #define DACOUT_SUPPORT  0x7
75 #endif
76 /** @endcond */
77 
78 /*******************************************************************************
79  **************************   LOCAL FUNCTIONS   ********************************
80  ******************************************************************************/
81 
82 /*******************************************************************************
83  **************************   GLOBAL FUNCTIONS   *******************************
84  ******************************************************************************/
85 
86 /***************************************************************************//**
87  * @brief
88  *   Initialize the LESENSE module.
89  *
90  * @details
91  *   This function configures the main parameters of the LESENSE interface.
92  *   See the initialization parameter type definition
93  *   (@ref LESENSE_Init_TypeDef) for more details.
94  *
95  * @note
96  *   @ref LESENSE_Init() is designed to initialize LESENSE once in an
97  *   operation cycle. Be aware of the effects of reconfiguration if using this
98  *   function from multiple sources in your code. This function has not been
99  *   designed to be re-entrant.
100  *   Requesting reset by setting @p reqReset to true is required in each reset
101  *   or power-on cycle to configure the default values of the RAM
102  *   mapped LESENSE registers.
103  *   Notice that GPIO pins used by the LESENSE module must be properly
104  *   configured by the user explicitly for the LESENSE to work as
105  *   intended.
106  *   (When configuring pins, one should remember to consider the sequence of
107  *   configuration to avoid unintended pulses/glitches on output
108  *   pins.)
109  *
110  * @param[in] init
111  *   The LESENSE initialization structure.
112  *
113  * @param[in] reqReset
114  *   Request to call @ref LESENSE_Reset() first to initialize all
115  *   LESENSE registers with default values.
116  ******************************************************************************/
LESENSE_Init(const LESENSE_Init_TypeDef * init,bool reqReset)117 void LESENSE_Init(const LESENSE_Init_TypeDef * init, bool reqReset)
118 {
119   /* Sanity check of initialization values. */
120   EFM_ASSERT((uint32_t)init->timeCtrl.startDelay < 4U);
121 #if defined(_LESENSE_PERCTRL_DACPRESC_MASK)
122   EFM_ASSERT((uint32_t)init->perCtrl.dacPresc < 32U);
123 #endif
124 
125 #if defined(_SILICON_LABS_32B_SERIES_2)
126   if (LESENSE->EN != 0U) {
127     /* Wait for synchronization before writing to EN register */
128     while (LESENSE->SYNCBUSY) {
129       /* Wait for all synchronizations to finish */
130     }
131 
132     /* Disable LESENSE module */
133     LESENSE->EN_CLR = LESENSE_EN_EN;
134     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
135       /* Wait for disabling to finish */
136     }
137   }
138 #endif
139 
140   /* Reset LESENSE registers if requested. */
141   if (reqReset) {
142     LESENSE_Reset();
143   }
144 
145   /* Set sensor start delay for each channel. */
146   LESENSE_StartDelaySet((uint32_t)init->timeCtrl.startDelay);
147 #if defined(_LESENSE_TIMCTRL_AUXSTARTUP_MASK)
148   /* Configure the AUXHRFCO startup delay. */
149   LESENSE->TIMCTRL = (LESENSE->TIMCTRL & (~_LESENSE_TIMCTRL_AUXSTARTUP_MASK))
150                      | (init->timeCtrl.delayAuxStartup << _LESENSE_TIMCTRL_AUXSTARTUP_SHIFT);
151 #endif
152 
153   /* LESENSE core control configuration.
154    * Set the PRS source, SCANCONF register usage strategy, interrupt and
155    * DMA trigger level condition, DMA wakeup condition, bias mode,
156    * enable/disable to sample both ACMPs simultaneously, enable/disable to store
157    * SCANRES in CNT_RES after each scan, enable/disable to always write to the
158    * result buffer, even if it is full, and enable/disable LESENSE running in debug
159    * mode. */
160 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
161   LESENSE->CTRL =
162     ((uint32_t)init->coreCtrl.prsSel         << _LESENSE_CTRL_PRSSEL_SHIFT)
163     | (uint32_t)init->coreCtrl.scanConfSel
164     | (uint32_t)init->coreCtrl.bufTrigLevel
165     | (uint32_t)init->coreCtrl.wakeupOnDMA
166 #if defined(_LESENSE_CTRL_ACMP0INV_MASK)
167     | ((uint32_t)init->coreCtrl.invACMP0     << _LESENSE_CTRL_ACMP0INV_SHIFT)
168     | ((uint32_t)init->coreCtrl.invACMP1     << _LESENSE_CTRL_ACMP1INV_SHIFT)
169 #endif
170     | ((uint32_t)init->coreCtrl.dualSample   << _LESENSE_CTRL_DUALSAMPLE_SHIFT)
171     | ((uint32_t)init->coreCtrl.storeScanRes << _LESENSE_CTRL_STRSCANRES_SHIFT)
172     | ((uint32_t)init->coreCtrl.bufOverWr    << _LESENSE_CTRL_BUFOW_SHIFT)
173     | ((uint32_t)init->coreCtrl.debugRun     << _LESENSE_CTRL_DEBUGRUN_SHIFT);
174 #else
175   EFM_ASSERT(init->coreCtrl.fifoTrigLevel < 16);
176   LESENSE->CFG = (uint32_t)init->coreCtrl.scanConfSel
177                  | (uint32_t)init->coreCtrl.wakeupOnDMA
178                  | ((uint32_t)init->coreCtrl.fifoTrigLevel << _LESENSE_CFG_RESFIDL_SHIFT)
179                  | ((uint32_t)init->coreCtrl.dualSample    << _LESENSE_CFG_DUALSAMPLE_SHIFT)
180                  | ((uint32_t)init->coreCtrl.storeScanRes  << _LESENSE_CFG_STRSCANRES_SHIFT)
181                  | ((uint32_t)init->coreCtrl.debugRun      << _LESENSE_CFG_DEBUGRUN_SHIFT);
182 
183   /* Set PRS input */
184   PRS->CONSUMER_LESENSE_START = init->coreCtrl.prsSel;
185 #endif
186 
187   /* Set scan mode in the CTRL/CFG register using the provided function. Don't
188    * start scanning immediately. */
189   LESENSE_ScanModeSet((LESENSE_ScanMode_TypeDef)init->coreCtrl.scanStart, false);
190 
191   /* The LESENSE peripheral control configuration.
192    * Set DAC0 and DAC1 data source, conversion mode, and output mode. Set the DAC
193    * prescaler and reference. Set ACMP0 and ACMP1 control mode. Set the ACMP and DAC
194    * duty cycle (warm up) mode. */
195   LESENSE->PERCTRL = 0
196 #if defined(_LESENSE_PERCTRL_DACCH0EN_MASK)
197                      | ((uint32_t)init->perCtrl.dacCh0En       << _LESENSE_PERCTRL_DACCH0EN_SHIFT)
198                      | ((uint32_t)init->perCtrl.dacCh1En       << _LESENSE_PERCTRL_DACCH1EN_SHIFT)
199 #endif
200                      | ((uint32_t)init->perCtrl.dacCh0Data     << _LESENSE_PERCTRL_DACCH0DATA_SHIFT)
201 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
202                      | ((uint32_t)init->perCtrl.dacCh1Data     << _LESENSE_PERCTRL_DACCH1DATA_SHIFT)
203 #endif
204 #if defined(_LESENSE_PERCTRL_DACCH0CONV_MASK)
205                      | ((uint32_t)init->perCtrl.dacCh0ConvMode << _LESENSE_PERCTRL_DACCH0CONV_SHIFT)
206                      | ((uint32_t)init->perCtrl.dacCh0OutMode  << _LESENSE_PERCTRL_DACCH0OUT_SHIFT)
207                      | ((uint32_t)init->perCtrl.dacCh1ConvMode << _LESENSE_PERCTRL_DACCH1CONV_SHIFT)
208                      | ((uint32_t)init->perCtrl.dacCh1OutMode  << _LESENSE_PERCTRL_DACCH1OUT_SHIFT)
209                      | ((uint32_t)init->perCtrl.dacPresc       << _LESENSE_PERCTRL_DACPRESC_SHIFT)
210                      | (uint32_t)init->perCtrl.dacRef
211 #endif
212 #if defined(_LESENSE_PERCTRL_DACCONVTRIG_MASK)
213                      | ((uint32_t)init->perCtrl.dacStartupHalf << _LESENSE_PERCTRL_DACSTARTUP_SHIFT)
214                      | ((uint32_t)init->perCtrl.dacScan        << _LESENSE_PERCTRL_DACCONVTRIG_SHIFT)
215 #endif
216                      | ((uint32_t)init->perCtrl.acmp0Mode      << _LESENSE_PERCTRL_ACMP0MODE_SHIFT)
217                      | ((uint32_t)init->perCtrl.acmp1Mode      << _LESENSE_PERCTRL_ACMP1MODE_SHIFT)
218 #if defined(_LESENSE_PERCTRL_ACMP0INV_MASK)
219                      | ((uint32_t)init->coreCtrl.invACMP0      << _LESENSE_PERCTRL_ACMP0INV_SHIFT)
220                      | ((uint32_t)init->coreCtrl.invACMP1      << _LESENSE_PERCTRL_ACMP1INV_SHIFT)
221 #endif
222 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
223                      | (uint32_t)init->perCtrl.warmupMode;
224 #else
225   ;
226 #endif
227 
228   /* The LESENSE decoder general control configuration.
229    * Set the decoder input source and select PRS input for decoder bits.
230    * Enable/disable the decoder to check the present state.
231    * Enable/disable decoder to channel interrupt mapping.
232    * Enable/disable decoder hysteresis on the PRS output.
233    * Enable/disable decoder hysteresis on count events.
234    * Enable/disable decoder hysteresis on interrupt requests.
235    * Enable/disable count mode on LESPRS0 and LESPRS1. */
236   LESENSE->DECCTRL =
237 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
238     (uint32_t)init->decCtrl.decInput
239     | ((uint32_t)init->decCtrl.prsChSel0 << _LESENSE_DECCTRL_PRSSEL0_SHIFT)
240     | ((uint32_t)init->decCtrl.prsChSel1 << _LESENSE_DECCTRL_PRSSEL1_SHIFT)
241     | ((uint32_t)init->decCtrl.prsChSel2 << _LESENSE_DECCTRL_PRSSEL2_SHIFT)
242     | ((uint32_t)init->decCtrl.prsChSel3 << _LESENSE_DECCTRL_PRSSEL3_SHIFT)
243     | ((uint32_t)init->decCtrl.chkState  << _LESENSE_DECCTRL_ERRCHK_SHIFT) |
244 #endif
245     ((uint32_t)init->decCtrl.intMap    << _LESENSE_DECCTRL_INTMAP_SHIFT)
246     | ((uint32_t)init->decCtrl.hystPRS0  << _LESENSE_DECCTRL_HYSTPRS0_SHIFT)
247     | ((uint32_t)init->decCtrl.hystPRS1  << _LESENSE_DECCTRL_HYSTPRS1_SHIFT)
248     | ((uint32_t)init->decCtrl.hystPRS2  << _LESENSE_DECCTRL_HYSTPRS2_SHIFT)
249     | ((uint32_t)init->decCtrl.hystIRQ   << _LESENSE_DECCTRL_HYSTIRQ_SHIFT)
250     | ((uint32_t)init->decCtrl.prsCount  << _LESENSE_DECCTRL_PRSCNT_SHIFT);
251 
252 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
253   /* Set the initial LESENSE decoder state. */
254   LESENSE_DecoderStateSet((uint32_t)init->decCtrl.initState);
255 
256   /* The LESENSE bias control configuration. */
257   LESENSE->BIASCTRL = (uint32_t)init->coreCtrl.biasMode;
258 #endif
259 
260 #if defined(_SILICON_LABS_32B_SERIES_2)
261   LESENSE->EN_SET = LESENSE_EN_EN;
262 #endif
263 }
264 
265 /***************************************************************************//**
266  * @brief
267  *   Set the scan frequency for periodic scanning.
268  *
269  * @details
270  *   This function only applies to LESENSE if a period counter is used as
271  *   a trigger for scan start.
272  *   The calculation is based on the following formula:
273  *   Fscan = LFACLKles / ((1+PCTOP)*2^PCPRESC)
274  *
275  * @note
276  *   Note that the calculation does not necessarily result in the requested
277  *   scan frequency due to integer division. Check the return value for the
278  *   resulted scan frequency.
279  *
280  * @param[in] refFreq
281  *   Select reference LFACLK clock frequency in Hz. If set to 0, the current
282  *   clock frequency is being used as a reference.
283  *
284  * @param[in] scanFreq
285  *   Set the desired scan frequency in Hz.
286  *
287  * @return
288  *   Frequency in Hz calculated and set by this function. Users can use this to
289  *   compare the requested and set values.
290  ******************************************************************************/
LESENSE_ScanFreqSet(uint32_t refFreq,uint32_t scanFreq)291 uint32_t LESENSE_ScanFreqSet(uint32_t refFreq, uint32_t scanFreq)
292 {
293   uint32_t tmp;
294   uint32_t pcPresc = 0UL;  /* Period counter prescaler. */
295   uint32_t clkDiv  = 1UL;  /* Clock divisor value (2^pcPresc). */
296   uint32_t pcTop   = 63UL; /* Period counter top value (max. 63). */
297   uint32_t calcScanFreq;   /* Variable for testing the calculation algorithm. */
298 #if defined(_SILICON_LABS_32B_SERIES_2)
299   bool enabled = false;
300 #endif
301 
302 #if defined(_SILICON_LABS_32B_SERIES_2)
303   if (LESENSE->EN != 0U) {
304     enabled = true;
305     /* Wait for synchronization before writing to EN register */
306     while (LESENSE->SYNCBUSY) {
307       /* Wait for all synchronizations to finish */
308     }
309     /* Disable LESENSE module */
310     LESENSE->EN_CLR = LESENSE_EN_EN;
311     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
312       /* Wait for disabling to finish */
313     }
314   }
315 #endif
316 
317   /* If refFreq is set to 0, the currently-configured reference clock is
318    * assumed. */
319   if (!refFreq) {
320 #if defined(_SILICON_LABS_32B_SERIES_1) || defined(_SILICON_LABS_32B_SERIES_0)
321     refFreq = CMU_ClockFreqGet(cmuClock_LESENSE);
322 #elif defined(_SILICON_LABS_32B_SERIES_2)
323     refFreq = CMU_ClockFreqGet(cmuClock_LESENSEHF);
324 #endif
325   }
326 
327   /* The maximum value of pcPresc is 128. AS a result, using the reference frequency less than
328    * 33554431 Hz (33.554431 MHz), the frequency calculation in the while loop
329    * below will not overflow. */
330   EFM_ASSERT(refFreq < ((uint32_t)UINT32_MAX / 128UL));
331 
332   /* A sanity check of scan frequency value. */
333   EFM_ASSERT((scanFreq > 0U) && (scanFreq <= refFreq));
334 
335   /* Calculate the minimum necessary prescaler value to provide the
336    * biggest possible resolution for setting the scan frequency.
337    * The maximum number of calculation cycles is 7 (value of lesenseClkDiv_128). */
338   while ((refFreq / ((uint32_t)scanFreq * clkDiv) > (pcTop + 1UL))
339          && (pcPresc < lesenseClkDiv_128)) {
340     ++pcPresc;
341     clkDiv = (uint32_t)1UL << pcPresc;
342   }
343 
344   /* Calculate the pcTop value. */
345   pcTop = ((uint32_t)refFreq / ((uint32_t)scanFreq * clkDiv)) - 1UL;
346 
347   /* Clear current PCPRESC and PCTOP settings. Be aware of the effect of
348    * non-atomic Read-Modify-Write on LESENSE->TIMCRTL. */
349   tmp = LESENSE->TIMCTRL & (~_LESENSE_TIMCTRL_PCPRESC_MASK
350                             & ~_LESENSE_TIMCTRL_PCTOP_MASK);
351 
352   /* Set new values in tmp while reserving other settings. */
353   tmp |= ((uint32_t)pcPresc << _LESENSE_TIMCTRL_PCPRESC_SHIFT)
354          | ((uint32_t)pcTop << _LESENSE_TIMCTRL_PCTOP_SHIFT);
355 
356   /* Set values in the LESENSE_TIMCTRL register. */
357   LESENSE->TIMCTRL = tmp;
358 
359   /* For testing the calculation algorithm. */
360   calcScanFreq = ((uint32_t)refFreq / ((uint32_t)(1UL + pcTop) * clkDiv));
361 
362 #if defined(_SILICON_LABS_32B_SERIES_2)
363   /* Re-Enable LESENSE module if it was enabled in the first place. */
364   if (enabled == true) {
365     LESENSE->EN_SET = LESENSE_EN_EN;
366   }
367 #endif
368 
369   return calcScanFreq;
370 }
371 
372 /***************************************************************************//**
373  * @brief
374  *   Set scan mode of the LESENSE channels.
375  *
376  * @details
377  *   This function configures how the scan start is triggered. It can be
378  *   used for re-configuring the scan mode while running the application but it
379  *   is also used by LESENSE_Init() for initialization.
380  *
381  * @note
382  *   Users can configure the scan mode by LESENSE_Init() function, but only with
383  *   a significant overhead. This simple function serves the purpose of
384  *   controlling this parameter after the channel has been configured.
385  *   Be aware of the effects of the non-atomic Read-Modify-Write cycle.
386  *
387  * @param[in] scanMode
388  *   Select the location to map LESENSE alternate excitation channels.
389  *   @li lesenseScanStartPeriodic - A new scan is started each time the period
390  *                                  counter overflows.
391  *   @li lesenseScanStartOneShot - A single scan is performed when
392  *                                 LESENSE_ScanStart() is called.
393  *   @li lesenseScanStartPRS - A new scan is triggered by pulse on the PRS channel.
394  *
395  * @param[in] start
396  *   If true, LESENSE_ScanStart() is immediately issued after configuration.
397  ******************************************************************************/
LESENSE_ScanModeSet(LESENSE_ScanMode_TypeDef scanMode,bool start)398 void LESENSE_ScanModeSet(LESENSE_ScanMode_TypeDef scanMode,
399                          bool start)
400 {
401   uint32_t tmp; /* temporary storage of the CTRL register value */
402 #if defined(_SILICON_LABS_32B_SERIES_2)
403   bool enabled = false;
404 #endif
405 
406 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
407   /* Save the CTRL register value to tmp.
408    * Be aware of the effects of the non-atomic Read-Modify-Write cycle. */
409   tmp = LESENSE->CTRL & ~(_LESENSE_CTRL_SCANMODE_MASK);
410   /* Setting the requested scanMode to the CTRL register. Casting signed int
411    * (enumeration) to unsigned long (uint32_t). */
412   tmp |= (uint32_t)scanMode;
413 
414   /* Write the new value to the CTRL register. */
415   LESENSE->CTRL = tmp;
416 #else
417   if (LESENSE->EN != 0U) {
418     enabled = true;
419     /* Wait for synchronization before writing to EN register */
420     while (LESENSE->SYNCBUSY) {
421       /* Wait for all synchronizations to finish */
422     }
423 
424     /* Disable LESENSE module */
425     LESENSE->EN_CLR = LESENSE_EN_EN;
426     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
427       /* Wait for disabling to finish */
428     }
429   }
430 
431   /* Save the CTRL register value to tmp.
432    * Be aware of the effects of the non-atomic Read-Modify-Write cycle. */
433   tmp = LESENSE->CFG & ~(_LESENSE_CFG_SCANMODE_MASK);
434   /* Setting the requested scanMode to the CTRL register. Casting signed int
435    * (enumeration) to unsigned long (uint32_t). */
436   tmp |= (uint32_t)scanMode;
437   /* Write the new value to the CTRL register. */
438   LESENSE->CFG = tmp;
439 
440   /* Re-Enable LESENSE module if it was enabled in the first place. */
441   if (enabled || start) {
442     LESENSE->EN_SET = LESENSE_EN_EN;
443   }
444 #endif
445 
446   /* Start the sensor scanning if requested. */
447   if (start) {
448     LESENSE_ScanStart();
449   }
450 }
451 
452 /***************************************************************************//**
453  * @brief
454  *   Set the start delay of the sensor interaction on each channel.
455  *
456  * @details
457  *   This function sets the start delay of the sensor interaction on each channel.
458  *   It can be used for adjusting the start delay while running the application
459  *   but it is also used by LESENSE_Init() for initialization.
460  *
461  * @note
462  *   Users can configure the start delay by LESENSE_Init() function, but only
463  *   with a significant overhead. This simple function serves the purpose of
464  *   controlling this parameter after the channel has been configured.
465  *   Be aware of the effects of the non-atomic Read-Modify-Write cycle.
466  *
467  * @param[in] startDelay
468  *   A number of LFACLK cycles to delay. A valid range: 0-3 (2 bit).
469  ******************************************************************************/
LESENSE_StartDelaySet(uint8_t startDelay)470 void LESENSE_StartDelaySet(uint8_t startDelay)
471 {
472   uint32_t tmp; /* Temporary storage of the TIMCTRL register value */
473 #if defined(_SILICON_LABS_32B_SERIES_2)
474   bool enabled = false;
475 #endif
476 
477   /* Sanity check of the startDelay. */
478   EFM_ASSERT(startDelay < 4U);
479 
480 #if defined(_SILICON_LABS_32B_SERIES_2)
481   if (LESENSE->EN != 0U) {
482     enabled = true;
483     /* Wait for synchronization before writing to EN register */
484     while (LESENSE->SYNCBUSY) {
485       /* Wait for all synchronizations to finish */
486     }
487     /* Disable LESENSE module */
488     LESENSE->EN_CLR = LESENSE_EN_EN;
489     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
490       /* Wait for disabling to finish */
491     }
492   }
493 #endif
494 
495   /* Save the TIMCTRL register value to tmp.
496    * Be aware of the effects of the non-atomic Read-Modify-Write cycle. */
497   tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_STARTDLY_MASK);
498   /* Setting the requested startDelay to the TIMCTRL register. */
499   tmp |= (uint32_t)startDelay << _LESENSE_TIMCTRL_STARTDLY_SHIFT;
500 
501   /* Write the new value to the TIMCTRL register. */
502   LESENSE->TIMCTRL = tmp;
503 
504 #if defined(_SILICON_LABS_32B_SERIES_2)
505   /* Re-Enable LESENSE module if it was enabled in the first place. */
506   if (enabled == true) {
507     LESENSE->EN_SET = LESENSE_EN_EN;
508   }
509 #endif
510 }
511 
512 /***************************************************************************//**
513  * @brief
514  *   Set the clock division for LESENSE timers.
515  *
516  * @details
517  *   Use this function to configure the clock division for the LESENSE timers
518  *   used for excitation timing.
519  *   The division setting is global but the clock source can be selected for
520  *   each channel using LESENSE_ChannelConfig() function. See
521  *   documentation for more details.
522  *
523  * @note
524  *   If AUXHFRCO is used for excitation timing, LFACLK can't exceed 500 kHz.
525  *   LFACLK can't exceed 50 kHz if the ACMP threshold level (ACMPTHRES) is not
526  *   equal for all channels.
527  *
528  * @param[in] clk
529  *   Select the clock to prescale.
530  *    @li lesenseClkHF - set AUXHFRCO clock divisor for HF timer.
531  *    @li lesenseClkLF - set LFACLKles clock divisor for LF timer.
532  *
533  * @param[in] clkDiv
534  *   The clock divisor value. A valid range depends on the @p clk value.
535  ******************************************************************************/
LESENSE_ClkDivSet(LESENSE_ChClk_TypeDef clk,LESENSE_ClkPresc_TypeDef clkDiv)536 void LESENSE_ClkDivSet(LESENSE_ChClk_TypeDef clk,
537                        LESENSE_ClkPresc_TypeDef clkDiv)
538 {
539   uint32_t tmp;
540 #if defined(_SILICON_LABS_32B_SERIES_2)
541   bool enabled = false;
542 
543   if (LESENSE->EN != 0U) {
544     enabled = true;
545     /* Wait for synchronization before writing to EN register */
546     while (LESENSE->SYNCBUSY) {
547       /* Wait for all synchronizations to finish */
548     }
549     /* Disable LESENSE module */
550     LESENSE->EN_CLR = LESENSE_EN_EN;
551     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
552       /* Wait for disabling to finish */
553     }
554   }
555 #endif
556 
557   /* Select the clock to prescale. */
558   switch (clk) {
559     case lesenseClkHF:
560       /* A sanity check of the clock divisor for the HF clock. */
561       EFM_ASSERT((uint32_t)clkDiv <= lesenseClkDiv_8);
562 
563       /* Clear the current AUXPRESC settings. */
564       tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_AUXPRESC_MASK);
565 
566       /* Set the new values in tmp while reserving other settings. */
567       tmp |= ((uint32_t)clkDiv << _LESENSE_TIMCTRL_AUXPRESC_SHIFT);
568 
569       /* Set values in LESENSE_TIMCTRL register. */
570       LESENSE->TIMCTRL = tmp;
571       break;
572 
573     case lesenseClkLF:
574       /* Clear current LFPRESC settings. */
575       tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_LFPRESC_MASK);
576 
577       /* Set new values in tmp while reserving other settings. */
578       tmp |= ((uint32_t)clkDiv << _LESENSE_TIMCTRL_LFPRESC_SHIFT);
579 
580       /* Set values in the LESENSE_TIMCTRL register. */
581       LESENSE->TIMCTRL = tmp;
582       break;
583 
584     default:
585       EFM_ASSERT(0);
586       break;
587   }
588 
589 #if defined(_SILICON_LABS_32B_SERIES_2)
590   /* Re-Enable LESENSE module if it was enabled in the first place. */
591   if (enabled == true) {
592     LESENSE->EN_SET = LESENSE_EN_EN;
593   }
594 #endif
595 }
596 
597 /***************************************************************************//**
598  * @brief
599  *   Configure all (16) LESENSE sensor channels.
600  *
601  * @details
602  *   This function configures all sensor channels of the LESENSE interface.
603  *   See the configuration parameter type definition
604  *   (LESENSE_ChAll_TypeDef) for more details.
605  *
606  * @note
607  *   Channels can be configured individually using LESENSE_ChannelConfig()
608  *   function.
609  *   Notice that pins used by the LESENSE module must be properly configured
610  *   by the user explicitly for LESENSE to work as intended.
611  *   (When configuring pins, consider the sequence of the
612  *   configuration to avoid unintended pulses/glitches on output
613  *   pins.)
614  *
615  * @param[in] confChAll
616  *   A configuration structure for all (16) LESENSE sensor channels.
617  ******************************************************************************/
LESENSE_ChannelAllConfig(const LESENSE_ChAll_TypeDef * confChAll)618 void LESENSE_ChannelAllConfig(const LESENSE_ChAll_TypeDef * confChAll)
619 {
620   uint32_t i;
621 
622   /* Iterate through all 16 channels. */
623   for (i = 0U; i < LESENSE_NUM_CHANNELS; ++i) {
624     /* Configure scan channels. */
625     LESENSE_ChannelConfig(&confChAll->Ch[i], i);
626   }
627 }
628 
629 /***************************************************************************//**
630  * @brief
631  *   Configure a single LESENSE sensor channel.
632  *
633  * @details
634  *   This function configures a single sensor channel of the LESENSE interface.
635  *   See the configuration parameter type definition
636  *   (LESENSE_ChDesc_TypeDef) for more details.
637  *
638  * @note
639  *   This function has been designed to minimize the effects of sensor channel
640  *   reconfiguration while LESENSE is in operation. However, be aware
641  *   of these effects and the right timing to call this function.
642  *   Parameter @p useAltEx must be true in the channel configuration to
643  *   use alternate excitation pins.
644  *
645  * @param[in] confCh
646  *   A configuration structure for a single LESENSE sensor channel.
647  *
648  * @param[in] chIdx
649  *   A channel index to configure (0-15).
650  ******************************************************************************/
LESENSE_ChannelConfig(const LESENSE_ChDesc_TypeDef * confCh,uint32_t chIdx)651 void LESENSE_ChannelConfig(const LESENSE_ChDesc_TypeDef * confCh,
652                            uint32_t chIdx)
653 {
654   uint32_t tmp; /* A service variable. */
655 
656 #if defined(_SILICON_LABS_32B_SERIES_2)
657   bool enabled = false;
658 
659   if (LESENSE->EN != 0U) {
660     enabled = true;
661     /* Wait for synchronization before writing to EN register */
662     while (LESENSE->SYNCBUSY) {
663       /* Wait for all synchronizations to finish */
664     }
665     /* Disable LESENSE module */
666     LESENSE->EN_CLR = LESENSE_EN_EN;
667     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
668       /* Wait for disabling to finish */
669     }
670   }
671 #endif
672 
673   /* A sanity check of configuration parameters. */
674   EFM_ASSERT(chIdx < LESENSE_NUM_CHANNELS);
675   EFM_ASSERT(confCh->exTime      <= (_LESENSE_CH_TIMING_EXTIME_MASK >> _LESENSE_CH_TIMING_EXTIME_SHIFT));
676   EFM_ASSERT(confCh->measDelay   <= (_LESENSE_CH_TIMING_MEASUREDLY_MASK >> _LESENSE_CH_TIMING_MEASUREDLY_SHIFT));
677 #if defined(_SILICON_LABS_32B_SERIES_0)
678   // Sample delay on other devices are 8 bits which fits perfectly in uint8_t.
679   EFM_ASSERT(confCh->sampleDelay <= (_LESENSE_CH_TIMING_SAMPLEDLY_MASK >> _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT));
680 #endif
681 
682   /* Not a complete assert, as the maximum value of acmpThres depends on other
683    * configuration parameters. Check the parameter description of acmpThres
684    * for more details. */
685   EFM_ASSERT(confCh->acmpThres < 4096U);
686   if (confCh->chPinExMode == lesenseChPinExDACOut) {
687     EFM_ASSERT((0x1 << chIdx) & DACOUT_SUPPORT);
688   }
689 
690 #if defined(_LESENSE_IDLECONF_CH0_DACCH0)
691   EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh1
692                && ((chIdx != 12U)
693                    && (chIdx != 13U)
694                    && (chIdx != 14U)
695                    && (chIdx != 15U))));
696   EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh0
697                && ((chIdx != 0U)
698                    && (chIdx != 1U)
699                    && (chIdx != 2U)
700                    && (chIdx != 3U))));
701 #endif
702 
703   /* Configure the chIdx setup in LESENSE idle phase.
704    * Read-modify-write to support reconfiguration during the LESENSE
705    * operation. */
706   tmp               = (LESENSE->IDLECONF & ~((uint32_t)0x3UL << (chIdx * 2UL)));
707   tmp              |= ((uint32_t)confCh->chPinIdleMode << (chIdx * 2UL));
708   LESENSE->IDLECONF = tmp;
709 
710   /* A channel-specific timing configuration on scan channel chIdx.
711    * Set excitation time, sampling delay, and measurement delay. */
712   LESENSE_ChannelTimingSet(chIdx,
713                            confCh->exTime,
714                            confCh->sampleDelay,
715                            confCh->measDelay);
716 
717   /* A channel-specific configuration of clocks, sample mode, excitation pin mode
718    * alternate excitation usage, and interrupt mode on scan channel chIdx in
719    * LESENSE_CHchIdx_INTERACT. */
720   LESENSE->CH[chIdx].INTERACT =
721     ((uint32_t)confCh->exClk       << _LESENSE_CH_INTERACT_EXCLK_SHIFT)
722     | ((uint32_t)confCh->sampleClk << _LESENSE_CH_INTERACT_SAMPLECLK_SHIFT)
723     | (uint32_t)confCh->sampleMode
724     | (uint32_t)confCh->intMode
725     | (uint32_t)confCh->chPinExMode
726     | ((uint32_t)confCh->useAltEx  << _LESENSE_CH_INTERACT_ALTEX_SHIFT);
727 
728   /* Configure the channel-specific counter comparison mode, optional result
729    * forwarding to decoder, optional counter value storing, and optional result
730    * inverting on scan channel chIdx in LESENSE_CHchIdx_EVAL. */
731 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
732   LESENSE->CH[chIdx].EVAL =
733     (uint32_t)confCh->compMode
734     | ((uint32_t)confCh->shiftRes    << _LESENSE_CH_EVAL_DECODE_SHIFT)
735     | ((uint32_t)confCh->storeCntRes << _LESENSE_CH_EVAL_STRSAMPLE_SHIFT)
736     | ((uint32_t)confCh->invRes      << _LESENSE_CH_EVAL_SCANRESINV_SHIFT)
737 #if defined(_LESENSE_CH_EVAL_MODE_MASK)
738     | ((uint32_t)confCh->evalMode    << _LESENSE_CH_EVAL_MODE_SHIFT)
739 #endif
740   ;
741 #else
742   LESENSE->CH[chIdx].EVALCFG =
743     (uint32_t)confCh->compMode
744     | ((uint32_t)confCh->shiftRes    << _LESENSE_CH_EVALCFG_DECODE_SHIFT)
745     | ((uint32_t)confCh->storeCntRes << _LESENSE_CH_EVALCFG_STRSAMPLE_SHIFT)
746     | ((uint32_t)confCh->invRes      << _LESENSE_CH_EVALCFG_SCANRESINV_SHIFT)
747     | ((uint32_t)confCh->evalMode    << _LESENSE_CH_EVALCFG_MODE_SHIFT)
748   ;
749 #endif
750 
751   /* Configure the analog comparator (ACMP) threshold and decision threshold for
752    * the counter separately with the function provided for that. */
753   LESENSE_ChannelThresSet(chIdx,
754                           confCh->acmpThres,
755                           confCh->cntThres);
756 
757   /* Enable/disable interrupts on channel */
758   BUS_RegBitWrite(&LESENSE->IEN, chIdx, confCh->enaInt);
759 
760   /* Enable/disable CHchIdx pin. */
761   BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE, chIdx, confCh->enaPin);
762 
763   /* Enable/disable scan channel chIdx. */
764   BUS_RegBitWrite(&LESENSE->CHEN, chIdx, confCh->enaScanCh);
765 
766 #if defined(_SILICON_LABS_32B_SERIES_2)
767   /* Re-Enable LESENSE module if it was enabled in the first place. */
768   if (enabled == true) {
769     LESENSE->EN_SET = LESENSE_EN_EN;
770   }
771 #endif
772 }
773 
774 /***************************************************************************//**
775  * @brief
776  *   Configure the LESENSE alternate excitation modes.
777  *
778  * @details
779  *   This function configures the alternate excitation channels of the LESENSE
780  *   interface. See the configuration parameter type definition
781  *   (LESENSE_ConfAltEx_TypeDef) for more details.
782  *
783  * @note
784  *   The @p useAltEx parameter must be true in the channel configuration structure
785  *   (LESENSE_ChDesc_TypeDef) to use alternate excitation pins on the
786  *   channel.
787  *
788  * @param[in] confAltEx
789  *   A configuration structure for LESENSE alternate excitation pins.
790  ******************************************************************************/
LESENSE_AltExConfig(const LESENSE_ConfAltEx_TypeDef * confAltEx)791 void LESENSE_AltExConfig(const LESENSE_ConfAltEx_TypeDef * confAltEx)
792 {
793   uint32_t i;
794 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
795   uint32_t tmp;
796 
797   /* Configure the alternate excitation mapping.
798    * Atomic read-modify-write using BUS_RegBitWrite function to
799    * support reconfiguration during the LESENSE operation. */
800   BUS_RegBitWrite(&LESENSE->CTRL,
801                   _LESENSE_CTRL_ALTEXMAP_SHIFT,
802                   confAltEx->altExMap);
803 
804   switch (confAltEx->altExMap) {
805     case lesenseAltExMapALTEX:
806       /* Iterate through the 8 possible alternate excitation pin descriptors. */
807       for (i = 0U; i < 8U; ++i) {
808         /* Enable/disable the alternate excitation pin i.
809          * Atomic read-modify-write using BUS_RegBitWrite function to
810          * support reconfiguration during the LESENSE operation. */
811         BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE,
812                         (16UL + i),
813                         confAltEx->AltEx[i].enablePin);
814 
815         /* Set up the idle phase state of the alternate excitation pin i.
816          * Read-modify-write to support reconfiguration during the LESENSE
817          * operation. */
818         tmp                = (LESENSE->ALTEXCONF & ~((uint32_t)0x3UL << (i * 2UL)));
819         tmp               |= ((uint32_t)confAltEx->AltEx[i].idleConf << (i * 2UL));
820         LESENSE->ALTEXCONF = tmp;
821 
822         /* Enable/disable always excite on channel i. */
823         BUS_RegBitWrite(&LESENSE->ALTEXCONF,
824                         (16UL + i),
825                         confAltEx->AltEx[i].alwaysEx);
826       }
827       break;
828 
829 #if defined(_LESENSE_CTRL_ALTEXMAP_ACMP)
830     case lesenseAltExMapACMP:
831 #else
832     case lesenseAltExMapCH:
833 #endif
834       /* Iterate through all 16 alternate excitation channels. */
835       for (i = 0U; i < 16U; ++i) {
836         /* Enable/disable the alternate ACMP excitation channel pin i. */
837         /* An atomic read-modify-write using BUS_RegBitWrite function to
838          * support reconfiguration during the LESENSE operation. */
839         BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE,
840                         i,
841                         confAltEx->AltEx[i].enablePin);
842       }
843       break;
844     default:
845       /* An illegal value. */
846       EFM_ASSERT(0);
847       break;
848   }
849 #else
850   /* Iterate through all 16 alternate excitation channels. */
851   for (i = 0U; i < 16U; ++i) {
852     /* Enable/disable the alternate excitation channel pin i. */
853     /* An atomic read-modify-write using BUS_RegBitWrite function to
854      * support reconfiguration during the LESENSE operation. */
855     BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE,
856                     i,
857                     confAltEx->AltEx[i].enablePin);
858   }
859 #endif
860 }
861 
862 /***************************************************************************//**
863  * @brief
864  *   Enable/disable LESENSE scan channel and the pin assigned to it.
865  *
866  * @details
867  *   Use this function to enable/disable a selected LESENSE scan channel and the
868  *   pin assigned to it.
869  *
870  * @note
871  *   Users can enable/disable scan channels and the channel pin with
872  *   the LESENSE_ChannelConfig() function, but only with a significant overhead.
873  *   This simple function controls these parameters
874  *   after the channel has been configured.
875  *
876  * @param[in] chIdx
877  *   An identifier of the scan channel. A valid range: 0-15.
878  *
879  * @param[in] enaScanCh
880  *   Enable/disable the selected scan channel by setting this parameter to
881  *   true/false respectively.
882  *
883  * @param[in] enaPin
884  *   Enable/disable the pin assigned to the channel selected by @p chIdx.
885  ******************************************************************************/
LESENSE_ChannelEnable(uint8_t chIdx,bool enaScanCh,bool enaPin)886 void LESENSE_ChannelEnable(uint8_t chIdx,
887                            bool enaScanCh,
888                            bool enaPin)
889 {
890   /* Enable/disable the assigned pin of scan channel chIdx.
891    * Note: BUS_RegBitWrite() function is used for setting/clearing single
892    * bit peripheral register bit fields. Read the function description in
893    * em_bus.h for more details. */
894   BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE, chIdx, enaPin);
895 
896   /* Enable/disable scan channel chIdx. */
897   BUS_RegBitWrite(&LESENSE->CHEN, chIdx, enaScanCh);
898 }
899 
900 /***************************************************************************//**
901  * @brief
902  *   Enable/disable LESENSE scan channel and the pin assigned to it.
903  *
904  * @details
905  *   Use this function to enable/disable LESENSE scan channels and the pins
906  *   assigned to them using a mask.
907  *
908  * @note
909  *   Users can enable/disable scan channels and channel pins by using the
910  *   LESENSE_ChannelAllConfig() function, but only with a significant overhead.
911  *   This simple function controls these parameters
912  *   after the channel has been configured.
913  *
914  * @param[in] chMask
915  *   Set the corresponding bit to 1 to enable, 0 to disable the selected scan
916  *   channel.
917  *
918  * @param[in] pinMask
919  *   Set the corresponding bit to 1 to enable, 0 to disable the pin on selected
920  *   channel.
921  ******************************************************************************/
LESENSE_ChannelEnableMask(uint16_t chMask,uint16_t pinMask)922 void LESENSE_ChannelEnableMask(uint16_t chMask, uint16_t pinMask)
923 {
924   /* Enable/disable all channels at once according to the mask. */
925   LESENSE->CHEN = chMask;
926   /* Enable/disable all channel pins at once according to the mask. */
927   GENERIC_LESENSE_ROUTE = pinMask;
928 }
929 
930 /***************************************************************************//**
931  * @brief
932  *   Set LESENSE channel timing parameters.
933  *
934  * @details
935  *   Use this function to set timing parameters on a selected LESENSE channel.
936  *
937  * @note
938  *   Users can configure the channel timing parameters with the
939  *   LESENSE_ChannelConfig() function, but only with a significant overhead.
940  *   This simple function controls these parameters
941  *   after the channel has been configured.
942  *
943  * @param[in] chIdx
944  *   An identifier of the scan channel. A valid range is 0-15.
945  *
946  * @param[in] exTime
947  *   An excitation time on chIdx. The excitation will last exTime+1 excitation clock
948  *   cycles. A valid range is 0-63 (6 bits).
949  *
950  * @param[in] sampleDelay
951  *   Sample delay on chIdx. Sampling will occur after sampleDelay+1 sample clock
952  *   cycles. A valid range is 0-127 (7 bits).
953  *
954  * @param[in] measDelay
955  *   A measure delay on chIdx. Sensor measuring is delayed for measDelay+1
956  *   excitation clock cycles. A valid range is 0-127 (7 bits).
957  ******************************************************************************/
LESENSE_ChannelTimingSet(uint8_t chIdx,uint8_t exTime,uint8_t sampleDelay,uint16_t measDelay)958 void LESENSE_ChannelTimingSet(uint8_t chIdx,
959                               uint8_t exTime,
960                               uint8_t sampleDelay,
961                               uint16_t measDelay)
962 {
963 #if defined(_SILICON_LABS_32B_SERIES_2)
964   bool enabled = false;
965 #endif
966 
967   /* A sanity check of parameters. */
968   EFM_ASSERT(exTime      <= (_LESENSE_CH_TIMING_EXTIME_MASK >> _LESENSE_CH_TIMING_EXTIME_SHIFT));
969   EFM_ASSERT(measDelay   <= (_LESENSE_CH_TIMING_MEASUREDLY_MASK >> _LESENSE_CH_TIMING_MEASUREDLY_SHIFT));
970 #if defined(_SILICON_LABS_32B_SERIES_0)
971   // A sample delay on other devices is 8 bits which fits perfectly in uint8_t.
972   EFM_ASSERT(sampleDelay <= (_LESENSE_CH_TIMING_SAMPLEDLY_MASK >> _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT));
973 #endif
974 
975 #if defined(_SILICON_LABS_32B_SERIES_2)
976   if (LESENSE->EN != 0U) {
977     enabled = true;
978     /* Wait for synchronization before writing to EN register */
979     while (LESENSE->SYNCBUSY) {
980       /* Wait for all synchronizations to finish */
981     }
982     /* Disable LESENSE module */
983     LESENSE->EN_CLR = LESENSE_EN_EN;
984     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
985       /* Wait for disabling to finish */
986     }
987   }
988 #endif
989 
990   /* A channel-specific timing configuration on the scan channel chIdx.
991    * Setting excitation time, sampling delay, and measurement delay. */
992   LESENSE->CH[chIdx].TIMING =
993     ((uint32_t)exTime        << _LESENSE_CH_TIMING_EXTIME_SHIFT)
994     | ((uint32_t)sampleDelay << _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT)
995     | ((uint32_t)measDelay   << _LESENSE_CH_TIMING_MEASUREDLY_SHIFT);
996 
997 #if defined(_SILICON_LABS_32B_SERIES_2)
998   /* Re-Enable LESENSE module if it was enabled in the first place. */
999   if (enabled == true) {
1000     LESENSE->EN_SET = LESENSE_EN_EN;
1001   }
1002 #endif
1003 }
1004 
1005 /***************************************************************************//**
1006  * @brief
1007  *   Set LESENSE channel threshold parameters.
1008  *
1009  * @details
1010  *   Use this function to set threshold parameters on a selected LESENSE
1011  *   channel.
1012  *
1013  * @note
1014  *   Users can configure the channel threshold parameters with the
1015  *   LESENSE_ChannelConfig() function, but only with a significant overhead.
1016  *   This simple function serves controls these parameters
1017  *   after the channel has been configured.
1018  *
1019  * @param[in] chIdx
1020  *   An identifier of the scan channel. A valid range is 0-15.
1021  *
1022  * @param[in] acmpThres
1023  *   ACMP threshold.
1024  *   @li If perCtrl.dacCh0Data or perCtrl.dacCh1Data is set to
1025  *   #lesenseDACIfData, acmpThres defines the 12-bit DAC data in the
1026  *   corresponding data register of the DAC interface (DACn_CH0DATA and
1027  *   DACn_CH1DATA). In this case, the valid range is 0-4095 (12 bits).
1028  *
1029  *   @li If perCtrl.dacCh0Data or perCtrl.dacCh1Data is set to
1030  *   lesenseACMPThres, acmpThres defines the 6-bit Vdd scaling factor of ACMP
1031  *   negative input (VDDLEVEL in ACMP_INPUTSEL register). In this case, the
1032  *   valid range is 0-63 (6 bits).
1033  *
1034  * @param[in] cntThres
1035  *   A decision threshold for counter comparison.
1036  *   A valid range is 0-65535 (16 bits).
1037  ******************************************************************************/
LESENSE_ChannelThresSet(uint8_t chIdx,uint16_t acmpThres,uint16_t cntThres)1038 void LESENSE_ChannelThresSet(uint8_t chIdx,
1039                              uint16_t acmpThres,
1040                              uint16_t cntThres)
1041 {
1042   uint32_t tmp; /* A temporary storage */
1043 #if defined(_SILICON_LABS_32B_SERIES_2)
1044   bool enabled = false;
1045 #endif
1046 
1047   /* A sanity check for acmpThres only, cntThres is a 16 bit value. */
1048   EFM_ASSERT(acmpThres < 4096U);
1049   /* A sanity check for the LESENSE channel ID. */
1050   EFM_ASSERT(chIdx < LESENSE_NUM_CHANNELS);
1051 
1052 #if defined(_SILICON_LABS_32B_SERIES_2)
1053   if (LESENSE->EN != 0U) {
1054     enabled = true;
1055     /* Wait for synchronization before writing to EN register */
1056     while (LESENSE->SYNCBUSY) {
1057       /* Wait for all synchronizations to finish */
1058     }
1059     /* Disable LESENSE module */
1060     LESENSE->EN_CLR = LESENSE_EN_EN;
1061     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1062       /* Wait for disabling to finish */
1063     }
1064   }
1065 #endif
1066 
1067   /* Save the INTERACT register value of channel chIdx to tmp.
1068    * Be aware of the effects of the non-atomic Read-Modify-Write cycle. */
1069   tmp = LESENSE->CH[chIdx].INTERACT & ~(0xFFF);
1070   /* Set the ACMP threshold value to the INTERACT register of the channel chIdx. */
1071   tmp |= (uint32_t)acmpThres;
1072   /* Write the new value to the INTERACT register. */
1073   LESENSE->CH[chIdx].INTERACT = tmp;
1074 
1075 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1076   /* Save the EVAL register value of channel chIdx to tmp.
1077    * Be aware of the effects of the non-atomic Read-Modify-Write cycle. */
1078   tmp = LESENSE->CH[chIdx].EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK);
1079   /* Set the counter threshold value to the INTERACT register of the channel chIdx. */
1080   tmp |= (uint32_t)cntThres << _LESENSE_CH_EVAL_COMPTHRES_SHIFT;
1081   /* Write the new value to the EVAL register. */
1082   LESENSE->CH[chIdx].EVAL = tmp;
1083 #else
1084 
1085   LESENSE->EN_SET = LESENSE_EN_EN;
1086 
1087   LESENSE->CH[chIdx].EVALTHRES = (uint32_t)cntThres << _LESENSE_CH_EVALTHRES_EVALTHRES_SHIFT;
1088 
1089   while (LESENSE->SYNCBUSY) {
1090     /* Wait for all synchronizations to finish */
1091   }
1092   if (!enabled) {
1093     /* Disable LESENSE module */
1094     LESENSE->EN_CLR = LESENSE_EN_EN;
1095     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1096       /* Wait for disabling to finish */
1097     }
1098   }
1099 
1100 #endif
1101 }
1102 
1103 #if defined(_LESENSE_CH_EVAL_MODE_MASK) || defined(_SILICON_LABS_32B_SERIES_2)
1104 /***************************************************************************//**
1105  * @brief
1106  *   Configure a Sliding Window evaluation mode for a specific channel.
1107  *
1108  * @details
1109  *   This function will configure the evaluation mode, the initial
1110  *   sensor measurement (COMPTHRES), and the window size. For other channel-related
1111  *   configuration, see the @ref LESENSE_ChannelConfig() function.
1112  *
1113  * @warning
1114  *   Note that the step size and window size configuration are global to all
1115  *   LESENSE channels and use the same register field in the hardware. This
1116  *   means that any windowSize configuration passed to this function will
1117  *   apply for all channels and override all other stepSize/windowSize
1118  *   configurations.
1119  *
1120  * @param[in] chIdx
1121  *   An identifier of the scan channel. A valid range is 0-15.
1122  *
1123  * @param[in] windowSize
1124  *   A window size to be used on all channels.
1125  *
1126  * @param[in] initValue
1127  *   The initial sensor value for the channel.
1128  ******************************************************************************/
LESENSE_ChannelSlidingWindow(uint8_t chIdx,uint32_t windowSize,uint32_t initValue)1129 void LESENSE_ChannelSlidingWindow(uint8_t chIdx,
1130                                   uint32_t windowSize,
1131                                   uint32_t initValue)
1132 {
1133   LESENSE_CH_TypeDef * ch = &LESENSE->CH[chIdx];
1134 #if defined(_SILICON_LABS_32B_SERIES_2)
1135   bool enabled = false;
1136 #endif
1137 
1138   LESENSE_WindowSizeSet(windowSize);
1139 
1140 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1141   ch->EVAL = (ch->EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK | _LESENSE_CH_EVAL_MODE_MASK))
1142              | (initValue << _LESENSE_CH_EVAL_COMPTHRES_SHIFT)
1143              | LESENSE_CH_EVAL_MODE_SLIDINGWIN;
1144 #else
1145 
1146   if (LESENSE->EN != 0U) {
1147     enabled = true;
1148     /* Wait for synchronization before writing to EN register */
1149     while (LESENSE->SYNCBUSY) {
1150       /* Wait for all synchronizations to finish */
1151     }
1152     /* Disable LESENSE module */
1153     LESENSE->EN_CLR = LESENSE_EN_EN;
1154     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1155       /* Wait for disabling to finish */
1156     }
1157   }
1158 
1159   /* Set Channel Sliding Window config */
1160   ch->EVALCFG = (ch->EVALCFG & ~_LESENSE_CH_EVALCFG_MODE_MASK)
1161                 | LESENSE_CH_EVALCFG_MODE_SLIDINGWIN;
1162 
1163   LESENSE->EN_SET = LESENSE_EN_EN;
1164   ch->EVALTHRES = (ch->EVALTHRES & ~_LESENSE_CH_EVALTHRES_EVALTHRES_MASK)
1165                   | (initValue << _LESENSE_CH_EVALTHRES_EVALTHRES_SHIFT);
1166   while (LESENSE->SYNCBUSY) {
1167     /* Wait for all synchronizations to finish */
1168   }
1169   if (!enabled) {
1170     /* Disable LESENSE module */
1171     LESENSE->EN_CLR = LESENSE_EN_EN;
1172     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1173       /* Wait for disabling to finish */
1174     }
1175   }
1176 #endif
1177 }
1178 
1179 /***************************************************************************//**
1180  * @brief
1181  *   Configure the step detection evaluation mode for a specific channel.
1182  *
1183  * @details
1184  *   This function will configure the evaluation mode, the initial
1185  *   sensor measurement (COMPTHRES) and the window size. For other channel-related
1186  *   configuration, see the @ref LESENSE_ChannelConfig() function.
1187  *
1188  * @warning
1189  *   Note that the step size and window size configuration are global to all
1190  *   LESENSE channels and use the same register field in the hardware. This
1191  *   means that any stepSize configuration passed to this function will
1192  *   apply for all channels and override all other stepSize/windowSize
1193  *   configurations.
1194  *
1195  * @param[in] chIdx
1196  *   An identifier of the scan channel. A valid range is 0-15.
1197  *
1198  * @param[in] stepSize
1199  *   A step size to be used on all channels.
1200  *
1201  * @param[in] initValue
1202  *   The initial sensor value for the channel.
1203  ******************************************************************************/
LESENSE_ChannelStepDetection(uint8_t chIdx,uint32_t stepSize,uint32_t initValue)1204 void LESENSE_ChannelStepDetection(uint8_t chIdx,
1205                                   uint32_t stepSize,
1206                                   uint32_t initValue)
1207 {
1208   LESENSE_CH_TypeDef * ch = &LESENSE->CH[chIdx];
1209 #if defined(_SILICON_LABS_32B_SERIES_2)
1210   bool enabled = false;
1211 #endif
1212 
1213   LESENSE_StepSizeSet(stepSize);
1214 
1215 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1216   ch->EVAL = (ch->EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK | _LESENSE_CH_EVAL_MODE_MASK))
1217              | (initValue << _LESENSE_CH_EVAL_COMPTHRES_SHIFT)
1218              | LESENSE_CH_EVAL_MODE_STEPDET;
1219 #else
1220   if (LESENSE->EN != 0U) {
1221     enabled = true;
1222     /* Wait for synchronization before writing to EN register */
1223     while (LESENSE->SYNCBUSY) {
1224       /* Wait for all synchronizations to finish */
1225     }
1226     /* Disable LESENSE module */
1227     LESENSE->EN_CLR = LESENSE_EN_EN;
1228     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1229       /* Wait for disabling to finish */
1230     }
1231   }
1232 
1233   ch->EVALCFG = (ch->EVALCFG & ~_LESENSE_CH_EVALCFG_MODE_MASK)
1234                 | LESENSE_CH_EVALCFG_MODE_STEPDET;
1235 
1236   LESENSE->EN_SET = LESENSE_EN_EN;
1237   ch->EVALTHRES = (ch->EVALTHRES & ~_LESENSE_CH_EVALTHRES_EVALTHRES_MASK)
1238                   | (initValue << _LESENSE_CH_EVALTHRES_EVALTHRES_SHIFT);
1239   while (LESENSE->SYNCBUSY) {
1240     /* Wait for all synchronizations to finish */
1241   }
1242   if (!enabled) {
1243     /* Disable LESENSE module */
1244     LESENSE->EN_CLR = LESENSE_EN_EN;
1245     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1246       /* Wait for disabling to finish */
1247     }
1248   }
1249 #endif
1250 }
1251 
1252 /***************************************************************************//**
1253  * @brief
1254  *   Set the window size for all LESENSE channels.
1255  *
1256  * @details
1257  *   The window size is used by all channels that are configured as
1258  *   @ref lesenseEvalModeSlidingWindow.
1259  *
1260  * @warning
1261  *   The window size configuration is using the same register field as the
1262  *   step detection size. As a result, the window size configuration will have an
1263  *   effect on channels configured with the @ref lesenseEvalModeStepDetection
1264  *   evaluation mode as well.
1265  *
1266  * @param[in] windowSize
1267  *   The window size to use for all channels.
1268  ******************************************************************************/
LESENSE_WindowSizeSet(uint32_t windowSize)1269 void LESENSE_WindowSizeSet(uint32_t windowSize)
1270 {
1271 #if defined(_SILICON_LABS_32B_SERIES_2)
1272   bool enabled = false;
1273 
1274   if (LESENSE->EN != 0U) {
1275     enabled = true;
1276     /* Wait for synchronization before writing to EN register */
1277     while (LESENSE->SYNCBUSY) {
1278       /* Wait for all synchronizations to finish */
1279     }
1280     /* Disable LESENSE module */
1281     LESENSE->EN_CLR = LESENSE_EN_EN;
1282     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1283       /* Wait for disabling to finish */
1284     }
1285   }
1286 #endif
1287 
1288   LESENSE->EVALCTRL = (LESENSE->EVALCTRL & ~_LESENSE_EVALCTRL_WINSIZE_MASK)
1289                       | windowSize;
1290 
1291 #if defined(_SILICON_LABS_32B_SERIES_2)
1292   /* Re-Enable LESENSE module if it was enabled in the first place. */
1293   if (enabled == true) {
1294     LESENSE->EN_SET = LESENSE_EN_EN;
1295   }
1296 #endif
1297 }
1298 
1299 /***************************************************************************//**
1300  * @brief
1301  *   Set the step size for all LESENSE channels.
1302  *
1303  * @details
1304  *   The step size is configured using the same register field as used to
1305  *   configure window size. Therefore, calling this function will overwrite any
1306  *   previously configured window size as done by the
1307  *   @ref LESENSE_WindowSizeSet() function.
1308  *
1309  * @param[in] stepSize
1310  *   The step size to use for all channels.
1311  ******************************************************************************/
LESENSE_StepSizeSet(uint32_t stepSize)1312 void LESENSE_StepSizeSet(uint32_t stepSize)
1313 {
1314   LESENSE_WindowSizeSet(stepSize);
1315 }
1316 #endif
1317 
1318 /***************************************************************************//**
1319  * @brief
1320  *   Configure all LESENSE decoder states.
1321  *
1322  * @details
1323  *   This function configures all the decoder states of the LESENSE interface.
1324  *   See the configuration parameter type definition
1325  *   (LESENSE_DecStAll_TypeDef) for more details.
1326  *
1327  * @note
1328  *   Decoder states can be configured individually using
1329  *   LESENSE_DecoderStateConfig() function.
1330  *
1331  * @param[in] confDecStAll
1332  *   A configuration structure for all (16 or 32) LESENSE decoder states.
1333  ******************************************************************************/
LESENSE_DecoderStateAllConfig(const LESENSE_DecStAll_TypeDef * confDecStAll)1334 void LESENSE_DecoderStateAllConfig(const LESENSE_DecStAll_TypeDef * confDecStAll)
1335 {
1336   uint32_t i;
1337 
1338   /* Iterate through all 16 or 32 decoder states. */
1339   for (i = 0U; i < LESENSE_NUM_DECODER_STATES; ++i) {
1340     /* A configure decoder state i. */
1341     LESENSE_DecoderStateConfig(&confDecStAll->St[i], i);
1342   }
1343 }
1344 
1345 /***************************************************************************//**
1346  * @brief
1347  *   Configure a single LESENSE decoder state.
1348  *
1349  * @details
1350  *   This function configures a single decoder state of the LESENSE interface.
1351  *   See the configuration parameter type definition
1352  *   (LESENSE_DecStDesc_TypeDef) for more details.
1353  *
1354  * @param[in] confDecSt
1355  *   A configuration structure for a single LESENSE decoder state.
1356  *
1357  * @param[in] decSt
1358  *   A decoder state index to configure (0-15) or (0-31) depending on the device.
1359  ******************************************************************************/
LESENSE_DecoderStateConfig(const LESENSE_DecStDesc_TypeDef * confDecSt,uint32_t decSt)1360 void LESENSE_DecoderStateConfig(const LESENSE_DecStDesc_TypeDef * confDecSt,
1361                                 uint32_t decSt)
1362 {
1363 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1364   /* Sanity check of configuration parameters */
1365   EFM_ASSERT(decSt < LESENSE_NUM_DECODER_STATES);
1366   EFM_ASSERT((uint32_t)confDecSt->confA.compMask < 16U);
1367   EFM_ASSERT((uint32_t)confDecSt->confA.compVal < 16U);
1368   EFM_ASSERT((uint32_t)confDecSt->confA.nextState < LESENSE_NUM_DECODER_STATES);
1369   EFM_ASSERT((uint32_t)confDecSt->confB.compMask < 16U);
1370   EFM_ASSERT((uint32_t)confDecSt->confB.compVal < 16U);
1371   EFM_ASSERT((uint32_t)confDecSt->confB.nextState < LESENSE_NUM_DECODER_STATES);
1372 
1373   /* Configure the state descriptor A (LESENSE_STi_TCONFA) for the decoder state i.
1374    * Setting sensor compare value, sensor mask, next state index,
1375    * transition action, interrupt flag option, and state descriptor chaining
1376    * configurations. */
1377   LESENSE->ST[decSt].TCONFA =
1378     (uint32_t)confDecSt->confA.prsAct
1379     | ((uint32_t)confDecSt->confA.compMask  << _LESENSE_ST_TCONFA_MASK_SHIFT)
1380     | ((uint32_t)confDecSt->confA.compVal   << _LESENSE_ST_TCONFA_COMP_SHIFT)
1381     | ((uint32_t)confDecSt->confA.nextState << _LESENSE_ST_TCONFA_NEXTSTATE_SHIFT)
1382     | ((uint32_t)confDecSt->confA.setInt    << _LESENSE_ST_TCONFA_SETIF_SHIFT)
1383     | ((uint32_t)confDecSt->chainDesc       << _LESENSE_ST_TCONFA_CHAIN_SHIFT);
1384 
1385   /* Configure the state descriptor Bi (LESENSE_STi_TCONFB).
1386    * Setting sensor compare value, sensor mask, next state index, transition
1387    * action, and interrupt flag option configurations. */
1388   LESENSE->ST[decSt].TCONFB =
1389     (uint32_t)confDecSt->confB.prsAct
1390     | ((uint32_t)confDecSt->confB.compMask  << _LESENSE_ST_TCONFB_MASK_SHIFT)
1391     | ((uint32_t)confDecSt->confB.compVal   << _LESENSE_ST_TCONFB_COMP_SHIFT)
1392     | ((uint32_t)confDecSt->confB.nextState << _LESENSE_ST_TCONFB_NEXTSTATE_SHIFT)
1393     | ((uint32_t)confDecSt->confB.setInt    << _LESENSE_ST_TCONFB_SETIF_SHIFT);
1394 #else
1395   bool enabled = false;
1396 
1397   /* Sanity check of configuration parameters */
1398   EFM_ASSERT(decSt < LESENSE_NUM_DECODER_STATES);
1399   EFM_ASSERT((uint32_t)confDecSt->compMask < 16U);
1400   EFM_ASSERT((uint32_t)confDecSt->compVal < 16U);
1401   EFM_ASSERT((uint32_t)confDecSt->curState < LESENSE_NUM_DECODER_STATES);
1402   EFM_ASSERT((uint32_t)confDecSt->nextState < LESENSE_NUM_DECODER_STATES);
1403 
1404   if (LESENSE->EN != 0U) {
1405     enabled = true;
1406     /* Wait for synchronization before writing to EN register */
1407     while (LESENSE->SYNCBUSY) {
1408       /* Wait for all synchronizations to finish */
1409     }
1410     /* Disable LESENSE module */
1411     LESENSE->EN_CLR = LESENSE_EN_EN;
1412     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1413       /* Wait for disabling to finish */
1414     }
1415   }
1416 
1417   LESENSE->ST[decSt].ARC =  (uint32_t)confDecSt->prsAct
1418                            | ((uint32_t)confDecSt->compMask  << _LESENSE_ST_ARC_SMASK_SHIFT)
1419                            | ((uint32_t)confDecSt->compVal   << _LESENSE_ST_ARC_SCOMP_SHIFT)
1420                            | ((uint32_t)confDecSt->curState  << _LESENSE_ST_ARC_CURSTATE_SHIFT)
1421                            | ((uint32_t)confDecSt->nextState << _LESENSE_ST_ARC_NEXTSTATE_SHIFT)
1422                            | ((uint32_t)confDecSt->setInt    << _LESENSE_ST_ARC_SETIF_SHIFT);
1423 
1424   /* Re-Enable LESENSE module if it was enabled in the first place. */
1425   if (enabled == true) {
1426     LESENSE->EN_SET = LESENSE_EN_EN;
1427   }
1428 #endif
1429 }
1430 
1431 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1432 /***************************************************************************//**
1433  * @brief
1434  *   Set the LESENSE decoder state.
1435  *
1436  * @details
1437  *   This function can be used for setting the initial state of the LESENSE
1438  *   decoder.
1439  *
1440  * @note
1441  *   Make sure the LESENSE decoder state is initialized by this function before
1442  *   enabling the decoder!
1443  *
1444  * @param[in] decSt
1445  *   A decoder state to set as the current state. A valid range is 0-15 or 0-31,
1446  *   depending on the device.
1447  ******************************************************************************/
LESENSE_DecoderStateSet(uint32_t decSt)1448 void LESENSE_DecoderStateSet(uint32_t decSt)
1449 {
1450   EFM_ASSERT(decSt <= _LESENSE_DECSTATE_DECSTATE_MASK);
1451 
1452   LESENSE->DECSTATE = decSt & _LESENSE_DECSTATE_DECSTATE_MASK;
1453 }
1454 #endif
1455 
1456 /***************************************************************************//**
1457  * @brief
1458  *   Get the current state of the LESENSE decoder.
1459  *
1460  * @return
1461  *   This function returns the value of the LESENSE_DECSTATE register that
1462  *   represents the current state of the LESENSE decoder.
1463  ******************************************************************************/
LESENSE_DecoderStateGet(void)1464 uint32_t LESENSE_DecoderStateGet(void)
1465 {
1466   return LESENSE->DECSTATE & _LESENSE_DECSTATE_DECSTATE_MASK;
1467 }
1468 
1469 #if defined(_LESENSE_PRSCTRL_MASK)
1470 /***************************************************************************//**
1471  * @brief
1472  *   Enable or disable the PRS output from the LESENSE decoder.
1473  *
1474  * @param[in] enable
1475  *   Enable/disable the PRS output from the LESENSE decoder. True to enable and
1476  *   false to disable.
1477  *
1478  * @param[in] decMask
1479  *   A decoder state compare value mask.
1480  *
1481  * @param[in] decVal
1482  *   A decoder state comparison value.
1483  ******************************************************************************/
LESENSE_DecoderPrsOut(bool enable,uint32_t decMask,uint32_t decVal)1484 void LESENSE_DecoderPrsOut(bool enable, uint32_t decMask, uint32_t decVal)
1485 {
1486   LESENSE->PRSCTRL = (enable << _LESENSE_PRSCTRL_DECCMPEN_SHIFT)
1487                      | (decMask << _LESENSE_PRSCTRL_DECCMPMASK_SHIFT)
1488                      | (decVal << _LESENSE_PRSCTRL_DECCMPVAL_SHIFT);
1489 }
1490 #endif
1491 
1492 /***************************************************************************//**
1493  * @brief
1494  *   Start scanning sensors.
1495  *
1496  * @note
1497  *   This function will wait for any pending previous write operation to the
1498  *   CMD register to complete before accessing the CMD register. It will also
1499  *   wait for the write operation to the CMD register to complete before
1500  *   returning. Each write operation to the CMD register may take up to 3 LF
1501  *   clock cycles, so expect some delay. The user may implement
1502  *   a separate function to write multiple command bits in the CMD register
1503  *   in one single operation to optimize an application.
1504  ******************************************************************************/
LESENSE_ScanStart(void)1505 void LESENSE_ScanStart(void)
1506 {
1507   /* Wait for any pending previous write operation to the CMD register to
1508      complete before accessing the CMD register. */
1509   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1510     ;
1511 
1512   /* Start scanning sensors. */
1513   LESENSE->CMD = LESENSE_CMD_START;
1514 
1515   /* Wait for the write operation to the CMD register to complete before
1516      returning. */
1517   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1518     ;
1519 }
1520 
1521 /***************************************************************************//**
1522  * @brief
1523  *   Stop scanning sensors.
1524  *
1525  * @note
1526  *   This function will wait for any pending previous write operation to the
1527  *   CMD register to complete before accessing the CMD register. It will also
1528  *   wait for the write operation to the CMD register to complete before
1529  *   returning. Each write operation to the CMD register may take up to 3 LF
1530  *   clock cycles, so the user should expect some delay. The user may implement
1531  *   a separate function to write multiple command bits in the CMD register
1532  *   in one single operation in order to optimize an application.
1533  *
1534  * @note
1535  *   If issued during a scan, the command takes effect after scan completion.
1536  ******************************************************************************/
LESENSE_ScanStop(void)1537 void LESENSE_ScanStop(void)
1538 {
1539   /* Wait for any pending previous write operation to the CMD register to
1540      complete before accessing the CMD register. */
1541   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1542     ;
1543 
1544   /* Stop scanning sensors. */
1545   LESENSE->CMD = LESENSE_CMD_STOP;
1546 
1547   /* Wait for the write operation to the CMD register to complete before
1548      returning. */
1549   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1550     ;
1551 }
1552 
1553 /***************************************************************************//**
1554  * @brief
1555  *   Start the LESENSE decoder.
1556  *
1557  * @note
1558  *   This function will wait for any pending previous write operation to the
1559  *   CMD register to complete before accessing the CMD register. It will also
1560  *   wait for the write operation to the CMD register to complete before
1561  *   returning. Each write operation to the CMD register may take up to 3 LF
1562  *   clock cycles, so expect some delay. The user may implement
1563  *   a separate function to write multiple command bits in the CMD register
1564  *   in one single operation to optimize an application.
1565  ******************************************************************************/
LESENSE_DecoderStart(void)1566 void LESENSE_DecoderStart(void)
1567 {
1568   /* Wait for any pending previous write operation to the CMD register to
1569      complete before accessing the CMD register. */
1570   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1571     ;
1572 
1573   /* Start the decoder. */
1574   LESENSE->CMD = LESENSE_CMD_DECODE;
1575 
1576   /* Wait for the write operation to the CMD register to complete before
1577      returning. */
1578   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1579     ;
1580 }
1581 
1582 /***************************************************************************//**
1583  * @brief
1584  *   Clear the result buffer.
1585  *
1586  * @note
1587  *   This function will wait for any pending previous write operation to the
1588  *   CMD register to complete before accessing the CMD register. It will also
1589  *   wait for the write operation to the CMD register to complete before
1590  *   returning. Each write operation to the CMD register may take up to 3 LF
1591  *   clock cycles, so expect some delay. The user may implement
1592  *   a separate function to write multiple command bits in the CMD register
1593  *   in one single operation to optimize an application.
1594  ******************************************************************************/
LESENSE_ResultBufferClear(void)1595 void LESENSE_ResultBufferClear(void)
1596 {
1597   /* Wait for any pending previous write operation to the CMD register to
1598      complete before accessing the CMD register. */
1599   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1600     ;
1601 
1602   LESENSE->CMD = LESENSE_CMD_CLEARBUF;
1603 
1604   /* Wait for the write operation to the CMD register to complete before
1605      returning. */
1606   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1607     ;
1608 
1609 #if defined(_SILICON_LABS_32B_SERIES_2)
1610   while (LESENSE->STATUS & _LESENSE_STATUS_FLUSHING_MASK)
1611     ;
1612 #endif
1613 }
1614 
1615 /***************************************************************************//**
1616  * @brief
1617  *   Reset the LESENSE module.
1618  *
1619  * @details
1620  *   Use this function to reset LESENSE registers.
1621  *
1622  * @note
1623  *   Resetting LESENSE registers is required in each reset or power-on cycle
1624  *   to configure the default values of the RAM mapped LESENSE registers.
1625  *   LESENSE_Reset() can be called on initialization by setting the @p reqReset
1626  *   parameter to true in LESENSE_Init().
1627  *   Starting from Series 2 Config 3 (xG23 and higher), this function leaves
1628  *   LESENSE in the disabled state.
1629  ******************************************************************************/
LESENSE_Reset(void)1630 void LESENSE_Reset(void)
1631 {
1632 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1633   uint32_t i;
1634 
1635   /* Disable all LESENSE interrupts first. */
1636   LESENSE->IEN = _LESENSE_IEN_RESETVALUE;
1637 
1638   /* Clear all pending LESENSE interrupts. */
1639   LESENSE->IFC = _LESENSE_IFC_MASK;
1640 
1641   /* Stop the decoder. */
1642   LESENSE->DECCTRL |= LESENSE_DECCTRL_DISABLE;
1643 
1644   /* Wait for any pending previous write operation to the CMD register to
1645      complete before accessing the CMD register. */
1646   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
1647     ;
1648 
1649   /* Stop the sensor scan and clear the result buffer. */
1650   LESENSE->CMD = (LESENSE_CMD_STOP | LESENSE_CMD_CLEARBUF);
1651 
1652   /* Reset LESENSE configuration registers */
1653   LESENSE->CTRL      = _LESENSE_CTRL_RESETVALUE;
1654 
1655   LESENSE->PERCTRL   = _LESENSE_PERCTRL_RESETVALUE;
1656   LESENSE->DECCTRL   = _LESENSE_DECCTRL_RESETVALUE;
1657   LESENSE->BIASCTRL  = _LESENSE_BIASCTRL_RESETVALUE;
1658 
1659 #if defined(_LESENSE_EVALCTRL_MASK)
1660   LESENSE->EVALCTRL  = _LESENSE_EVALCTRL_RESETVALUE;
1661   LESENSE->PRSCTRL   = _LESENSE_PRSCTRL_RESETVALUE;
1662 #endif
1663 
1664   LESENSE->CHEN      = _LESENSE_CHEN_RESETVALUE;
1665   LESENSE->IDLECONF  = _LESENSE_IDLECONF_RESETVALUE;
1666   LESENSE->ALTEXCONF = _LESENSE_ALTEXCONF_RESETVALUE;
1667 
1668   /* Reset SENSORSTATE register */
1669   LESENSE->SENSORSTATE = _LESENSE_SENSORSTATE_RESETVALUE;
1670 
1671   /* Disable LESENSE to control GPIO pins. */
1672 #if defined(_LESENSE_ROUTE_MASK)
1673   LESENSE->ROUTE    = _LESENSE_ROUTE_RESETVALUE;
1674 #else
1675   LESENSE->ROUTEPEN = _LESENSE_ROUTEPEN_RESETVALUE;
1676 #endif
1677 
1678   /* Reset all channel configuration registers. */
1679   for (i = 0U; i < LESENSE_NUM_CHANNELS; ++i) {
1680     LESENSE->CH[i].TIMING   = _LESENSE_CH_TIMING_RESETVALUE;
1681     LESENSE->CH[i].INTERACT = _LESENSE_CH_INTERACT_RESETVALUE;
1682     LESENSE->CH[i].EVAL     = _LESENSE_CH_EVAL_RESETVALUE;
1683   }
1684 
1685   /* Reset all decoder state configuration registers. */
1686   for (i = 0U; i < LESENSE_NUM_DECODER_STATES; ++i) {
1687     LESENSE->ST[i].TCONFA = _LESENSE_ST_TCONFA_RESETVALUE;
1688     LESENSE->ST[i].TCONFB = _LESENSE_ST_TCONFB_RESETVALUE;
1689   }
1690   /* Wait for the write operation to complete before
1691      returning. */
1692   while (LESENSE->SYNCBUSY & LESENSE_SYNCBUSY_CMD)
1693     ;
1694 #else
1695   LESENSE->SWRST_SET = LESENSE_SWRST_SWRST;
1696   while (LESENSE->SWRST & _LESENSE_SWRST_RESETTING_MASK) ;
1697 #endif
1698 }
1699 
1700 /** @} (end addtogroup lesense) */
1701 
1702 #endif /* defined(LESENSE_COUNT) && (LESENSE_COUNT > 0) */
1703