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