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 "sl_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 calcScanFreq;   /* Variable for testing the calculation algorithm. */
297 #if defined(_SILICON_LABS_32B_SERIES_2)
298   bool enabled = false;
299 #endif
300 
301 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)
302   uint32_t pcTop   = 255UL; /* Period counter top value (max. 255). */
303 #else
304   uint32_t pcTop   = 63UL; /* Period counter top value (max. 63). */
305 #endif
306 
307 #if defined(_SILICON_LABS_32B_SERIES_2)
308   if (LESENSE->EN != 0U) {
309     enabled = true;
310     /* Wait for synchronization before writing to EN register */
311     while (LESENSE->SYNCBUSY) {
312       /* Wait for all synchronizations to finish */
313     }
314     /* Disable LESENSE module */
315     LESENSE->EN_CLR = LESENSE_EN_EN;
316     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
317       /* Wait for disabling to finish */
318     }
319   }
320 #endif
321 
322   /* If refFreq is set to 0, the currently-configured reference clock is
323    * assumed. */
324   if (!refFreq) {
325 #if defined(_SILICON_LABS_32B_SERIES_1) \
326     || defined(_SILICON_LABS_32B_SERIES_0)
327     refFreq = CMU_ClockFreqGet(cmuClock_LESENSE);
328 #elif defined(_SILICON_LABS_32B_SERIES_2)
329     refFreq = CMU_ClockFreqGet(cmuClock_LESENSECLK);
330 #endif
331   }
332 
333   /* The maximum value of pcPresc is 128. AS a result, using the reference frequency less than
334    * 33554431 Hz (33.554431 MHz), the frequency calculation in the while loop
335    * below will not overflow. */
336   EFM_ASSERT(refFreq < ((uint32_t)UINT32_MAX / 128UL));
337 
338   /* A sanity check of scan frequency value. */
339   EFM_ASSERT((scanFreq > 0U) && (scanFreq <= refFreq));
340 
341   /* Calculate the minimum necessary prescaler value to provide the
342    * biggest possible resolution for setting the scan frequency.
343    * The maximum number of calculation cycles is 7 (value of lesenseClkDiv_128). */
344   while ((refFreq / ((uint32_t)scanFreq * clkDiv) > (pcTop + 1UL))
345          && (pcPresc < lesenseClkDiv_128)) {
346     ++pcPresc;
347     clkDiv = (uint32_t)1UL << pcPresc;
348   }
349 
350   /* Calculate the pcTop value. */
351   pcTop = ((uint32_t)refFreq / ((uint32_t)scanFreq * clkDiv)) - 1UL;
352   EFM_ASSERT(pcTop <= (_LESENSE_TIMCTRL_PCTOP_MASK >> _LESENSE_TIMCTRL_PCTOP_SHIFT));
353 
354   /* Clear current PCPRESC and PCTOP settings. Be aware of the effect of
355    * non-atomic Read-Modify-Write on LESENSE->TIMCRTL. */
356   tmp = LESENSE->TIMCTRL & (~_LESENSE_TIMCTRL_PCPRESC_MASK
357                             & ~_LESENSE_TIMCTRL_PCTOP_MASK);
358 
359   /* Set new values in tmp while reserving other settings. */
360   tmp |= ((uint32_t)pcPresc << _LESENSE_TIMCTRL_PCPRESC_SHIFT)
361          | ((uint32_t)pcTop << _LESENSE_TIMCTRL_PCTOP_SHIFT);
362 
363   /* Set values in the LESENSE_TIMCTRL register. */
364   LESENSE->TIMCTRL = tmp;
365 
366   /* For testing the calculation algorithm. */
367   calcScanFreq = ((uint32_t)refFreq / ((uint32_t)(1UL + pcTop) * clkDiv));
368 
369 #if defined(_SILICON_LABS_32B_SERIES_2)
370   /* Re-Enable LESENSE module if it was enabled in the first place. */
371   if (enabled == true) {
372     LESENSE->EN_SET = LESENSE_EN_EN;
373   }
374 #endif
375 
376   return calcScanFreq;
377 }
378 
379 /***************************************************************************//**
380  * @brief
381  *   Set scan mode of the LESENSE channels.
382  *
383  * @details
384  *   This function configures how the scan start is triggered. It can be
385  *   used for re-configuring the scan mode while running the application but it
386  *   is also used by LESENSE_Init() for initialization.
387  *
388  * @note
389  *   Users can configure the scan mode by LESENSE_Init() function, but only with
390  *   a significant overhead. This simple function serves the purpose of
391  *   controlling this parameter after the channel has been configured.
392  *   Be aware of the effects of the non-atomic Read-Modify-Write cycle.
393  *
394  * @param[in] scanMode
395  *   Select the location to map LESENSE alternate excitation channels.
396  *   @li lesenseScanStartPeriodic - A new scan is started each time the period
397  *                                  counter overflows.
398  *   @li lesenseScanStartOneShot - A single scan is performed when
399  *                                 LESENSE_ScanStart() is called.
400  *   @li lesenseScanStartPRS - A new scan is triggered by pulse on the PRS channel.
401  *
402  * @param[in] start
403  *   If true, LESENSE_ScanStart() is immediately issued after configuration.
404  ******************************************************************************/
LESENSE_ScanModeSet(LESENSE_ScanMode_TypeDef scanMode,bool start)405 void LESENSE_ScanModeSet(LESENSE_ScanMode_TypeDef scanMode,
406                          bool start)
407 {
408   uint32_t tmp; /* temporary storage of the CTRL register value */
409 #if defined(_SILICON_LABS_32B_SERIES_2)
410   bool enabled = false;
411 #endif
412 
413 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
414   /* Save the CTRL register value to tmp.
415    * Be aware of the effects of the non-atomic Read-Modify-Write cycle. */
416   tmp = LESENSE->CTRL & ~(_LESENSE_CTRL_SCANMODE_MASK);
417   /* Setting the requested scanMode to the CTRL register. Casting signed int
418    * (enumeration) to unsigned long (uint32_t). */
419   tmp |= (uint32_t)scanMode;
420 
421   /* Write the new value to the CTRL register. */
422   LESENSE->CTRL = tmp;
423 #else
424   if (LESENSE->EN != 0U) {
425     enabled = true;
426     /* Wait for synchronization before writing to EN register */
427     while (LESENSE->SYNCBUSY) {
428       /* Wait for all synchronizations to finish */
429     }
430 
431     /* Disable LESENSE module */
432     LESENSE->EN_CLR = LESENSE_EN_EN;
433     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
434       /* Wait for disabling to finish */
435     }
436   }
437 
438   /* Save the CTRL register value to tmp.
439    * Be aware of the effects of the non-atomic Read-Modify-Write cycle. */
440   tmp = LESENSE->CFG & ~(_LESENSE_CFG_SCANMODE_MASK);
441   /* Setting the requested scanMode to the CTRL register. Casting signed int
442    * (enumeration) to unsigned long (uint32_t). */
443   tmp |= (uint32_t)scanMode;
444   /* Write the new value to the CTRL register. */
445   LESENSE->CFG = tmp;
446 
447   /* Re-Enable LESENSE module if it was enabled in the first place. */
448   if (enabled || start) {
449     LESENSE->EN_SET = LESENSE_EN_EN;
450   }
451 #endif
452 
453   /* Start the sensor scanning if requested. */
454   if (start) {
455     LESENSE_ScanStart();
456   }
457 }
458 
459 /***************************************************************************//**
460  * @brief
461  *   Set the start delay of the sensor interaction on each channel.
462  *
463  * @details
464  *   This function sets the start delay of the sensor interaction on each channel.
465  *   It can be used for adjusting the start delay while running the application
466  *   but it is also used by LESENSE_Init() for initialization.
467  *
468  * @note
469  *   Users can configure the start delay by LESENSE_Init() function, but only
470  *   with a significant overhead. This simple function serves the purpose of
471  *   controlling this parameter after the channel has been configured.
472  *   Be aware of the effects of the non-atomic Read-Modify-Write cycle.
473  *
474  * @param[in] startDelay
475  *   A number of LFACLK cycles to delay. A valid range: 0-3 (2 bit).
476  ******************************************************************************/
LESENSE_StartDelaySet(uint8_t startDelay)477 void LESENSE_StartDelaySet(uint8_t startDelay)
478 {
479   uint32_t tmp; /* Temporary storage of the TIMCTRL register value */
480 #if defined(_SILICON_LABS_32B_SERIES_2)
481   bool enabled = false;
482 #endif
483 
484   /* Sanity check of the startDelay. */
485   EFM_ASSERT(startDelay < 4U);
486 
487 #if defined(_SILICON_LABS_32B_SERIES_2)
488   if (LESENSE->EN != 0U) {
489     enabled = true;
490     /* Wait for synchronization before writing to EN register */
491     while (LESENSE->SYNCBUSY) {
492       /* Wait for all synchronizations to finish */
493     }
494     /* Disable LESENSE module */
495     LESENSE->EN_CLR = LESENSE_EN_EN;
496     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
497       /* Wait for disabling to finish */
498     }
499   }
500 #endif
501 
502   /* Save the TIMCTRL register value to tmp.
503    * Be aware of the effects of the non-atomic Read-Modify-Write cycle. */
504   tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_STARTDLY_MASK);
505   /* Setting the requested startDelay to the TIMCTRL register. */
506   tmp |= (uint32_t)startDelay << _LESENSE_TIMCTRL_STARTDLY_SHIFT;
507 
508   /* Write the new value to the TIMCTRL register. */
509   LESENSE->TIMCTRL = tmp;
510 
511 #if defined(_SILICON_LABS_32B_SERIES_2)
512   /* Re-Enable LESENSE module if it was enabled in the first place. */
513   if (enabled == true) {
514     LESENSE->EN_SET = LESENSE_EN_EN;
515   }
516 #endif
517 }
518 
519 /***************************************************************************//**
520  * @brief
521  *   Set the clock division for LESENSE timers.
522  *
523  * @details
524  *   Use this function to configure the clock division for the LESENSE timers
525  *   used for excitation timing.
526  *   The division setting is global but the clock source can be selected for
527  *   each channel using LESENSE_ChannelConfig() function. See
528  *   documentation for more details.
529  *
530  * @note
531  *   If AUXHFRCO is used for excitation timing, LFACLK can't exceed 500 kHz.
532  *   LFACLK can't exceed 50 kHz if the ACMP threshold level (ACMPTHRES) is not
533  *   equal for all channels.
534  *
535  * @param[in] clk
536  *   Select the clock to prescale.
537  *    @li lesenseClkHF - set AUXHFRCO clock divisor for HF timer.
538  *    @li lesenseClkLF - set LFACLKles clock divisor for LF timer.
539  *
540  * @param[in] clkDiv
541  *   The clock divisor value. A valid range depends on the @p clk value.
542  ******************************************************************************/
LESENSE_ClkDivSet(LESENSE_ChClk_TypeDef clk,LESENSE_ClkPresc_TypeDef clkDiv)543 void LESENSE_ClkDivSet(LESENSE_ChClk_TypeDef clk,
544                        LESENSE_ClkPresc_TypeDef clkDiv)
545 {
546   uint32_t tmp;
547 #if defined(_SILICON_LABS_32B_SERIES_2)
548   bool enabled = false;
549 
550   if (LESENSE->EN != 0U) {
551     enabled = true;
552     /* Wait for synchronization before writing to EN register */
553     while (LESENSE->SYNCBUSY) {
554       /* Wait for all synchronizations to finish */
555     }
556     /* Disable LESENSE module */
557     LESENSE->EN_CLR = LESENSE_EN_EN;
558     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
559       /* Wait for disabling to finish */
560     }
561   }
562 #endif
563 
564   /* Select the clock to prescale. */
565   switch (clk) {
566     case lesenseClkHF:
567       /* A sanity check of the clock divisor for the HF clock. */
568       EFM_ASSERT((uint32_t)clkDiv <= lesenseClkDiv_8);
569 
570       /* Clear the current AUXPRESC settings. */
571       tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_AUXPRESC_MASK);
572 
573       /* Set the new values in tmp while reserving other settings. */
574       tmp |= ((uint32_t)clkDiv << _LESENSE_TIMCTRL_AUXPRESC_SHIFT);
575 
576       /* Set values in LESENSE_TIMCTRL register. */
577       LESENSE->TIMCTRL = tmp;
578       break;
579 
580     case lesenseClkLF:
581       /* Clear current LFPRESC settings. */
582       tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_LFPRESC_MASK);
583 
584       /* Set new values in tmp while reserving other settings. */
585       tmp |= ((uint32_t)clkDiv << _LESENSE_TIMCTRL_LFPRESC_SHIFT);
586 
587       /* Set values in the LESENSE_TIMCTRL register. */
588       LESENSE->TIMCTRL = tmp;
589       break;
590 
591     default:
592       EFM_ASSERT(0);
593       break;
594   }
595 
596 #if defined(_SILICON_LABS_32B_SERIES_2)
597   /* Re-Enable LESENSE module if it was enabled in the first place. */
598   if (enabled == true) {
599     LESENSE->EN_SET = LESENSE_EN_EN;
600   }
601 #endif
602 }
603 
604 /***************************************************************************//**
605  * @brief
606  *   Configure all (16) LESENSE sensor channels.
607  *
608  * @details
609  *   This function configures all sensor channels of the LESENSE interface.
610  *   See the configuration parameter type definition
611  *   (LESENSE_ChAll_TypeDef) for more details.
612  *
613  * @note
614  *   Channels can be configured individually using LESENSE_ChannelConfig()
615  *   function.
616  *   Notice that pins used by the LESENSE module must be properly configured
617  *   by the user explicitly for LESENSE to work as intended.
618  *   (When configuring pins, consider the sequence of the
619  *   configuration to avoid unintended pulses/glitches on output
620  *   pins.)
621  *
622  * @param[in] confChAll
623  *   A configuration structure for all (16) LESENSE sensor channels.
624  ******************************************************************************/
LESENSE_ChannelAllConfig(const LESENSE_ChAll_TypeDef * confChAll)625 void LESENSE_ChannelAllConfig(const LESENSE_ChAll_TypeDef * confChAll)
626 {
627   uint32_t i;
628 
629   /* Iterate through all 16 channels. */
630   for (i = 0U; i < LESENSE_NUM_CHANNELS; ++i) {
631     /* Configure scan channels. */
632     LESENSE_ChannelConfig(&confChAll->Ch[i], i);
633   }
634 }
635 
636 /***************************************************************************//**
637  * @brief
638  *   Configure a single LESENSE sensor channel.
639  *
640  * @details
641  *   This function configures a single sensor channel of the LESENSE interface.
642  *   See the configuration parameter type definition
643  *   (LESENSE_ChDesc_TypeDef) for more details.
644  *
645  * @note
646  *   This function has been designed to minimize the effects of sensor channel
647  *   reconfiguration while LESENSE is in operation. However, be aware
648  *   of these effects and the right timing to call this function.
649  *   Parameter @p useAltEx must be true in the channel configuration to
650  *   use alternate excitation pins.
651  *
652  * @param[in] confCh
653  *   A configuration structure for a single LESENSE sensor channel.
654  *
655  * @param[in] chIdx
656  *   A channel index to configure (0-15).
657  ******************************************************************************/
LESENSE_ChannelConfig(const LESENSE_ChDesc_TypeDef * confCh,uint32_t chIdx)658 void LESENSE_ChannelConfig(const LESENSE_ChDesc_TypeDef * confCh,
659                            uint32_t chIdx)
660 {
661   uint32_t tmp; /* A service variable. */
662 
663 #if defined(_SILICON_LABS_32B_SERIES_2)
664   bool enabled = false;
665 
666   if (LESENSE->EN != 0U) {
667     enabled = true;
668     /* Wait for synchronization before writing to EN register */
669     while (LESENSE->SYNCBUSY) {
670       /* Wait for all synchronizations to finish */
671     }
672     /* Disable LESENSE module */
673     LESENSE->EN_CLR = LESENSE_EN_EN;
674     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
675       /* Wait for disabling to finish */
676     }
677   }
678 #endif
679 
680   /* A sanity check of configuration parameters. */
681   EFM_ASSERT(chIdx < LESENSE_NUM_CHANNELS);
682   EFM_ASSERT(confCh->exTime      <= (_LESENSE_CH_TIMING_EXTIME_MASK >> _LESENSE_CH_TIMING_EXTIME_SHIFT));
683   EFM_ASSERT(confCh->measDelay   <= (_LESENSE_CH_TIMING_MEASUREDLY_MASK >> _LESENSE_CH_TIMING_MEASUREDLY_SHIFT));
684 #if defined(_LESENSE_CH_INTERACT_OFFSET_MASK)
685   EFM_ASSERT(confCh->offset      <= (_LESENSE_CH_INTERACT_OFFSET_MASK >> _LESENSE_CH_INTERACT_OFFSET_SHIFT));
686 #endif
687 #if defined(_SILICON_LABS_32B_SERIES_0)
688   // Sample delay on other devices are 8 bits which fits perfectly in uint8_t.
689   EFM_ASSERT(confCh->sampleDelay <= (_LESENSE_CH_TIMING_SAMPLEDLY_MASK >> _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT));
690 #endif
691 
692   /* Not a complete assert, as the maximum value of acmpThres depends on other
693    * configuration parameters. Check the parameter description of acmpThres
694    * for more details. */
695   EFM_ASSERT(confCh->acmpThres < 4096U);
696   if (confCh->chPinExMode == lesenseChPinExDACOut) {
697     EFM_ASSERT((0x1 << chIdx) & DACOUT_SUPPORT);
698   }
699 
700 #if defined(_LESENSE_IDLECONF_CH0_DACCH0)
701   EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh1
702                && ((chIdx != 12U)
703                    && (chIdx != 13U)
704                    && (chIdx != 14U)
705                    && (chIdx != 15U))));
706   EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh0
707                && ((chIdx != 0U)
708                    && (chIdx != 1U)
709                    && (chIdx != 2U)
710                    && (chIdx != 3U))));
711 #endif
712 
713   /* Configure the chIdx setup in LESENSE idle phase.
714    * Read-modify-write to support reconfiguration during the LESENSE
715    * operation. */
716   tmp               = (LESENSE->IDLECONF & ~((uint32_t)0x3UL << (chIdx * 2UL)));
717   tmp              |= ((uint32_t)confCh->chPinIdleMode << (chIdx * 2UL));
718   LESENSE->IDLECONF = tmp;
719 
720   /* A channel-specific timing configuration on scan channel chIdx.
721    * Set excitation time, sampling delay, and measurement delay. */
722   LESENSE_ChannelTimingSet(chIdx,
723                            confCh->exTime,
724                            confCh->sampleDelay,
725                            confCh->measDelay);
726 
727   /* A channel-specific configuration of clocks, sample mode, excitation pin mode
728    * alternate excitation usage, and interrupt mode on scan channel chIdx in
729    * LESENSE_CHchIdx_INTERACT. */
730   LESENSE->CH[chIdx].INTERACT =
731     ((uint32_t)confCh->exClk       << _LESENSE_CH_INTERACT_EXCLK_SHIFT)
732     | ((uint32_t)confCh->sampleClk << _LESENSE_CH_INTERACT_SAMPLECLK_SHIFT)
733     | (uint32_t)confCh->sampleMode
734     | (uint32_t)confCh->intMode
735     | (uint32_t)confCh->chPinExMode
736     | ((uint32_t)confCh->useAltEx  << _LESENSE_CH_INTERACT_ALTEX_SHIFT)
737 #if defined(_LESENSE_CH_INTERACT_OFFSET_MASK)
738     | ((uint32_t)confCh->offset    << _LESENSE_CH_INTERACT_OFFSET_SHIFT)
739 #endif
740   ;
741 
742   /* Configure the channel-specific counter comparison mode, optional result
743    * forwarding to decoder, optional counter value storing, and optional result
744    * inverting on scan channel chIdx in LESENSE_CHchIdx_EVAL. */
745 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
746   LESENSE->CH[chIdx].EVAL =
747     (uint32_t)confCh->compMode
748     | ((uint32_t)confCh->shiftRes    << _LESENSE_CH_EVAL_DECODE_SHIFT)
749     | ((uint32_t)confCh->storeCntRes << _LESENSE_CH_EVAL_STRSAMPLE_SHIFT)
750     | ((uint32_t)confCh->invRes      << _LESENSE_CH_EVAL_SCANRESINV_SHIFT)
751 #if defined(_LESENSE_CH_EVAL_MODE_MASK)
752     | ((uint32_t)confCh->evalMode    << _LESENSE_CH_EVAL_MODE_SHIFT)
753 #endif
754   ;
755 #else
756   LESENSE->CH[chIdx].EVALCFG =
757     (uint32_t)confCh->compMode
758     | ((uint32_t)confCh->shiftRes    << _LESENSE_CH_EVALCFG_DECODE_SHIFT)
759     | ((uint32_t)confCh->storeCntRes << _LESENSE_CH_EVALCFG_STRSAMPLE_SHIFT)
760     | ((uint32_t)confCh->invRes      << _LESENSE_CH_EVALCFG_SCANRESINV_SHIFT)
761     | ((uint32_t)confCh->evalMode    << _LESENSE_CH_EVALCFG_MODE_SHIFT)
762   ;
763 #endif
764 
765   /* Configure the analog comparator (ACMP) threshold and decision threshold for
766    * the counter separately with the function provided for that. */
767   LESENSE_ChannelThresSet(chIdx,
768                           confCh->acmpThres,
769                           confCh->cntThres);
770 
771   /* Enable/disable interrupts on channel */
772   BUS_RegBitWrite(&LESENSE->IEN, chIdx, confCh->enaInt);
773 
774   /* Enable/disable CHchIdx pin. */
775   BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE, chIdx, confCh->enaPin);
776 
777   /* Enable/disable scan channel chIdx. */
778   BUS_RegBitWrite(&LESENSE->CHEN, chIdx, confCh->enaScanCh);
779 
780 #if defined(_SILICON_LABS_32B_SERIES_2)
781   /* Re-Enable LESENSE module if it was enabled in the first place. */
782   if (enabled == true) {
783     LESENSE->EN_SET = LESENSE_EN_EN;
784   }
785 #endif
786 }
787 
788 /***************************************************************************//**
789  * @brief
790  *   Configure the LESENSE alternate excitation modes.
791  *
792  * @details
793  *   This function configures the alternate excitation channels of the LESENSE
794  *   interface. See the configuration parameter type definition
795  *   (LESENSE_ConfAltEx_TypeDef) for more details.
796  *
797  * @note
798  *   The @p useAltEx parameter must be true in the channel configuration structure
799  *   (LESENSE_ChDesc_TypeDef) to use alternate excitation pins on the
800  *   channel.
801  *
802  * @param[in] confAltEx
803  *   A configuration structure for LESENSE alternate excitation pins.
804  ******************************************************************************/
LESENSE_AltExConfig(const LESENSE_ConfAltEx_TypeDef * confAltEx)805 void LESENSE_AltExConfig(const LESENSE_ConfAltEx_TypeDef * confAltEx)
806 {
807   uint32_t i;
808 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
809   uint32_t tmp;
810 
811   /* Configure the alternate excitation mapping.
812    * Atomic read-modify-write using BUS_RegBitWrite function to
813    * support reconfiguration during the LESENSE operation. */
814   BUS_RegBitWrite(&LESENSE->CTRL,
815                   _LESENSE_CTRL_ALTEXMAP_SHIFT,
816                   confAltEx->altExMap);
817 
818   switch (confAltEx->altExMap) {
819     case lesenseAltExMapALTEX:
820       /* Iterate through the 8 possible alternate excitation pin descriptors. */
821       for (i = 0U; i < 8U; ++i) {
822         /* Enable/disable the alternate excitation pin i.
823          * Atomic read-modify-write using BUS_RegBitWrite function to
824          * support reconfiguration during the LESENSE operation. */
825         BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE,
826                         (16UL + i),
827                         confAltEx->AltEx[i].enablePin);
828 
829         /* Set up the idle phase state of the alternate excitation pin i.
830          * Read-modify-write to support reconfiguration during the LESENSE
831          * operation. */
832         tmp                = (LESENSE->ALTEXCONF & ~((uint32_t)0x3UL << (i * 2UL)));
833         tmp               |= ((uint32_t)confAltEx->AltEx[i].idleConf << (i * 2UL));
834         LESENSE->ALTEXCONF = tmp;
835 
836         /* Enable/disable always excite on channel i. */
837         BUS_RegBitWrite(&LESENSE->ALTEXCONF,
838                         (16UL + i),
839                         confAltEx->AltEx[i].alwaysEx);
840       }
841       break;
842 
843 #if defined(_LESENSE_CTRL_ALTEXMAP_ACMP)
844     case lesenseAltExMapACMP:
845 #else
846     case lesenseAltExMapCH:
847 #endif
848       /* Iterate through all 16 alternate excitation channels. */
849       for (i = 0U; i < 16U; ++i) {
850         /* Enable/disable the alternate ACMP excitation channel pin i. */
851         /* An atomic read-modify-write using BUS_RegBitWrite function to
852          * support reconfiguration during the LESENSE operation. */
853         BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE,
854                         i,
855                         confAltEx->AltEx[i].enablePin);
856       }
857       break;
858     default:
859       /* An illegal value. */
860       EFM_ASSERT(0);
861       break;
862   }
863 #else
864   /* Iterate through all 16 alternate excitation channels. */
865   for (i = 0U; i < 16U; ++i) {
866     /* Enable/disable the alternate excitation channel pin i. */
867     /* An atomic read-modify-write using BUS_RegBitWrite function to
868      * support reconfiguration during the LESENSE operation. */
869     BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE,
870                     i,
871                     confAltEx->AltEx[i].enablePin);
872   }
873 #endif
874 }
875 
876 /***************************************************************************//**
877  * @brief
878  *   Enable/disable LESENSE scan channel and the pin assigned to it.
879  *
880  * @details
881  *   Use this function to enable/disable a selected LESENSE scan channel and the
882  *   pin assigned to it.
883  *
884  * @note
885  *   Users can enable/disable scan channels and the channel pin with
886  *   the LESENSE_ChannelConfig() function, but only with a significant overhead.
887  *   This simple function controls these parameters
888  *   after the channel has been configured.
889  *
890  * @param[in] chIdx
891  *   An identifier of the scan channel. A valid range: 0-15.
892  *
893  * @param[in] enaScanCh
894  *   Enable/disable the selected scan channel by setting this parameter to
895  *   true/false respectively.
896  *
897  * @param[in] enaPin
898  *   Enable/disable the pin assigned to the channel selected by @p chIdx.
899  ******************************************************************************/
LESENSE_ChannelEnable(uint8_t chIdx,bool enaScanCh,bool enaPin)900 void LESENSE_ChannelEnable(uint8_t chIdx,
901                            bool enaScanCh,
902                            bool enaPin)
903 {
904   /* Enable/disable the assigned pin of scan channel chIdx.
905    * Note: BUS_RegBitWrite() function is used for setting/clearing single
906    * bit peripheral register bit fields. Read the function description in
907    * em_bus.h for more details. */
908   BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE, chIdx, enaPin);
909 
910   /* Enable/disable scan channel chIdx. */
911   BUS_RegBitWrite(&LESENSE->CHEN, chIdx, enaScanCh);
912 }
913 
914 /***************************************************************************//**
915  * @brief
916  *   Enable/disable LESENSE scan channel and the pin assigned to it.
917  *
918  * @details
919  *   Use this function to enable/disable LESENSE scan channels and the pins
920  *   assigned to them using a mask.
921  *
922  * @note
923  *   Users can enable/disable scan channels and channel pins by using the
924  *   LESENSE_ChannelAllConfig() function, but only with a significant overhead.
925  *   This simple function controls these parameters
926  *   after the channel has been configured.
927  *
928  * @param[in] chMask
929  *   Set the corresponding bit to 1 to enable, 0 to disable the selected scan
930  *   channel.
931  *
932  * @param[in] pinMask
933  *   Set the corresponding bit to 1 to enable, 0 to disable the pin on selected
934  *   channel.
935  ******************************************************************************/
LESENSE_ChannelEnableMask(uint16_t chMask,uint16_t pinMask)936 void LESENSE_ChannelEnableMask(uint16_t chMask, uint16_t pinMask)
937 {
938   /* Enable/disable all channels at once according to the mask. */
939   LESENSE->CHEN = chMask;
940   /* Enable/disable all channel pins at once according to the mask. */
941   GENERIC_LESENSE_ROUTE = pinMask;
942 }
943 
944 /***************************************************************************//**
945  * @brief
946  *   Set LESENSE channel timing parameters.
947  *
948  * @details
949  *   Use this function to set timing parameters on a selected LESENSE channel.
950  *
951  * @note
952  *   Users can configure the channel timing parameters with the
953  *   LESENSE_ChannelConfig() function, but only with a significant overhead.
954  *   This simple function controls these parameters
955  *   after the channel has been configured.
956  *
957  * @param[in] chIdx
958  *   An identifier of the scan channel. A valid range is 0-15.
959  *
960  * @param[in] exTime
961  *   An excitation time on chIdx. The excitation will last exTime+1 excitation clock
962  *   cycles. A valid range is 0-63 (6 bits).
963  *
964  * @param[in] sampleDelay
965  *   Sample delay on chIdx. Sampling will occur after sampleDelay+1 sample clock
966  *   cycles. A valid range is 0-127 (7 bits).
967  *
968  * @param[in] measDelay
969  *   A measure delay on chIdx. Sensor measuring is delayed for measDelay+1
970  *   excitation clock cycles. A valid range is 0-127 (7 bits).
971  ******************************************************************************/
LESENSE_ChannelTimingSet(uint8_t chIdx,uint8_t exTime,uint8_t sampleDelay,uint16_t measDelay)972 void LESENSE_ChannelTimingSet(uint8_t chIdx,
973                               uint8_t exTime,
974                               uint8_t sampleDelay,
975                               uint16_t measDelay)
976 {
977 #if defined(_SILICON_LABS_32B_SERIES_2)
978   bool enabled = false;
979 #endif
980 
981   /* A sanity check of parameters. */
982   EFM_ASSERT(exTime      <= (_LESENSE_CH_TIMING_EXTIME_MASK >> _LESENSE_CH_TIMING_EXTIME_SHIFT));
983   EFM_ASSERT(measDelay   <= (_LESENSE_CH_TIMING_MEASUREDLY_MASK >> _LESENSE_CH_TIMING_MEASUREDLY_SHIFT));
984 #if defined(_SILICON_LABS_32B_SERIES_0)
985   // A sample delay on other devices is 8 bits which fits perfectly in uint8_t.
986   EFM_ASSERT(sampleDelay <= (_LESENSE_CH_TIMING_SAMPLEDLY_MASK >> _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT));
987 #endif
988 
989 #if defined(_SILICON_LABS_32B_SERIES_2)
990   if (LESENSE->EN != 0U) {
991     enabled = true;
992     /* Wait for synchronization before writing to EN register */
993     while (LESENSE->SYNCBUSY) {
994       /* Wait for all synchronizations to finish */
995     }
996     /* Disable LESENSE module */
997     LESENSE->EN_CLR = LESENSE_EN_EN;
998     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
999       /* Wait for disabling to finish */
1000     }
1001   }
1002 #endif
1003 
1004   /* A channel-specific timing configuration on the scan channel chIdx.
1005    * Setting excitation time, sampling delay, and measurement delay. */
1006   LESENSE->CH[chIdx].TIMING =
1007     ((uint32_t)exTime        << _LESENSE_CH_TIMING_EXTIME_SHIFT)
1008     | ((uint32_t)sampleDelay << _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT)
1009     | ((uint32_t)measDelay   << _LESENSE_CH_TIMING_MEASUREDLY_SHIFT);
1010 
1011 #if defined(_SILICON_LABS_32B_SERIES_2)
1012   /* Re-Enable LESENSE module if it was enabled in the first place. */
1013   if (enabled == true) {
1014     LESENSE->EN_SET = LESENSE_EN_EN;
1015   }
1016 #endif
1017 }
1018 
1019 /***************************************************************************//**
1020  * @brief
1021  *   Set LESENSE channel threshold parameters.
1022  *
1023  * @details
1024  *   Use this function to set threshold parameters on a selected LESENSE
1025  *   channel.
1026  *
1027  * @note
1028  *   Users can configure the channel threshold parameters with the
1029  *   LESENSE_ChannelConfig() function, but only with a significant overhead.
1030  *   This simple function serves controls these parameters
1031  *   after the channel has been configured.
1032  *
1033  * @param[in] chIdx
1034  *   An identifier of the scan channel. A valid range is 0-15.
1035  *
1036  * @param[in] acmpThres
1037  *   ACMP threshold.
1038  *   @li If perCtrl.dacCh0Data or perCtrl.dacCh1Data is set to
1039  *   #lesenseDACIfData, acmpThres defines the 12-bit DAC data in the
1040  *   corresponding data register of the DAC interface (DACn_CH0DATA and
1041  *   DACn_CH1DATA). In this case, the valid range is 0-4095 (12 bits).
1042  *
1043  *   @li If perCtrl.dacCh0Data or perCtrl.dacCh1Data is set to
1044  *   lesenseACMPThres, acmpThres defines the 6-bit Vdd scaling factor of ACMP
1045  *   negative input (VDDLEVEL in ACMP_INPUTSEL register). In this case, the
1046  *   valid range is 0-63 (6 bits).
1047  *
1048  * @param[in] cntThres
1049  *   A decision threshold for counter comparison.
1050  *   A valid range is 0-65535 (16 bits).
1051  ******************************************************************************/
LESENSE_ChannelThresSet(uint8_t chIdx,uint16_t acmpThres,uint16_t cntThres)1052 void LESENSE_ChannelThresSet(uint8_t chIdx,
1053                              uint16_t acmpThres,
1054                              uint16_t cntThres)
1055 {
1056   uint32_t tmp; /* A temporary storage */
1057 #if defined(_SILICON_LABS_32B_SERIES_2)
1058   bool enabled = false;
1059 #endif
1060 
1061   /* A sanity check for acmpThres only, cntThres is a 16 bit value. */
1062   EFM_ASSERT(acmpThres < 4096U);
1063   /* A sanity check for the LESENSE channel ID. */
1064   EFM_ASSERT(chIdx < LESENSE_NUM_CHANNELS);
1065 
1066 #if defined(_SILICON_LABS_32B_SERIES_2)
1067   if (LESENSE->EN != 0U) {
1068     enabled = true;
1069     /* Wait for synchronization before writing to EN register */
1070     while (LESENSE->SYNCBUSY) {
1071       /* Wait for all synchronizations to finish */
1072     }
1073     /* Disable LESENSE module */
1074     LESENSE->EN_CLR = LESENSE_EN_EN;
1075     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1076       /* Wait for disabling to finish */
1077     }
1078   }
1079 #endif
1080 
1081   /* Save the INTERACT register value of channel chIdx to tmp.
1082    * Be aware of the effects of the non-atomic Read-Modify-Write cycle. */
1083   tmp = LESENSE->CH[chIdx].INTERACT & ~(0xFFF);
1084   /* Set the ACMP threshold value to the INTERACT register of the channel chIdx. */
1085   tmp |= (uint32_t)acmpThres;
1086   /* Write the new value to the INTERACT register. */
1087   LESENSE->CH[chIdx].INTERACT = tmp;
1088 
1089 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1090   /* Save the EVAL register value of channel chIdx to tmp.
1091    * Be aware of the effects of the non-atomic Read-Modify-Write cycle. */
1092   tmp = LESENSE->CH[chIdx].EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK);
1093   /* Set the counter threshold value to the INTERACT register of the channel chIdx. */
1094   tmp |= (uint32_t)cntThres << _LESENSE_CH_EVAL_COMPTHRES_SHIFT;
1095   /* Write the new value to the EVAL register. */
1096   LESENSE->CH[chIdx].EVAL = tmp;
1097 #else
1098 
1099   LESENSE->EN_SET = LESENSE_EN_EN;
1100 
1101   LESENSE->CH[chIdx].EVALTHRES = (uint32_t)cntThres << _LESENSE_CH_EVALTHRES_EVALTHRES_SHIFT;
1102 
1103   while (LESENSE->SYNCBUSY) {
1104     /* Wait for all synchronizations to finish */
1105   }
1106   if (!enabled) {
1107     /* Disable LESENSE module */
1108     LESENSE->EN_CLR = LESENSE_EN_EN;
1109     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1110       /* Wait for disabling to finish */
1111     }
1112   }
1113 
1114 #endif
1115 }
1116 
1117 #if defined(_LESENSE_CH_EVAL_MODE_MASK) || defined(_LESENSE_CH_EVALCFG_MODE_MASK)
1118 /***************************************************************************//**
1119  * @brief
1120  *   Configure a Sliding Window evaluation mode for a specific channel.
1121  *
1122  * @details
1123  *   This function will configure the evaluation mode, the initial
1124  *   sensor measurement (COMPTHRES), and the window size. For other channel-related
1125  *   configuration, see the @ref LESENSE_ChannelConfig() function.
1126  *
1127  * @warning
1128  *   Note that the step size and window size configuration are global to all
1129  *   LESENSE channels and use the same register field in the hardware. This
1130  *   means that any windowSize configuration passed to this function will
1131  *   apply for all channels and override all other stepSize/windowSize
1132  *   configurations.
1133  *
1134  * @param[in] chIdx
1135  *   An identifier of the scan channel. A valid range is 0-15.
1136  *
1137  * @param[in] windowSize
1138  *   A window size to be used on all channels.
1139  *
1140  * @param[in] initValue
1141  *   The initial sensor value for the channel.
1142  ******************************************************************************/
LESENSE_ChannelSlidingWindow(uint8_t chIdx,uint32_t windowSize,uint32_t initValue)1143 void LESENSE_ChannelSlidingWindow(uint8_t chIdx,
1144                                   uint32_t windowSize,
1145                                   uint32_t initValue)
1146 {
1147   LESENSE_CH_TypeDef * ch = &LESENSE->CH[chIdx];
1148 #if defined(_SILICON_LABS_32B_SERIES_2)
1149   bool enabled = false;
1150 #endif
1151 
1152   LESENSE_WindowSizeSet(windowSize);
1153 
1154 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1155   ch->EVAL = (ch->EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK | _LESENSE_CH_EVAL_MODE_MASK))
1156              | (initValue << _LESENSE_CH_EVAL_COMPTHRES_SHIFT)
1157              | LESENSE_CH_EVAL_MODE_SLIDINGWIN;
1158 #else
1159 
1160   if (LESENSE->EN != 0U) {
1161     enabled = true;
1162     /* Wait for synchronization before writing to EN register */
1163     while (LESENSE->SYNCBUSY) {
1164       /* Wait for all synchronizations to finish */
1165     }
1166     /* Disable LESENSE module */
1167     LESENSE->EN_CLR = LESENSE_EN_EN;
1168     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1169       /* Wait for disabling to finish */
1170     }
1171   }
1172 
1173   /* Set Channel Sliding Window config */
1174   ch->EVALCFG = (ch->EVALCFG & ~_LESENSE_CH_EVALCFG_MODE_MASK)
1175                 | LESENSE_CH_EVALCFG_MODE_SLIDINGWIN;
1176 
1177   LESENSE->EN_SET = LESENSE_EN_EN;
1178   ch->EVALTHRES = (ch->EVALTHRES & ~_LESENSE_CH_EVALTHRES_EVALTHRES_MASK)
1179                   | (initValue << _LESENSE_CH_EVALTHRES_EVALTHRES_SHIFT);
1180   while (LESENSE->SYNCBUSY) {
1181     /* Wait for all synchronizations to finish */
1182   }
1183   if (!enabled) {
1184     /* Disable LESENSE module */
1185     LESENSE->EN_CLR = LESENSE_EN_EN;
1186     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1187       /* Wait for disabling to finish */
1188     }
1189   }
1190 #endif
1191 }
1192 
1193 /***************************************************************************//**
1194  * @brief
1195  *   Configure the step detection evaluation mode for a specific channel.
1196  *
1197  * @details
1198  *   This function will configure the evaluation mode, the initial
1199  *   sensor measurement (COMPTHRES) and the window size. For other channel-related
1200  *   configuration, see the @ref LESENSE_ChannelConfig() function.
1201  *
1202  * @warning
1203  *   Note that the step size and window size configuration are global to all
1204  *   LESENSE channels and use the same register field in the hardware. This
1205  *   means that any stepSize configuration passed to this function will
1206  *   apply for all channels and override all other stepSize/windowSize
1207  *   configurations.
1208  *
1209  * @param[in] chIdx
1210  *   An identifier of the scan channel. A valid range is 0-15.
1211  *
1212  * @param[in] stepSize
1213  *   A step size to be used on all channels.
1214  *
1215  * @param[in] initValue
1216  *   The initial sensor value for the channel.
1217  ******************************************************************************/
LESENSE_ChannelStepDetection(uint8_t chIdx,uint32_t stepSize,uint32_t initValue)1218 void LESENSE_ChannelStepDetection(uint8_t chIdx,
1219                                   uint32_t stepSize,
1220                                   uint32_t initValue)
1221 {
1222   LESENSE_CH_TypeDef * ch = &LESENSE->CH[chIdx];
1223 #if defined(_SILICON_LABS_32B_SERIES_2)
1224   bool enabled = false;
1225 #endif
1226 
1227   LESENSE_StepSizeSet(stepSize);
1228 
1229 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1230   ch->EVAL = (ch->EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK | _LESENSE_CH_EVAL_MODE_MASK))
1231              | (initValue << _LESENSE_CH_EVAL_COMPTHRES_SHIFT)
1232              | LESENSE_CH_EVAL_MODE_STEPDET;
1233 #else
1234   if (LESENSE->EN != 0U) {
1235     enabled = true;
1236     /* Wait for synchronization before writing to EN register */
1237     while (LESENSE->SYNCBUSY) {
1238       /* Wait for all synchronizations to finish */
1239     }
1240     /* Disable LESENSE module */
1241     LESENSE->EN_CLR = LESENSE_EN_EN;
1242     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1243       /* Wait for disabling to finish */
1244     }
1245   }
1246 
1247   ch->EVALCFG = (ch->EVALCFG & ~_LESENSE_CH_EVALCFG_MODE_MASK)
1248                 | LESENSE_CH_EVALCFG_MODE_STEPDET;
1249 
1250   LESENSE->EN_SET = LESENSE_EN_EN;
1251   ch->EVALTHRES = (ch->EVALTHRES & ~_LESENSE_CH_EVALTHRES_EVALTHRES_MASK)
1252                   | (initValue << _LESENSE_CH_EVALTHRES_EVALTHRES_SHIFT);
1253   while (LESENSE->SYNCBUSY) {
1254     /* Wait for all synchronizations to finish */
1255   }
1256   if (!enabled) {
1257     /* Disable LESENSE module */
1258     LESENSE->EN_CLR = LESENSE_EN_EN;
1259     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1260       /* Wait for disabling to finish */
1261     }
1262   }
1263 #endif
1264 }
1265 
1266 /***************************************************************************//**
1267  * @brief
1268  *   Set the window size for all LESENSE channels.
1269  *
1270  * @details
1271  *   The window size is used by all channels that are configured as
1272  *   @ref lesenseEvalModeSlidingWindow.
1273  *
1274  * @warning
1275  *   The window size configuration is using the same register field as the
1276  *   step detection size. As a result, the window size configuration will have an
1277  *   effect on channels configured with the @ref lesenseEvalModeStepDetection
1278  *   evaluation mode as well.
1279  *
1280  * @param[in] windowSize
1281  *   The window size to use for all channels.
1282  ******************************************************************************/
LESENSE_WindowSizeSet(uint32_t windowSize)1283 void LESENSE_WindowSizeSet(uint32_t windowSize)
1284 {
1285 #if defined(_SILICON_LABS_32B_SERIES_2)
1286   bool enabled = false;
1287 
1288   if (LESENSE->EN != 0U) {
1289     enabled = true;
1290     /* Wait for synchronization before writing to EN register */
1291     while (LESENSE->SYNCBUSY) {
1292       /* Wait for all synchronizations to finish */
1293     }
1294     /* Disable LESENSE module */
1295     LESENSE->EN_CLR = LESENSE_EN_EN;
1296     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1297       /* Wait for disabling to finish */
1298     }
1299   }
1300 #endif
1301 
1302   LESENSE->EVALCTRL = (LESENSE->EVALCTRL & ~_LESENSE_EVALCTRL_WINSIZE_MASK)
1303                       | windowSize;
1304 
1305 #if defined(_SILICON_LABS_32B_SERIES_2)
1306   /* Re-Enable LESENSE module if it was enabled in the first place. */
1307   if (enabled == true) {
1308     LESENSE->EN_SET = LESENSE_EN_EN;
1309   }
1310 #endif
1311 }
1312 
1313 /***************************************************************************//**
1314  * @brief
1315  *   Set the step size for all LESENSE channels.
1316  *
1317  * @details
1318  *   The step size is configured using the same register field as used to
1319  *   configure window size. Therefore, calling this function will overwrite any
1320  *   previously configured window size as done by the
1321  *   @ref LESENSE_WindowSizeSet() function.
1322  *
1323  * @param[in] stepSize
1324  *   The step size to use for all channels.
1325  ******************************************************************************/
LESENSE_StepSizeSet(uint32_t stepSize)1326 void LESENSE_StepSizeSet(uint32_t stepSize)
1327 {
1328   LESENSE_WindowSizeSet(stepSize);
1329 }
1330 #endif
1331 
1332 /***************************************************************************//**
1333  * @brief
1334  *   Configure all LESENSE decoder states.
1335  *
1336  * @details
1337  *   This function configures all the decoder states of the LESENSE interface.
1338  *   See the configuration parameter type definition
1339  *   (LESENSE_DecStAll_TypeDef) for more details.
1340  *
1341  * @param[in] confDecStAll
1342  *   A configuration structure for all (16 or 32) LESENSE decoder states.
1343  *
1344  * @note
1345  *   Decoder states can be configured individually using
1346  *   LESENSE_DecoderStateConfig() function.
1347  *   Starting from Series 2 Config 3 (xG23 and higher), this function configures
1348  *   a transition ARC instead of a decoder state.
1349  ******************************************************************************/
LESENSE_DecoderStateAllConfig(const LESENSE_DecStAll_TypeDef * confDecStAll)1350 void LESENSE_DecoderStateAllConfig(const LESENSE_DecStAll_TypeDef * confDecStAll)
1351 {
1352   uint32_t i;
1353 
1354 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1355   /* Iterate through all 16 or 32 decoder states. */
1356   for (i = 0U; i < LESENSE_NUM_DECODER_STATES; ++i) {
1357     /* A configure decoder for state i. */
1358     LESENSE_DecoderStateConfig(&confDecStAll->St[i], i);
1359   }
1360 #else
1361   /* Iterate through all 64 transition arcs. */
1362   for (i = 0U; i < LESENSE_NUM_ARCS; ++i) {
1363     /* A configure decoder for arc i. */
1364     LESENSE_DecoderStateConfig(&confDecStAll->St[i], i);
1365   }
1366 #endif
1367 }
1368 
1369 /***************************************************************************//**
1370  * @brief
1371  *   Configure a single LESENSE decoder state.
1372  *
1373  * @details
1374  *   This function configures a single decoder state of the LESENSE interface.
1375  *   See the configuration parameter type definition
1376  *   (LESENSE_DecStDesc_TypeDef) for more details.
1377  *
1378  * @param[in] confDecSt
1379  *   A configuration structure for a single LESENSE decoder state.
1380  *
1381  * @param[in] decSt
1382  *   A decoder state index to configure (0-15) or (0-31) depending on the device.
1383  *
1384  * @note
1385  *   Starting from Series 2 Config 3 (xG23 and higher), this function configures
1386  *   a transition ARC instead of a decoder state.
1387  ******************************************************************************/
LESENSE_DecoderStateConfig(const LESENSE_DecStDesc_TypeDef * confDecSt,uint32_t decSt)1388 void LESENSE_DecoderStateConfig(const LESENSE_DecStDesc_TypeDef * confDecSt,
1389                                 uint32_t decSt)
1390 {
1391 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1392   /* Sanity check of configuration parameters */
1393   EFM_ASSERT(decSt < LESENSE_NUM_DECODER_STATES);
1394   EFM_ASSERT((uint32_t)confDecSt->confA.compMask < 16U);
1395   EFM_ASSERT((uint32_t)confDecSt->confA.compVal < 16U);
1396   EFM_ASSERT((uint32_t)confDecSt->confA.nextState < LESENSE_NUM_DECODER_STATES);
1397   EFM_ASSERT((uint32_t)confDecSt->confB.compMask < 16U);
1398   EFM_ASSERT((uint32_t)confDecSt->confB.compVal < 16U);
1399   EFM_ASSERT((uint32_t)confDecSt->confB.nextState < LESENSE_NUM_DECODER_STATES);
1400 
1401   /* Configure the state descriptor A (LESENSE_STi_TCONFA) for the decoder state i.
1402    * Setting sensor compare value, sensor mask, next state index,
1403    * transition action, interrupt flag option, and state descriptor chaining
1404    * configurations. */
1405   LESENSE->ST[decSt].TCONFA =
1406     (uint32_t)confDecSt->confA.prsAct
1407     | ((uint32_t)confDecSt->confA.compMask  << _LESENSE_ST_TCONFA_MASK_SHIFT)
1408     | ((uint32_t)confDecSt->confA.compVal   << _LESENSE_ST_TCONFA_COMP_SHIFT)
1409     | ((uint32_t)confDecSt->confA.nextState << _LESENSE_ST_TCONFA_NEXTSTATE_SHIFT)
1410     | ((uint32_t)confDecSt->confA.setInt    << _LESENSE_ST_TCONFA_SETIF_SHIFT)
1411     | ((uint32_t)confDecSt->chainDesc       << _LESENSE_ST_TCONFA_CHAIN_SHIFT);
1412 
1413   /* Configure the state descriptor Bi (LESENSE_STi_TCONFB).
1414    * Setting sensor compare value, sensor mask, next state index, transition
1415    * action, and interrupt flag option configurations. */
1416   LESENSE->ST[decSt].TCONFB =
1417     (uint32_t)confDecSt->confB.prsAct
1418     | ((uint32_t)confDecSt->confB.compMask  << _LESENSE_ST_TCONFB_MASK_SHIFT)
1419     | ((uint32_t)confDecSt->confB.compVal   << _LESENSE_ST_TCONFB_COMP_SHIFT)
1420     | ((uint32_t)confDecSt->confB.nextState << _LESENSE_ST_TCONFB_NEXTSTATE_SHIFT)
1421     | ((uint32_t)confDecSt->confB.setInt    << _LESENSE_ST_TCONFB_SETIF_SHIFT);
1422 #else
1423   bool enabled = false;
1424 
1425   /* Sanity check of configuration parameters */
1426   EFM_ASSERT(decSt < LESENSE_NUM_ARCS);
1427   EFM_ASSERT((uint32_t)confDecSt->compMask < 16U);
1428   EFM_ASSERT((uint32_t)confDecSt->compVal < 16U);
1429   EFM_ASSERT((uint32_t)confDecSt->curState < LESENSE_NUM_DECODER_STATES);
1430   EFM_ASSERT((uint32_t)confDecSt->nextState < LESENSE_NUM_DECODER_STATES);
1431 
1432   if (LESENSE->EN != 0U) {
1433     enabled = true;
1434     /* Wait for synchronization before writing to EN register */
1435     while (LESENSE->SYNCBUSY) {
1436       /* Wait for all synchronizations to finish */
1437     }
1438     /* Disable LESENSE module */
1439     LESENSE->EN_CLR = LESENSE_EN_EN;
1440     while (LESENSE->EN & _LESENSE_EN_DISABLING_MASK) {
1441       /* Wait for disabling to finish */
1442     }
1443   }
1444 
1445   LESENSE->ST[decSt].ARC =  (uint32_t)confDecSt->prsAct
1446                            | ((uint32_t)confDecSt->compMask  << _LESENSE_ST_ARC_SMASK_SHIFT)
1447                            | ((uint32_t)confDecSt->compVal   << _LESENSE_ST_ARC_SCOMP_SHIFT)
1448                            | ((uint32_t)confDecSt->curState  << _LESENSE_ST_ARC_CURSTATE_SHIFT)
1449                            | ((uint32_t)confDecSt->nextState << _LESENSE_ST_ARC_NEXTSTATE_SHIFT)
1450                            | ((uint32_t)confDecSt->setInt    << _LESENSE_ST_ARC_SETIF_SHIFT);
1451 
1452   /* Re-Enable LESENSE module if it was enabled in the first place. */
1453   if (enabled == true) {
1454     LESENSE->EN_SET = LESENSE_EN_EN;
1455   }
1456 #endif
1457 }
1458 
1459 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1460 /***************************************************************************//**
1461  * @brief
1462  *   Set the LESENSE decoder state.
1463  *
1464  * @details
1465  *   This function can be used for setting the initial state of the LESENSE
1466  *   decoder.
1467  *
1468  * @note
1469  *   Make sure the LESENSE decoder state is initialized by this function before
1470  *   enabling the decoder!
1471  *
1472  * @param[in] decSt
1473  *   A decoder state to set as the current state. A valid range is 0-15 or 0-31,
1474  *   depending on the device.
1475  ******************************************************************************/
LESENSE_DecoderStateSet(uint32_t decSt)1476 void LESENSE_DecoderStateSet(uint32_t decSt)
1477 {
1478   EFM_ASSERT(decSt <= _LESENSE_DECSTATE_DECSTATE_MASK);
1479 
1480   LESENSE->DECSTATE = decSt & _LESENSE_DECSTATE_DECSTATE_MASK;
1481 }
1482 #endif
1483 
1484 /***************************************************************************//**
1485  * @brief
1486  *   Get the current state of the LESENSE decoder.
1487  *
1488  * @return
1489  *   This function returns the value of the LESENSE_DECSTATE register that
1490  *   represents the current state of the LESENSE decoder.
1491  ******************************************************************************/
LESENSE_DecoderStateGet(void)1492 uint32_t LESENSE_DecoderStateGet(void)
1493 {
1494   return LESENSE->DECSTATE & _LESENSE_DECSTATE_DECSTATE_MASK;
1495 }
1496 
1497 #if defined(_LESENSE_PRSCTRL_MASK)
1498 /***************************************************************************//**
1499  * @brief
1500  *   Enable or disable the PRS output from the LESENSE decoder.
1501  *
1502  * @param[in] enable
1503  *   Enable/disable the PRS output from the LESENSE decoder. True to enable and
1504  *   false to disable.
1505  *
1506  * @param[in] decMask
1507  *   A decoder state compare value mask.
1508  *
1509  * @param[in] decVal
1510  *   A decoder state comparison value.
1511  ******************************************************************************/
LESENSE_DecoderPrsOut(bool enable,uint32_t decMask,uint32_t decVal)1512 void LESENSE_DecoderPrsOut(bool enable, uint32_t decMask, uint32_t decVal)
1513 {
1514   LESENSE->PRSCTRL = (enable << _LESENSE_PRSCTRL_DECCMPEN_SHIFT)
1515                      | (decMask << _LESENSE_PRSCTRL_DECCMPMASK_SHIFT)
1516                      | (decVal << _LESENSE_PRSCTRL_DECCMPVAL_SHIFT);
1517 }
1518 #endif
1519 
1520 /***************************************************************************//**
1521  * @brief
1522  *   Start scanning sensors.
1523  *
1524  * @note
1525  *   This function will wait for any pending previous write operation to the
1526  *   CMD register to complete before accessing the CMD register. It will also
1527  *   wait for the write operation to the CMD register to complete before
1528  *   returning. Each write operation to the CMD register may take up to 3 LF
1529  *   clock cycles, so expect some delay. The user may implement
1530  *   a separate function to write multiple command bits in the CMD register
1531  *   in one single operation to optimize an application.
1532  ******************************************************************************/
LESENSE_ScanStart(void)1533 void LESENSE_ScanStart(void)
1534 {
1535   /* Wait for any pending previous write operation to the CMD register to
1536      complete before accessing the CMD register. */
1537   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY) {
1538   }
1539 
1540   /* Start scanning sensors. */
1541   LESENSE->CMD = LESENSE_CMD_START;
1542 
1543   /* Wait for the write operation to the CMD register to complete before
1544      returning. */
1545   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY) {
1546   }
1547 }
1548 
1549 /***************************************************************************//**
1550  * @brief
1551  *   Stop scanning sensors.
1552  *
1553  * @note
1554  *   This function will wait for any pending previous write operation to the
1555  *   CMD register to complete before accessing the CMD register. It will also
1556  *   wait for the write operation to the CMD register to complete before
1557  *   returning. Each write operation to the CMD register may take up to 3 LF
1558  *   clock cycles, so the user should expect some delay. The user may implement
1559  *   a separate function to write multiple command bits in the CMD register
1560  *   in one single operation in order to optimize an application.
1561  *
1562  * @note
1563  *   If issued during a scan, the command takes effect after scan completion.
1564  ******************************************************************************/
LESENSE_ScanStop(void)1565 void LESENSE_ScanStop(void)
1566 {
1567   /* Wait for any pending previous write operation to the CMD register to
1568      complete before accessing the CMD register. */
1569   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY) {
1570   }
1571 
1572   /* Stop scanning sensors. */
1573   LESENSE->CMD = LESENSE_CMD_STOP;
1574 
1575   /* Wait for the write operation to the CMD register to complete before
1576      returning. */
1577   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY) {
1578   }
1579 }
1580 
1581 /***************************************************************************//**
1582  * @brief
1583  *   Start the LESENSE decoder.
1584  *
1585  * @note
1586  *   This function will wait for any pending previous write operation to the
1587  *   CMD register to complete before accessing the CMD register. It will also
1588  *   wait for the write operation to the CMD register to complete before
1589  *   returning. Each write operation to the CMD register may take up to 3 LF
1590  *   clock cycles, so expect some delay. The user may implement
1591  *   a separate function to write multiple command bits in the CMD register
1592  *   in one single operation to optimize an application.
1593  ******************************************************************************/
LESENSE_DecoderStart(void)1594 void LESENSE_DecoderStart(void)
1595 {
1596   /* Wait for any pending previous write operation to the CMD register to
1597      complete before accessing the CMD register. */
1598   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY) {
1599   }
1600 
1601   /* Start the decoder. */
1602   LESENSE->CMD = LESENSE_CMD_DECODE;
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 
1610 /***************************************************************************//**
1611  * @brief
1612  *   Clear the result buffer.
1613  *
1614  * @note
1615  *   This function will wait for any pending previous write operation to the
1616  *   CMD register to complete before accessing the CMD register. It will also
1617  *   wait for the write operation to the CMD register to complete before
1618  *   returning. Each write operation to the CMD register may take up to 3 LF
1619  *   clock cycles, so expect some delay. The user may implement
1620  *   a separate function to write multiple command bits in the CMD register
1621  *   in one single operation to optimize an application.
1622  ******************************************************************************/
LESENSE_ResultBufferClear(void)1623 void LESENSE_ResultBufferClear(void)
1624 {
1625   /* Wait for any pending previous write operation to the CMD register to
1626      complete before accessing the CMD register. */
1627   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY) {
1628   }
1629 
1630   LESENSE->CMD = LESENSE_CMD_CLEARBUF;
1631 
1632   /* Wait for the write operation to the CMD register to complete before
1633      returning. */
1634   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY) {
1635   }
1636 
1637 #if defined(_SILICON_LABS_32B_SERIES_2)
1638   while (LESENSE->STATUS & _LESENSE_STATUS_FLUSHING_MASK)
1639     ;
1640 #endif
1641 }
1642 
1643 /***************************************************************************//**
1644  * @brief
1645  *   Reset the LESENSE module.
1646  *
1647  * @details
1648  *   Use this function to reset LESENSE registers.
1649  *
1650  * @note
1651  *   Resetting LESENSE registers is required in each reset or power-on cycle
1652  *   to configure the default values of the RAM mapped LESENSE registers.
1653  *   LESENSE_Reset() can be called on initialization by setting the @p reqReset
1654  *   parameter to true in LESENSE_Init().
1655  *   Starting from Series 2 Config 3 (xG23 and higher), this function leaves
1656  *   LESENSE in the disabled state.
1657  ******************************************************************************/
LESENSE_Reset(void)1658 void LESENSE_Reset(void)
1659 {
1660 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
1661   uint32_t i;
1662 
1663   /* Disable all LESENSE interrupts first. */
1664   LESENSE->IEN = _LESENSE_IEN_RESETVALUE;
1665 
1666   /* Clear all pending LESENSE interrupts. */
1667   LESENSE->IFC = _LESENSE_IFC_MASK;
1668 
1669   /* Stop the decoder. */
1670   LESENSE->DECCTRL |= LESENSE_DECCTRL_DISABLE;
1671 
1672   /* Wait for any pending previous write operation to the CMD register to
1673      complete before accessing the CMD register. */
1674   while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY) {
1675   }
1676 
1677   /* Stop the sensor scan and clear the result buffer. */
1678   LESENSE->CMD = (LESENSE_CMD_STOP | LESENSE_CMD_CLEARBUF);
1679 
1680   /* Reset LESENSE configuration registers */
1681   LESENSE->CTRL      = _LESENSE_CTRL_RESETVALUE;
1682 
1683   LESENSE->PERCTRL   = _LESENSE_PERCTRL_RESETVALUE;
1684   LESENSE->DECCTRL   = _LESENSE_DECCTRL_RESETVALUE;
1685   LESENSE->BIASCTRL  = _LESENSE_BIASCTRL_RESETVALUE;
1686 
1687 #if defined(_LESENSE_EVALCTRL_MASK)
1688   LESENSE->EVALCTRL  = _LESENSE_EVALCTRL_RESETVALUE;
1689   LESENSE->PRSCTRL   = _LESENSE_PRSCTRL_RESETVALUE;
1690 #endif
1691 
1692   LESENSE->CHEN      = _LESENSE_CHEN_RESETVALUE;
1693   LESENSE->IDLECONF  = _LESENSE_IDLECONF_RESETVALUE;
1694   LESENSE->ALTEXCONF = _LESENSE_ALTEXCONF_RESETVALUE;
1695 
1696   /* Reset SENSORSTATE register */
1697   LESENSE->SENSORSTATE = _LESENSE_SENSORSTATE_RESETVALUE;
1698 
1699   /* Disable LESENSE to control GPIO pins. */
1700 #if defined(_LESENSE_ROUTE_MASK)
1701   LESENSE->ROUTE    = _LESENSE_ROUTE_RESETVALUE;
1702 #else
1703   LESENSE->ROUTEPEN = _LESENSE_ROUTEPEN_RESETVALUE;
1704 #endif
1705 
1706   /* Reset all channel configuration registers. */
1707   for (i = 0U; i < LESENSE_NUM_CHANNELS; ++i) {
1708     LESENSE->CH[i].TIMING   = _LESENSE_CH_TIMING_RESETVALUE;
1709     LESENSE->CH[i].INTERACT = _LESENSE_CH_INTERACT_RESETVALUE;
1710     LESENSE->CH[i].EVAL     = _LESENSE_CH_EVAL_RESETVALUE;
1711   }
1712 
1713   /* Reset all decoder state configuration registers. */
1714   for (i = 0U; i < LESENSE_NUM_DECODER_STATES; ++i) {
1715     LESENSE->ST[i].TCONFA = _LESENSE_ST_TCONFA_RESETVALUE;
1716     LESENSE->ST[i].TCONFB = _LESENSE_ST_TCONFB_RESETVALUE;
1717   }
1718   /* Wait for the write operation to complete before
1719      returning. */
1720   while (LESENSE->SYNCBUSY & LESENSE_SYNCBUSY_CMD) {
1721   }
1722 #else
1723   LESENSE->SWRST_SET = LESENSE_SWRST_SWRST;
1724   while (LESENSE->SWRST & _LESENSE_SWRST_RESETTING_MASK) {
1725   }
1726 #endif
1727 }
1728 
1729 /** @} (end addtogroup lesense) */
1730 
1731 #endif /* defined(LESENSE_COUNT) && (LESENSE_COUNT > 0) */
1732