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