1 /***************************************************************************//**
2  * @file
3  * @brief Low Energy Sensor (LESENSE) Peripheral API
4  * @author Energy Micro AS
5  * @version 3.0.0
6  *******************************************************************************
7  * @section License
8  * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
9  *******************************************************************************
10  *
11  * Permission is granted to anyone to use this software for any purpose,
12  * including commercial applications, and to alter it and redistribute it
13  * freely, subject to the following restrictions:
14  *
15  * 1. The origin of this software must not be misrepresented; you must not
16  *    claim that you wrote the original software.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  *    misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  *
21  * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
22  * obligation to support this Software. Energy Micro AS is providing the
23  * Software "AS IS", with no express or implied warranties of any kind,
24  * including, but not limited to, any implied warranties of merchantability
25  * or fitness for any particular purpose or warranties against infringement
26  * of any proprietary rights of a third party.
27  *
28  * Energy Micro AS will not be liable for any consequential, incidental, or
29  * special damages, or any other relief, or for any claim by any third party,
30  * arising from your use of this Software.
31  *
32  ******************************************************************************/
33 #include "em_lesense.h"
34 #if defined(LESENSE_COUNT) && (LESENSE_COUNT > 0)
35 #include "em_assert.h"
36 #include "em_bitband.h"
37 #include "em_cmu.h"
38 
39 /***************************************************************************//**
40  * @addtogroup EM_Library
41  * @{
42  ******************************************************************************/
43 
44 /***************************************************************************//**
45  * @addtogroup LESENSE
46  * @brief Low Energy Sensor (LESENSE) Peripheral API
47  * @{
48  ******************************************************************************/
49 
50 /*******************************************************************************
51  **************************   LOCAL FUNCTIONS   ********************************
52  ******************************************************************************/
53 
54 
55 /*******************************************************************************
56  **************************   GLOBAL FUNCTIONS   *******************************
57  ******************************************************************************/
58 
59 /***************************************************************************//**
60  * @brief
61  *   Initialize the LESENSE module.
62  *
63  * @details
64  *   This function configures the main parameters of the LESENSE interface.
65  *   Please refer to the initialization parameter type definition
66  *   (LESENSE_Init_TypeDef) for more details.
67  *
68  * @note
69  *   LESENSE_Init() has been designed for initializing LESENSE once in an
70  *   operation cycle. Be aware of the effects of reconfiguration if using this
71  *   function from multiple sources in your code. This function has not been
72  *   designed to be re-entrant.
73  *   Requesting reset by setting @p reqReset to true is required in each reset
74  *   or power-on cycle in order to configure the default values of the RAM
75  *   mapped LESENSE registers.
76  *   Notice that GPIO pins used by the LESENSE module must be properly
77  *   configured by the user explicitly, in order for the LESENSE to work as
78  *   intended.
79  *   (When configuring pins, one should remember to consider the sequence of
80  *   configuration, in order to avoid unintended pulses/glitches on output
81  *   pins.)
82  *
83  * @param[in] init
84  *   LESENSE initialization structure.
85  *
86  * @param[in] reqReset
87  *   Request to call LESENSE_Reset() first in order to initialize all LESENSE
88  *   registers with the default value.
89  ******************************************************************************/
LESENSE_Init(LESENSE_Init_TypeDef const * init,bool const reqReset)90 void LESENSE_Init(LESENSE_Init_TypeDef const *init, bool const reqReset)
91 {
92   /* Sanity check of initialization values */
93   EFM_ASSERT((uint32_t)init->timeCtrl.startDelay < 4U);
94   EFM_ASSERT((uint32_t)init->perCtrl.dacPresc < 32U);
95 
96   /* Reset LESENSE registers if requested. */
97   if (reqReset)
98   {
99     LESENSE_Reset();
100   }
101 
102   /* Set sensor start delay for each channel. */
103   LESENSE_StartDelaySet((uint32_t)init->timeCtrl.startDelay);
104 
105   /* LESENSE core control configuration.
106    * Set PRS source, SCANCONF register usage strategy, interrupt and
107    * DMA trigger level condition, DMA wakeup condition, bias mode,
108    * enable/disable to sample both ACMPs simultaneously, enable/disable to store
109    * SCANRES in CNT_RES after each scan, enable/disable to always write to the
110    * result buffer, even if it is full, enable/disable LESENSE running in debug
111    * mode. */
112   LESENSE->CTRL = ((uint32_t)init->coreCtrl.prsSel <<
113                    _LESENSE_CTRL_PRSSEL_SHIFT) |
114                   (uint32_t)init->coreCtrl.scanConfSel |
115                   (uint32_t)init->coreCtrl.bufTrigLevel |
116                   (uint32_t)init->coreCtrl.wakeupOnDMA |
117                   ((uint32_t)init->coreCtrl.invACMP0 <<
118                    _LESENSE_CTRL_ACMP0INV_SHIFT) |
119                   ((uint32_t)init->coreCtrl.invACMP1 <<
120                    _LESENSE_CTRL_ACMP1INV_SHIFT) |
121                   ((uint32_t)init->coreCtrl.dualSample <<
122                    _LESENSE_CTRL_DUALSAMPLE_SHIFT) |
123                   ((uint32_t)init->coreCtrl.storeScanRes <<
124                    _LESENSE_CTRL_STRSCANRES_SHIFT) |
125                   ((uint32_t)init->coreCtrl.bufOverWr <<
126                    _LESENSE_CTRL_BUFOW_SHIFT) |
127                   ((uint32_t)init->coreCtrl.debugRun <<
128                    _LESENSE_CTRL_DEBUGRUN_SHIFT);
129 
130   /* Set scan mode in the CTRL register using the provided function, don't
131    * start scanning immediately. */
132   LESENSE_ScanModeSet((LESENSE_ScanMode_TypeDef)init->coreCtrl.scanStart, false);
133 
134   /* LESENSE peripheral control configuration.
135    * Set DAC0 and DAC1 data source, conversion mode, output mode. Set DAC
136    * prescaler and reference. Set ACMP0 and ACMP1 control mode. Set ACMP and DAC
137    * duty cycle (warm up) mode. */
138   LESENSE->PERCTRL = ((uint32_t)init->perCtrl.dacCh0Data <<
139                       _LESENSE_PERCTRL_DACCH0DATA_SHIFT) |
140                      ((uint32_t)init->perCtrl.dacCh0ConvMode <<
141                       _LESENSE_PERCTRL_DACCH0CONV_SHIFT) |
142                      ((uint32_t)init->perCtrl.dacCh0OutMode <<
143                       _LESENSE_PERCTRL_DACCH0OUT_SHIFT) |
144                      ((uint32_t)init->perCtrl.dacCh1Data <<
145                       _LESENSE_PERCTRL_DACCH1DATA_SHIFT) |
146                      ((uint32_t)init->perCtrl.dacCh1ConvMode <<
147                       _LESENSE_PERCTRL_DACCH1CONV_SHIFT) |
148                      ((uint32_t)init->perCtrl.dacCh1OutMode <<
149                       _LESENSE_PERCTRL_DACCH1OUT_SHIFT) |
150                      ((uint32_t)init->perCtrl.dacPresc <<
151                       _LESENSE_PERCTRL_DACPRESC_SHIFT) |
152                      (uint32_t)init->perCtrl.dacRef |
153                      ((uint32_t)init->perCtrl.acmp0Mode <<
154                       _LESENSE_PERCTRL_ACMP0MODE_SHIFT) |
155                      ((uint32_t)init->perCtrl.acmp1Mode <<
156                       _LESENSE_PERCTRL_ACMP1MODE_SHIFT) |
157                      (uint32_t)init->perCtrl.warmupMode;
158 
159   /* LESENSE decoder general control configuration.
160    * Set decoder input source, select PRS input for decoder bits.
161    * Enable/disable the decoder to check the present state.
162    * Enable/disable decoder to channel interrupt mapping.
163    * Enable/disable decoder hysteresis on PRS output.
164    * Enable/disable decoder hysteresis on count events.
165    * Enable/disable decoder hysteresis on interrupt requests.
166    * Enable/disable count mode on LESPRS0 and LESPRS1. */
167   LESENSE->DECCTRL = (uint32_t)init->decCtrl.decInput |
168                      ((uint32_t)init->decCtrl.prsChSel0 <<
169                       _LESENSE_DECCTRL_PRSSEL0_SHIFT) |
170                      ((uint32_t)init->decCtrl.prsChSel1 <<
171                       _LESENSE_DECCTRL_PRSSEL1_SHIFT) |
172                      ((uint32_t)init->decCtrl.prsChSel2 <<
173                       _LESENSE_DECCTRL_PRSSEL2_SHIFT) |
174                      ((uint32_t)init->decCtrl.prsChSel3 <<
175                       _LESENSE_DECCTRL_PRSSEL3_SHIFT) |
176                      ((uint32_t)init->decCtrl.chkState <<
177                       _LESENSE_DECCTRL_ERRCHK_SHIFT) |
178                      ((uint32_t)init->decCtrl.intMap <<
179                       _LESENSE_DECCTRL_INTMAP_SHIFT) |
180                      ((uint32_t)init->decCtrl.hystPRS0 <<
181                       _LESENSE_DECCTRL_HYSTPRS0_SHIFT) |
182                      ((uint32_t)init->decCtrl.hystPRS1 <<
183                       _LESENSE_DECCTRL_HYSTPRS1_SHIFT) |
184                      ((uint32_t)init->decCtrl.hystPRS2 <<
185                       _LESENSE_DECCTRL_HYSTPRS2_SHIFT) |
186                      ((uint32_t)init->decCtrl.hystIRQ <<
187                       _LESENSE_DECCTRL_HYSTIRQ_SHIFT) |
188                      ((uint32_t)init->decCtrl.prsCount <<
189                       _LESENSE_DECCTRL_PRSCNT_SHIFT);
190 
191   /* Set initial LESENSE decoder state. */
192   LESENSE_DecoderStateSet((uint32_t)init->decCtrl.initState);
193 
194   /* LESENSE bias control configuration. */
195   LESENSE->BIASCTRL = (uint32_t)init->coreCtrl.biasMode;
196 }
197 
198 
199 /***************************************************************************//**
200  * @brief
201  *   Set scan frequency for periodic scanning.
202  *
203  * @details
204  *   This function only applies to LESENSE if period counter is being used as
205  *   a trigger for scan start.
206  *   The calculation is based on the following formula:
207  *   Fscan = LFACLKles / ((1+PCTOP)*2^PCPRESC)
208  *
209  * @note
210  *   Note that the calculation does not necessarily result in the requested
211  *   scan frequency due to integer division. Check the return value for the
212  *   resulted scan frequency.
213  *
214  * @param[in] refFreq
215  *   Select reference LFACLK clock frequency in Hz. If set to 0, the current
216  *   clock frequency is being used as a reference.
217  *
218  * @param[in] scanFreq
219  *   Set the desired scan frequency in Hz.
220  *
221  * @return
222  *   Frequency in Hz calculated and set by this function. Users can use this to
223  *   compare the requested and set values.
224  ******************************************************************************/
LESENSE_ScanFreqSet(uint32_t refFreq,uint32_t const scanFreq)225 uint32_t LESENSE_ScanFreqSet(uint32_t refFreq, uint32_t const scanFreq)
226 {
227   uint32_t tmp;
228   uint32_t pcPresc = 0UL;  /* Period counter prescaler. */
229   uint32_t clkDiv  = 1UL;  /* Clock divisor value (2^pcPresc). */
230   uint32_t pcTop   = 63UL; /* Period counter top value (max. 63). */
231   uint32_t calcScanFreq;   /* Variable for testing the calculation algorithm. */
232 
233 
234   /* If refFreq is set to 0, the currently configured reference clock is
235    * assumed. */
236   if (!refFreq)
237   {
238     refFreq = CMU_ClockFreqGet(cmuClock_LESENSE);
239   }
240 
241   /* Max. value of pcPresc is 128, thus using reference frequency less than
242    * 33554431Hz (33.554431MHz), the frequency calculation in the while loop
243    * below will not overflow. */
244   EFM_ASSERT(refFreq < ((uint32_t)UINT32_MAX / 128UL));
245 
246   /* Sanity check of scan frequency value. */
247   EFM_ASSERT((scanFreq > 0U) && (scanFreq <= refFreq));
248 
249   /* Calculate the minimum necessary prescaler value in order to provide the
250    * biggest possible resolution for setting scan frequency.
251    * Maximum number of calculation cycles is 7 (value of lesenseClkDiv_128). */
252   while ((refFreq / ((uint32_t)scanFreq * clkDiv) > (pcTop + 1UL)) &&
253          (pcPresc < lesenseClkDiv_128))
254   {
255     ++pcPresc;
256     clkDiv = (uint32_t)1UL << pcPresc;
257   }
258 
259   /* Calculate pcTop value. */
260   pcTop = ((uint32_t)refFreq / ((uint32_t)scanFreq * clkDiv)) - 1UL;
261 
262   /* Clear current PCPRESC and PCTOP settings. Be aware of the effect of
263    * non-atomic Read-Modify-Write on LESENSE->TIMCRTL. */
264   tmp = LESENSE->TIMCTRL & (~(_LESENSE_TIMCTRL_PCPRESC_MASK)&
265                             ~(_LESENSE_TIMCTRL_PCTOP_MASK));
266 
267   /* Set new values in tmp while reserving other settings. */
268   tmp |= ((uint32_t)pcPresc << _LESENSE_TIMCTRL_PCPRESC_SHIFT) |
269          ((uint32_t)pcTop << _LESENSE_TIMCTRL_PCTOP_SHIFT);
270 
271   /* Set values in LESENSE_TIMCTRL register. */
272   LESENSE->TIMCTRL = tmp;
273 
274   /* For testing the calculation algorithm. */
275   calcScanFreq = ((uint32_t)refFreq / ((uint32_t)(1UL + pcTop) * clkDiv));
276 
277   return calcScanFreq;
278 }
279 
280 
281 /***************************************************************************//**
282  * @brief
283  *   Set scan mode of the LESENSE channels.
284  *
285  * @details
286  *   This function configures how the scan start is being triggered. It can be
287  *   used for re-configuring the scan mode while running the application but it
288  *   is also used by LESENSE_Init() for initialization.
289  *
290  * @note
291  *   Users can configure the scan mode by LESENSE_Init() function, but only with
292  *   a significant overhead. This simple function serves the purpose of
293  *   controlling this parameter after the channel has been configured.
294  *   Please be aware the effects of the non-atomic Read-Modify-Write cycle!
295  *
296  * @param[in] scanMode
297  *   Select where to map LESENSE alternate excitation channels.
298  *   @li lesenseScanStartPeriodic - New scan is started each time the period
299  *                                  counter overflows.
300  *   @li lesenseScanStartOneShot - Single scan is performed when
301  *                                 LESENSE_ScanStart() is called.
302  *   @li lesenseScanStartPRS - New scan is triggered by pulse on PRS channel.
303  *
304  * @param[in] start
305  *   If true, LESENSE_ScanStart() is immediately issued after configuration.
306  ******************************************************************************/
LESENSE_ScanModeSet(LESENSE_ScanMode_TypeDef const scanMode,bool const start)307 void LESENSE_ScanModeSet(LESENSE_ScanMode_TypeDef const scanMode,
308                          bool const start)
309 {
310   uint32_t tmp; /* temporary storage of the CTRL register value */
311 
312 
313   /* Save the CTRL register value to tmp.
314    * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
315   tmp = LESENSE->CTRL & ~(_LESENSE_CTRL_SCANMODE_MASK);
316   /* Setting the requested scanMode to the CTRL register. Casting signed int
317    * (enum) to unsigned long (uint32_t). */
318   tmp |= (uint32_t)scanMode;
319 
320   /* Write the new value to the CTRL register. */
321   LESENSE->CTRL = tmp;
322 
323   /* Start sensor scanning if requested. */
324   if (start)
325   {
326     LESENSE_ScanStart();
327   }
328 }
329 
330 
331 /***************************************************************************//**
332  * @brief
333  *   Set start delay of sensor interaction on each channel.
334  *
335  * @details
336  *   This function sets start delay of sensor interaction on each channel.
337  *   It can be used for adjusting the start delay while running the application
338  *   but it is also used by LESENSE_Init() for initialization.
339  *
340  * @note
341  *   Users can configure the start delay by LESENSE_Init() function, but only
342  *   with a significant overhead. This simple function serves the purpose of
343  *   controlling this parameter after the channel has been configured.
344  *   Please be aware the effects of the non-atomic Read-Modify-Write cycle!
345  *
346  * @param[in] startDelay
347  *   Number of LFACLK cycles to delay. Valid range: 0-3 (2 bit).
348  ******************************************************************************/
LESENSE_StartDelaySet(uint8_t const startDelay)349 void LESENSE_StartDelaySet(uint8_t const startDelay)
350 {
351   uint32_t tmp; /* temporary storage of the TIMCTRL register value */
352 
353 
354   /* Sanity check of startDelay. */
355   EFM_ASSERT(startDelay < 4U);
356 
357   /* Save the TIMCTRL register value to tmp.
358    * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
359   tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_STARTDLY_MASK);
360   /* Setting the requested startDelay to the TIMCTRL register. */
361   tmp |= (uint32_t)startDelay << _LESENSE_TIMCTRL_STARTDLY_SHIFT;
362 
363   /* Write the new value to the TIMCTRL register. */
364   LESENSE->TIMCTRL = tmp;
365 }
366 
367 
368 /***************************************************************************//**
369  * @brief
370  *   Set clock division for LESENSE timers.
371  *
372  * @details
373  *   Use this function to configure the clock division for the LESENSE timers
374  *   used for excitation timing.
375  *   The division setting is global, but the clock source can be selected for
376  *   each channel using LESENSE_ChannelConfig() function, please refer to the
377  *   documentation of it for more details.
378  *
379  * @note
380  *   If AUXHFRCO is used for excitation timing, LFACLK can not exceed 500kHz.
381  *   LFACLK can not exceed 50kHz if the ACMP threshold level (ACMPTHRES) is not
382  *   equal for all channels.
383  *
384  * @param[in] clk
385  *   Select clock to prescale.
386  *    @li lesenseClkHF - set AUXHFRCO clock divisor for HF timer.
387  *    @li lesenseClkLF - set LFACLKles clock divisor for LF timer.
388  *
389  * @param[in] clkDiv
390  *   Clock divisor value. Valid range depends on the @p clk value.
391  ******************************************************************************/
LESENSE_ClkDivSet(LESENSE_ChClk_TypeDef const clk,LESENSE_ClkPresc_TypeDef const clkDiv)392 void LESENSE_ClkDivSet(LESENSE_ChClk_TypeDef const clk,
393                        LESENSE_ClkPresc_TypeDef const clkDiv)
394 {
395   uint32_t tmp;
396 
397 
398   /* Select clock to prescale */
399   switch (clk)
400   {
401   case lesenseClkHF:
402   {
403     /* Sanity check of clock divisor for HF clock. */
404     EFM_ASSERT((uint32_t)clkDiv <= lesenseClkDiv_8);
405 
406     /* Clear current AUXPRESC settings. */
407     tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_AUXPRESC_MASK);
408 
409     /* Set new values in tmp while reserving other settings. */
410     tmp |= ((uint32_t)clkDiv << _LESENSE_TIMCTRL_AUXPRESC_SHIFT);
411 
412     /* Set values in LESENSE_TIMCTRL register. */
413     LESENSE->TIMCTRL = tmp;
414   }
415   break;
416 
417   case lesenseClkLF:
418   {
419     /* Clear current LFPRESC settings. */
420     tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_LFPRESC_MASK);
421 
422     /* Set new values in tmp while reserving other settings. */
423     tmp |= ((uint32_t)clkDiv << _LESENSE_TIMCTRL_LFPRESC_SHIFT);
424 
425     /* Set values in LESENSE_TIMCTRL register. */
426     LESENSE->TIMCTRL = tmp;
427   }
428   break;
429 
430   default:
431   {
432     EFM_ASSERT(0);
433   }
434   break;
435   }
436 }
437 
438 
439 /***************************************************************************//**
440  * @brief
441  *   Configure all (16) LESENSE sensor channels.
442  *
443  * @details
444  *   This function configures all the sensor channels of LESENSE interface.
445  *   Please refer to the configuration parameter type definition
446  *   (LESENSE_ChAll_TypeDef) for more details.
447  *
448  * @note
449  *   Channels can be configured individually using LESENSE_ChannelConfig()
450  *   function.
451  *   Notice that pins used by the LESENSE module must be properly configured
452  *   by the user explicitly, in order for the LESENSE to work as intended.
453  *   (When configuring pins, one should remember to consider the sequence of
454  *   configuration, in order to avoid unintended pulses/glitches on output
455  *   pins.)
456  *
457  * @param[in] confChAll
458  *   Configuration structure for all (16) LESENSE sensor channels.
459  ******************************************************************************/
LESENSE_ChannelAllConfig(LESENSE_ChAll_TypeDef const * confChAll)460 void LESENSE_ChannelAllConfig(LESENSE_ChAll_TypeDef const *confChAll)
461 {
462   uint32_t i;
463 
464 
465   /* Iterate through all the 16 channels */
466   for (i = 0U; i < 16U; ++i)
467   {
468     /* Configure scan channels. */
469     LESENSE_ChannelConfig(&confChAll->Ch[i], i);
470   }
471 }
472 
473 
474 /***************************************************************************//**
475  * @brief
476  *   Configure a single LESENSE sensor channel.
477  *
478  * @details
479  *   This function configures a single sensor channel of the LESENSE interface.
480  *   Please refer to the configuration parameter type definition
481  *   (LESENSE_ChDesc_TypeDef) for more details.
482  *
483  * @note
484  *   This function has been designed to minimize the effects of sensor channel
485  *   reconfiguration while LESENSE is in operation, however one shall be aware
486  *   of these effects and the right timing of calling this function.
487  *   Parameter @p useAltEx must be true in the channel configuration in order to
488  *   use alternate excitation pins.
489  *
490  * @param[in] confCh
491  *   Configuration structure for a single LESENSE sensor channel.
492  *
493  * @param[in] chIdx
494  *   Channel index to configure (0-15).
495  ******************************************************************************/
LESENSE_ChannelConfig(LESENSE_ChDesc_TypeDef const * confCh,uint32_t const chIdx)496 void LESENSE_ChannelConfig(LESENSE_ChDesc_TypeDef const *confCh,
497                            uint32_t const chIdx)
498 {
499   uint32_t tmp; /* Service variable. */
500 
501 
502   /* Sanity check of configuration parameters */
503   EFM_ASSERT(chIdx < 16U);
504   EFM_ASSERT(confCh->exTime < 64U);
505   EFM_ASSERT(confCh->sampleDelay < 128U);
506   EFM_ASSERT(confCh->measDelay < 128U);
507   /* Not a complete assert, as the max. value of acmpThres depends on other
508    * configuration parameters, check the parameter description of acmpThres for
509    * for more details! */
510   EFM_ASSERT(confCh->acmpThres < 4096U);
511   EFM_ASSERT(!(confCh->chPinExMode == lesenseChPinExDACOut &&
512                (chIdx != 2U) && (chIdx != 3U) && (chIdx != 4U) && (chIdx != 5U)));
513   EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh1 &&
514                ((chIdx != 12U) && (chIdx != 13U) && (chIdx != 14U) && (chIdx != 15U))));
515   EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh0 &&
516                ((chIdx != 0U) && (chIdx != 1U) && (chIdx != 2U) && (chIdx != 3U))));
517 
518 
519   /* Configure chIdx setup in LESENSE idle phase.
520    * Read-modify-write in order to support reconfiguration during LESENSE
521    * operation. */
522   tmp               = (LESENSE->IDLECONF & ~((uint32_t)0x3UL << (chIdx * 2UL)));
523   tmp              |= ((uint32_t)confCh->chPinIdleMode << (chIdx * 2UL));
524   LESENSE->IDLECONF = tmp;
525 
526   /* Channel specific timing configuration on scan channel chIdx.
527    * Set excitation time, sampling delay, measurement delay. */
528   LESENSE_ChannelTimingSet(chIdx,
529                            (uint32_t)confCh->exTime,
530                            (uint32_t)confCh->sampleDelay,
531                            (uint32_t)confCh->measDelay);
532 
533   /* Channel specific configuration of clocks, sample mode, excitation pin mode
534    * alternate excitation usage and interrupt mode on scan channel chIdx in
535    * LESENSE_CHchIdx_INTERACT. */
536   LESENSE->CH[chIdx].INTERACT = ((uint32_t)confCh->exClk <<
537                                  _LESENSE_CH_INTERACT_EXCLK_SHIFT) |
538                                 ((uint32_t)confCh->sampleClk <<
539                                  _LESENSE_CH_INTERACT_SAMPLECLK_SHIFT) |
540                                 (uint32_t)confCh->sampleMode |
541                                 (uint32_t)confCh->intMode |
542                                 (uint32_t)confCh->chPinExMode |
543                                 ((uint32_t)confCh->useAltEx <<
544                                  _LESENSE_CH_INTERACT_ALTEX_SHIFT);
545 
546   /* Configure channel specific counter comparison mode, optional result
547    * forwarding to decoder, optional counter value storing and optional result
548    * inverting on scan channel chIdx in LESENSE_CHchIdx_EVAL. */
549   LESENSE->CH[chIdx].EVAL = (uint32_t)confCh->compMode |
550                             ((uint32_t)confCh->shiftRes <<
551                              _LESENSE_CH_EVAL_DECODE_SHIFT) |
552                             ((uint32_t)confCh->storeCntRes <<
553                              _LESENSE_CH_EVAL_STRSAMPLE_SHIFT) |
554                             ((uint32_t)confCh->invRes <<
555                              _LESENSE_CH_EVAL_SCANRESINV_SHIFT);
556 
557   /* Configure analog comparator (ACMP) threshold and decision threshold for
558    * counter separately with the function provided for that. */
559   LESENSE_ChannelThresSet(chIdx,
560                          (uint32_t)confCh->acmpThres,
561                          (uint32_t)confCh->cntThres);
562 
563   /* Enable/disable interrupts on channel.
564    * Note: BITBAND_Peripheral() function is used for setting/clearing single
565    * bit peripheral register bitfields. Read the function description in
566    * efm32_bitband.h for more details. */
567   BITBAND_Peripheral(&(LESENSE->IEN),
568                      (uint32_t)chIdx,
569                      (uint32_t)confCh->enaInt);
570 
571   /* Enable/disable CHchIdx pin. */
572   BITBAND_Peripheral(&(LESENSE->ROUTE),
573                      (uint32_t)chIdx,
574                      (uint32_t)confCh->enaPin);
575 
576   /* Enable/disable scan channel chIdx. */
577   BITBAND_Peripheral(&(LESENSE->CHEN),
578                      (uint32_t)chIdx,
579                      (uint32_t)confCh->enaScanCh);
580 }
581 
582 
583 /***************************************************************************//**
584  * @brief
585  *   Configure the LESENSE alternate excitation pins.
586  *
587  * @details
588  *   This function configures the alternate excitation channels of the LESENSE
589  *   interface. Please refer to the configuration parameter type definition
590  *   (LESENSE_ConfAltEx_TypeDef) for more details.
591  *
592  * @note
593  *   Parameter @p useAltEx must be true in the channel configuration structrure
594  *   (LESENSE_ChDesc_TypeDef) in order to use alternate excitation pins on the
595  *   channel.
596  *
597  * @param[in] confAltEx
598  *   Configuration structure for LESENSE alternate excitation pins.
599  ******************************************************************************/
LESENSE_AltExConfig(LESENSE_ConfAltEx_TypeDef const * confAltEx)600 void LESENSE_AltExConfig(LESENSE_ConfAltEx_TypeDef const *confAltEx)
601 {
602   uint32_t i;
603   uint32_t tmp;
604 
605 
606   /* Configure alternate excitation mapping.
607    * Atomic read-modify-write using BITBAND_Peripheral function in order to
608    * support reconfiguration during LESENSE operation. */
609   BITBAND_Peripheral(&(LESENSE->CTRL),
610                      _LESENSE_CTRL_ALTEXMAP_SHIFT,
611                      (uint32_t)confAltEx->altExMap);
612 
613   /* Iterate through all the 8 alternate excitation channels */
614   for (i = 0U; i < 8U; ++i)
615   {
616     /* Enable/disable alternate excitation pin i.
617      * Atomic read-modify-write using BITBAND_Peripheral function in order to
618      * support reconfiguration during LESENSE operation. */
619     BITBAND_Peripheral(&(LESENSE->ROUTE),
620                        (16UL + i),
621                        (uint32_t)confAltEx->AltEx[i].enablePin);
622 
623     /* Setup the idle phase state of alternate excitation pin i.
624      * Read-modify-write in order to support reconfiguration during LESENSE
625      * operation. */
626     tmp                = (LESENSE->ALTEXCONF & ~((uint32_t)0x3UL << (i * 2UL)));
627     tmp               |= ((uint32_t)confAltEx->AltEx[i].idleConf << (i * 2UL));
628     LESENSE->ALTEXCONF = tmp;
629 
630     /* Enable/disable always excite on channel i */
631     BITBAND_Peripheral(&(LESENSE->ALTEXCONF),
632                        (16UL + i),
633                        (uint32_t)confAltEx->AltEx[i].alwaysEx);
634   }
635 }
636 
637 
638 /***************************************************************************//**
639  * @brief
640  *   Enable/disable LESENSE scan channel and the pin assigned to it.
641  *
642  * @details
643  *   Use this function to enable/disable a selected LESENSE scan channel and the
644  *   pin assigned to.
645  *
646  * @note
647  *   Users can enable/disable scan channels and the channel pin by
648  *   LESENSE_ChannelConfig() function, but only with a significant overhead.
649  *   This simple function serves the purpose of controlling these parameters
650  *   after the channel has been configured.
651  *
652  * @param[in] chIdx
653  *   Identifier of the scan channel. Valid range: 0-15.
654  *
655  * @param[in] enaScanCh
656  *   Enable/disable the selected scan channel by setting this parameter to
657  *   true/false respectively.
658  *
659  * @param[in] enaPin
660  *   Enable/disable the pin assigned to the channel selected by @p chIdx.
661  ******************************************************************************/
LESENSE_ChannelEnable(uint8_t const chIdx,bool const enaScanCh,bool const enaPin)662 void LESENSE_ChannelEnable(uint8_t const chIdx,
663                            bool const enaScanCh,
664                            bool const enaPin)
665 {
666   /* Enable/disable the assigned pin of scan channel chIdx.
667    * Note: BITBAND_Peripheral() function is used for setting/clearing single
668    * bit peripheral register bitfields. Read the function description in
669    * efm32_bitband.h for more details. */
670   BITBAND_Peripheral(&(LESENSE->ROUTE),
671                      (uint32_t)chIdx,
672                      (uint32_t)enaPin);
673 
674   /* Enable/disable scan channel chIdx. */
675   BITBAND_Peripheral(&(LESENSE->CHEN),
676                      (uint32_t)chIdx,
677                      (uint32_t)enaScanCh);
678 }
679 
680 
681 /***************************************************************************//**
682  * @brief
683  *   Enable/disable LESENSE scan channel and the pin assigned to it.
684  *
685  * @details
686  *   Use this function to enable/disable LESENSE scan channels and the pins
687  *   assigned to them using a mask.
688  *
689  * @note
690  *   Users can enable/disable scan channels and channel pins by using
691  *   LESENSE_ChannelAllConfig() function, but only with a significant overhead.
692  *   This simple function serves the purpose of controlling these parameters
693  *   after the channel has been configured.
694  *
695  * @param[in] chMask
696  *   Set the corresponding bit to 1 to enable, 0 to disable the selected scan
697  *   channel.
698  *
699  * @param[in] pinMask
700  *   Set the corresponding bit to 1 to enable, 0 to disable the pin on selected
701  *   channel.
702  ******************************************************************************/
LESENSE_ChannelEnableMask(uint16_t chMask,uint16_t pinMask)703 void LESENSE_ChannelEnableMask(uint16_t chMask, uint16_t pinMask)
704 {
705   /* Enable/disable all channels at once according to the mask. */
706   LESENSE->CHEN = chMask;
707   /* Enable/disable all channel pins at once according to the mask. */
708   LESENSE->ROUTE = pinMask;
709 }
710 
711 
712 /***************************************************************************//**
713  * @brief
714  *   Set LESENSE channel timing parameters.
715  *
716  * @details
717  *   Use this function to set timing parameters on a selected LESENSE channel.
718  *
719  * @note
720  *   Users can configure the channel timing parameters by
721  *   LESENSE_ChannelConfig() function, but only with a significant overhead.
722  *   This simple function serves the purpose of controlling these parameters
723  *   after the channel has been configured.
724  *
725  * @param[in] chIdx
726  *   Identifier of the scan channel. Valid range: 0-15.
727  *
728  * @param[in] exTime
729  *   Excitation time on chIdx. Excitation will last exTime+1 excitation clock
730  *   cycles. Valid range: 0-63 (6 bits).
731  *
732  * @param[in] sampleDelay
733  *   Sample delay on chIdx. Sampling will occur after sampleDelay+1 sample clock
734  *   cycles. Valid range: 0-127 (7 bits).
735  *
736  * @param[in] measDelay
737  *   Measure delay on chIdx. Sensor measuring is delayed for measDelay+1
738  *   excitation clock cycles. Valid range: 0-127 (7 bits).
739  ******************************************************************************/
LESENSE_ChannelTimingSet(uint8_t const chIdx,uint8_t const exTime,uint8_t const sampleDelay,uint8_t const measDelay)740 void LESENSE_ChannelTimingSet(uint8_t const chIdx,
741                               uint8_t const exTime,
742                               uint8_t const sampleDelay,
743                               uint8_t const measDelay)
744 {
745   /* Sanity check of parameters. */
746   EFM_ASSERT(exTime < 64U);
747   EFM_ASSERT(sampleDelay < 128U);
748   EFM_ASSERT(measDelay < 128U);
749 
750   /* Channel specific timing configuration on scan channel chIdx.
751    * Setting excitation time, sampling delay, measurement delay. */
752   LESENSE->CH[chIdx].TIMING = ((uint32_t)exTime <<
753                                _LESENSE_CH_TIMING_EXTIME_SHIFT) |
754                               ((uint32_t)sampleDelay <<
755                                _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT) |
756                               ((uint32_t)measDelay <<
757                                _LESENSE_CH_TIMING_MEASUREDLY_SHIFT);
758 }
759 
760 
761 /***************************************************************************//**
762  * @brief
763  *   Set LESENSE channel threshold parameters.
764  *
765  * @details
766  *   Use this function to set threshold parameters on a selected LESENSE
767  *   channel.
768  *
769  * @note
770  *   Users can configure the channel threshold parameters by
771  *   LESENSE_ChannelConfig() function, but only with a significant overhead.
772  *   This simple function serves the purpose of controlling these parameters
773  *   after the channel has been configured.
774  *
775  * @param[in] chIdx
776  *   Identifier of the scan channel. Valid range: 0-15.
777  *
778  * @param[in] acmpThres
779  *   ACMP threshold.
780  *   @li If perCtrl.dacCh0Data or perCtrl.dacCh1Data is set to
781  *   #lesenseDACIfData, acmpThres defines the 12-bit DAC data in the
782  *   corresponding data register of the DAC interface (DACn_CH0DATA and
783  *   DACn_CH1DATA). In this case, the valid range is: 0-4095 (12 bits).
784  *
785  *   @li If perCtrl.dacCh0Data or perCtrl.dacCh1Data is set to
786  *   #lesenseACMPThres, acmpThres defines the 6-bit Vdd scaling factor of ACMP
787  *   negative input (VDDLEVEL in ACMP_INPUTSEL register). In this case, the
788  *   valid range is: 0-63 (6 bits).
789  *
790  * @param[in] cntThres
791  *   Decision threshold for counter comparison.
792  *   Valid range: 0-65535 (16 bits).
793  ******************************************************************************/
LESENSE_ChannelThresSet(uint8_t const chIdx,uint16_t const acmpThres,uint16_t const cntThres)794 void LESENSE_ChannelThresSet(uint8_t const chIdx,
795                              uint16_t const acmpThres,
796                              uint16_t const cntThres)
797 {
798   uint32_t tmp; /* temporary storage */
799 
800 
801   /* Sanity check for acmpThres only, cntThres is 16bit value. */
802   EFM_ASSERT(acmpThres < 4096U);
803   /* Sanity check for LESENSE channel id. */
804   EFM_ASSERT(chIdx < 16);
805 
806   /* Save the INTERACT register value of channel chIdx to tmp.
807    * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
808   tmp = LESENSE->CH[chIdx].INTERACT & ~(_LESENSE_CH_INTERACT_ACMPTHRES_MASK);
809   /* Set the ACMP threshold value to the INTERACT register of channel chIdx. */
810   tmp |= (uint32_t)acmpThres << _LESENSE_CH_INTERACT_ACMPTHRES_SHIFT;
811   /* Write the new value to the INTERACT register. */
812   LESENSE->CH[chIdx].INTERACT = tmp;
813 
814   /* Save the EVAL register value of channel chIdx to tmp.
815    * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
816   tmp = LESENSE->CH[chIdx].EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK);
817   /* Set the counter threshold value to the INTERACT register of channel chIdx. */
818   tmp |= (uint32_t)cntThres << _LESENSE_CH_EVAL_COMPTHRES_SHIFT;
819   /* Write the new value to the EVAL register. */
820   LESENSE->CH[chIdx].EVAL = tmp;
821 }
822 
823 
824 /***************************************************************************//**
825  * @brief
826  *   Configure all LESENSE decoder states.
827  *
828  * @details
829  *   This function configures all the decoder states of the LESENSE interface.
830  *   Please refer to the configuration parameter type definition
831  *   (LESENSE_DecStAll_TypeDef) for more details.
832  *
833  * @note
834  *   Decoder states can be configured individually using
835  *   LESENSE_DecoderStateConfig() function.
836  *
837  * @param[in] confDecStAll
838  *   Configuration structure for all (16) LESENSE decoder states.
839  ******************************************************************************/
LESENSE_DecoderStateAllConfig(LESENSE_DecStAll_TypeDef const * confDecStAll)840 void LESENSE_DecoderStateAllConfig(LESENSE_DecStAll_TypeDef const *confDecStAll)
841 {
842   uint32_t i;
843 
844 
845   /* Iterate through all the 16 decoder states. */
846   for (i = 0U; i < 16U; ++i)
847   {
848     /* Configure decoder state i. */
849     LESENSE_DecoderStateConfig(&confDecStAll->St[i], i);
850   }
851 }
852 
853 
854 /***************************************************************************//**
855  * @brief
856  *   Configure a single LESENSE decoder state.
857  *
858  * @details
859  *   This function configures a single decoder state of the LESENSE interface.
860  *   Please refer to the configuration parameter type definition
861  *   (LESENSE_DecStDesc_TypeDef) for more details.
862  *
863  * @param[in] confDecSt
864  *   Configuration structure for a single LESENSE decoder state.
865  *
866  * @param[in] decSt
867  *   Decoder state index to configure (0-15).
868  ******************************************************************************/
LESENSE_DecoderStateConfig(LESENSE_DecStDesc_TypeDef const * confDecSt,uint32_t const decSt)869 void LESENSE_DecoderStateConfig(LESENSE_DecStDesc_TypeDef const *confDecSt,
870                                 uint32_t const decSt)
871 {
872   /* Sanity check of configuration parameters */
873   EFM_ASSERT(decSt < 16U);
874   EFM_ASSERT((uint32_t)confDecSt->confA.compMask < 16U);
875   EFM_ASSERT((uint32_t)confDecSt->confA.compVal < 16U);
876   EFM_ASSERT((uint32_t)confDecSt->confA.nextState < 16U);
877   EFM_ASSERT((uint32_t)confDecSt->confB.compMask < 16U);
878   EFM_ASSERT((uint32_t)confDecSt->confB.compVal < 16U);
879   EFM_ASSERT((uint32_t)confDecSt->confB.nextState < 16U);
880 
881   /* Configure state descriptor A (LESENSE_STi_TCONFA) for decoder state i.
882    * Setting sensor compare value, sensor mask, next state index,
883    * transition action, interrupt flag option and state descriptor chaining
884    * configurations. */
885   LESENSE->ST[decSt].TCONFA = (uint32_t)confDecSt->confA.prsAct |
886                               ((uint32_t)confDecSt->confA.compMask <<
887                                _LESENSE_ST_TCONFA_MASK_SHIFT) |
888                               ((uint32_t)confDecSt->confA.compVal <<
889                                _LESENSE_ST_TCONFA_COMP_SHIFT) |
890                               ((uint32_t)confDecSt->confA.nextState <<
891                                _LESENSE_ST_TCONFA_NEXTSTATE_SHIFT) |
892                               ((uint32_t)confDecSt->confA.setInt <<
893                                _LESENSE_ST_TCONFA_SETIF_SHIFT) |
894                               ((uint32_t)confDecSt->chainDesc <<
895                                _LESENSE_ST_TCONFA_CHAIN_SHIFT);
896 
897   /* Configure state descriptor Bi (LESENSE_STi_TCONFB).
898    * Setting sensor compare value, sensor mask, next state index, transition
899    * action and interrupt flag option configurations. */
900   LESENSE->ST[decSt].TCONFB = (uint32_t)confDecSt->confB.prsAct |
901                               ((uint32_t)confDecSt->confB.compMask <<
902                                _LESENSE_ST_TCONFB_MASK_SHIFT) |
903                               ((uint32_t)confDecSt->confB.compVal <<
904                                _LESENSE_ST_TCONFB_COMP_SHIFT) |
905                               ((uint32_t)confDecSt->confB.nextState <<
906                                _LESENSE_ST_TCONFB_NEXTSTATE_SHIFT) |
907                               ((uint32_t)confDecSt->confB.setInt <<
908                                _LESENSE_ST_TCONFB_SETIF_SHIFT);
909 }
910 
911 
912 /***************************************************************************//**
913  * @brief
914  *   Set LESENSE decoder state.
915  *
916  * @details
917  *   This function can be used for setting the initial state of the LESENSE
918  *   decoder.
919  *
920  * @note
921  *   Make sure the LESENSE decoder state is initialized by this function before
922  *   enabling the decoder!
923  *
924  * @param[in] decSt
925  *   Decoder state to set as current state. Valid range: 0-15
926  ******************************************************************************/
LESENSE_DecoderStateSet(uint32_t decSt)927 void LESENSE_DecoderStateSet(uint32_t decSt)
928 {
929   EFM_ASSERT(decSt < 16U);
930 
931   LESENSE->DECSTATE = decSt & _LESENSE_DECSTATE_DECSTATE_MASK;
932 }
933 
934 
935 /***************************************************************************//**
936  * @brief
937  *   Get the current state of the LESENSE decoder.
938  *
939  * @return
940  *   This function returns the value of LESENSE_DECSTATE register that
941  *   represents the current state of the LESENSE decoder.
942  ******************************************************************************/
LESENSE_DecoderStateGet(void)943 uint32_t LESENSE_DecoderStateGet(void)
944 {
945   return LESENSE->DECSTATE & _LESENSE_DECSTATE_DECSTATE_MASK;
946 }
947 
948 
949 /***************************************************************************//**
950  * @brief
951  *   Reset the LESENSE module.
952  *
953  * @details
954  *   Use this function to reset the LESENSE registers.
955  *
956  * @note
957  *   Resetting LESENSE registers is required in each reset or power-on cycle in
958  *   order to configure the default values of the RAM mapped LESENSE registers.
959  *   LESENSE_Reset() can be called on initialization by setting the @p reqReset
960  *   parameter to true in LESENSE_Init().
961  ******************************************************************************/
LESENSE_Reset(void)962 void LESENSE_Reset(void)
963 {
964   uint32_t i;
965 
966 
967   /* Disable all LESENSE interrupts first */
968   LESENSE->IEN = _LESENSE_IEN_RESETVALUE;
969 
970   /* Clear all pending LESENSE interrupts */
971   LESENSE->IFC = _LESENSE_IFC_MASK;
972 
973   /* Stop the decoder */
974   LESENSE->DECCTRL |= LESENSE_DECCTRL_DISABLE;
975 
976   /* Stop sensor scan and clear result buffer */
977   LESENSE->CMD = (LESENSE_CMD_STOP | LESENSE_CMD_CLEARBUF);
978 
979   /* Reset LESENSE configuration registers */
980   LESENSE->CTRL      = _LESENSE_CTRL_RESETVALUE;
981   LESENSE->PERCTRL   = _LESENSE_PERCTRL_RESETVALUE;
982   LESENSE->DECCTRL   = _LESENSE_DECCTRL_RESETVALUE;
983   LESENSE->BIASCTRL  = _LESENSE_BIASCTRL_RESETVALUE;
984   LESENSE->CHEN      = _LESENSE_CHEN_RESETVALUE;
985   LESENSE->IDLECONF  = _LESENSE_IDLECONF_RESETVALUE;
986   LESENSE->ALTEXCONF = _LESENSE_ALTEXCONF_RESETVALUE;
987 
988   /* Disable LESENSE to control GPIO pins */
989   LESENSE->ROUTE = _LESENSE_ROUTE_RESETVALUE;
990 
991   /* Reset all channel configuration registers */
992   for (i = 0U; i < 16U; ++i)
993   {
994     LESENSE->CH[i].TIMING   = _LESENSE_CH_TIMING_RESETVALUE;
995     LESENSE->CH[i].INTERACT = _LESENSE_CH_INTERACT_RESETVALUE;
996     LESENSE->CH[i].EVAL     = _LESENSE_CH_EVAL_RESETVALUE;
997   }
998 
999   /* Reset all decoder state configuration registers */
1000   for (i = 0U; i < 16U; ++i)
1001   {
1002     LESENSE->ST[i].TCONFA = _LESENSE_ST_TCONFA_RESETVALUE;
1003     LESENSE->ST[i].TCONFB = _LESENSE_ST_TCONFB_RESETVALUE;
1004   }
1005 }
1006 
1007 
1008 /** @} (end addtogroup LESENSE) */
1009 /** @} (end addtogroup EM_Library) */
1010 
1011 #endif /* defined(LESENSE_COUNT) && (LESENSE_COUNT > 0) */
1012