mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Revision:
149:156823d33999
Parent:
144:ef7eb2e8f9f7
Child:
150:02e0a0aed4ec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_lesense.c	Fri Oct 28 11:17:30 2016 +0100
@@ -0,0 +1,1120 @@
+/***************************************************************************//**
+ * @file em_lesense.c
+ * @brief Low Energy Sensor (LESENSE) Peripheral API
+ * @version 4.2.1
+ *******************************************************************************
+ * @section License
+ * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
+ *******************************************************************************
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
+ * obligation to support this Software. Silicon Labs is providing the
+ * Software "AS IS", with no express or implied warranties of any kind,
+ * including, but not limited to, any implied warranties of merchantability
+ * or fitness for any particular purpose or warranties against infringement
+ * of any proprietary rights of a third party.
+ *
+ * Silicon Labs will not be liable for any consequential, incidental, or
+ * special damages, or any other relief, or for any claim by any third party,
+ * arising from your use of this Software.
+ *
+ ******************************************************************************/
+
+#include "em_lesense.h"
+#if defined(LESENSE_COUNT) && (LESENSE_COUNT > 0)
+#include "em_assert.h"
+#include "em_bus.h"
+#include "em_cmu.h"
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+#if !defined(UINT32_MAX)
+#define UINT32_MAX ((uint32_t)(0xFFFFFFFF))
+#endif
+/** @endcond */
+
+/***************************************************************************//**
+ * @addtogroup EM_Library
+ * @{
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @addtogroup LESENSE
+ * @brief Low Energy Sensor (LESENSE) Peripheral API
+ * @{
+ ******************************************************************************/
+
+/*******************************************************************************
+ **************************   LOCAL FUNCTIONS   ********************************
+ ******************************************************************************/
+
+
+/*******************************************************************************
+ **************************   GLOBAL FUNCTIONS   *******************************
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @brief
+ *   Initialize the LESENSE module.
+ *
+ * @details
+ *   This function configures the main parameters of the LESENSE interface.
+ *   Please refer to the initialization parameter type definition
+ *   (@ref LESENSE_Init_TypeDef) for more details.
+ *
+ * @note
+ *   @ref LESENSE_Init() has been designed for initializing LESENSE once in an
+ *   operation cycle. Be aware of the effects of reconfiguration if using this
+ *   function from multiple sources in your code. This function has not been
+ *   designed to be re-entrant.
+ *   Requesting reset by setting @p reqReset to true is required in each reset
+ *   or power-on cycle in order to configure the default values of the RAM
+ *   mapped LESENSE registers.
+ *   Notice that GPIO pins used by the LESENSE module must be properly
+ *   configured by the user explicitly, in order for the LESENSE to work as
+ *   intended.
+ *   (When configuring pins, one should remember to consider the sequence of
+ *   configuration, in order to avoid unintended pulses/glitches on output
+ *   pins.)
+ *
+ * @param[in] init
+ *   LESENSE initialization structure.
+ *
+ * @param[in] reqReset
+ *   Request to call @ref LESENSE_Reset() first in order to initialize all
+ *   LESENSE registers with the default value.
+ ******************************************************************************/
+void LESENSE_Init(LESENSE_Init_TypeDef const *init, bool const reqReset)
+{
+  /* Sanity check of initialization values */
+  EFM_ASSERT((uint32_t)init->timeCtrl.startDelay < 4U);
+  EFM_ASSERT((uint32_t)init->perCtrl.dacPresc < 32U);
+
+  /* Reset LESENSE registers if requested. */
+  if (reqReset)
+  {
+    LESENSE_Reset();
+  }
+
+  /* Set sensor start delay for each channel. */
+  LESENSE_StartDelaySet((uint32_t)init->timeCtrl.startDelay);
+
+  /* LESENSE core control configuration.
+   * Set PRS source, SCANCONF register usage strategy, interrupt and
+   * DMA trigger level condition, DMA wakeup condition, bias mode,
+   * enable/disable to sample both ACMPs simultaneously, enable/disable to store
+   * SCANRES in CNT_RES after each scan, enable/disable to always write to the
+   * result buffer, even if it is full, enable/disable LESENSE running in debug
+   * mode. */
+  LESENSE->CTRL =
+    ((uint32_t)init->coreCtrl.prsSel         << _LESENSE_CTRL_PRSSEL_SHIFT)
+    | (uint32_t)init->coreCtrl.scanConfSel
+    | (uint32_t)init->coreCtrl.bufTrigLevel
+    | (uint32_t)init->coreCtrl.wakeupOnDMA
+    | ((uint32_t)init->coreCtrl.invACMP0     << _LESENSE_CTRL_ACMP0INV_SHIFT)
+    | ((uint32_t)init->coreCtrl.invACMP1     << _LESENSE_CTRL_ACMP1INV_SHIFT)
+    | ((uint32_t)init->coreCtrl.dualSample   << _LESENSE_CTRL_DUALSAMPLE_SHIFT)
+    | ((uint32_t)init->coreCtrl.storeScanRes << _LESENSE_CTRL_STRSCANRES_SHIFT)
+    | ((uint32_t)init->coreCtrl.bufOverWr    << _LESENSE_CTRL_BUFOW_SHIFT)
+    | ((uint32_t)init->coreCtrl.debugRun     << _LESENSE_CTRL_DEBUGRUN_SHIFT);
+
+  /* Set scan mode in the CTRL register using the provided function, don't
+   * start scanning immediately. */
+  LESENSE_ScanModeSet((LESENSE_ScanMode_TypeDef)init->coreCtrl.scanStart, false);
+
+  /* LESENSE peripheral control configuration.
+   * Set DAC0 and DAC1 data source, conversion mode, output mode. Set DAC
+   * prescaler and reference. Set ACMP0 and ACMP1 control mode. Set ACMP and DAC
+   * duty cycle (warm up) mode. */
+  LESENSE->PERCTRL =
+    ((uint32_t)init->perCtrl.dacCh0Data       << _LESENSE_PERCTRL_DACCH0DATA_SHIFT)
+    | ((uint32_t)init->perCtrl.dacCh0ConvMode << _LESENSE_PERCTRL_DACCH0CONV_SHIFT)
+    | ((uint32_t)init->perCtrl.dacCh0OutMode  << _LESENSE_PERCTRL_DACCH0OUT_SHIFT)
+    | ((uint32_t)init->perCtrl.dacCh1Data     << _LESENSE_PERCTRL_DACCH1DATA_SHIFT)
+    | ((uint32_t)init->perCtrl.dacCh1ConvMode << _LESENSE_PERCTRL_DACCH1CONV_SHIFT)
+    | ((uint32_t)init->perCtrl.dacCh1OutMode  << _LESENSE_PERCTRL_DACCH1OUT_SHIFT)
+    | ((uint32_t)init->perCtrl.dacPresc       << _LESENSE_PERCTRL_DACPRESC_SHIFT)
+    | (uint32_t)init->perCtrl.dacRef
+    | ((uint32_t)init->perCtrl.acmp0Mode      << _LESENSE_PERCTRL_ACMP0MODE_SHIFT)
+    | ((uint32_t)init->perCtrl.acmp1Mode      << _LESENSE_PERCTRL_ACMP1MODE_SHIFT)
+    | (uint32_t)init->perCtrl.warmupMode;
+
+  /* LESENSE decoder general control configuration.
+   * Set decoder input source, select PRS input for decoder bits.
+   * Enable/disable the decoder to check the present state.
+   * Enable/disable decoder to channel interrupt mapping.
+   * Enable/disable decoder hysteresis on PRS output.
+   * Enable/disable decoder hysteresis on count events.
+   * Enable/disable decoder hysteresis on interrupt requests.
+   * Enable/disable count mode on LESPRS0 and LESPRS1. */
+  LESENSE->DECCTRL =
+    (uint32_t)init->decCtrl.decInput
+    | ((uint32_t)init->decCtrl.prsChSel0 << _LESENSE_DECCTRL_PRSSEL0_SHIFT)
+    | ((uint32_t)init->decCtrl.prsChSel1 << _LESENSE_DECCTRL_PRSSEL1_SHIFT)
+    | ((uint32_t)init->decCtrl.prsChSel2 << _LESENSE_DECCTRL_PRSSEL2_SHIFT)
+    | ((uint32_t)init->decCtrl.prsChSel3 << _LESENSE_DECCTRL_PRSSEL3_SHIFT)
+    | ((uint32_t)init->decCtrl.chkState  << _LESENSE_DECCTRL_ERRCHK_SHIFT)
+    | ((uint32_t)init->decCtrl.intMap    << _LESENSE_DECCTRL_INTMAP_SHIFT)
+    | ((uint32_t)init->decCtrl.hystPRS0  << _LESENSE_DECCTRL_HYSTPRS0_SHIFT)
+    | ((uint32_t)init->decCtrl.hystPRS1  << _LESENSE_DECCTRL_HYSTPRS1_SHIFT)
+    | ((uint32_t)init->decCtrl.hystPRS2  << _LESENSE_DECCTRL_HYSTPRS2_SHIFT)
+    | ((uint32_t)init->decCtrl.hystIRQ   << _LESENSE_DECCTRL_HYSTIRQ_SHIFT)
+    | ((uint32_t)init->decCtrl.prsCount  << _LESENSE_DECCTRL_PRSCNT_SHIFT);
+
+  /* Set initial LESENSE decoder state. */
+  LESENSE_DecoderStateSet((uint32_t)init->decCtrl.initState);
+
+  /* LESENSE bias control configuration. */
+  LESENSE->BIASCTRL = (uint32_t)init->coreCtrl.biasMode;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Set scan frequency for periodic scanning.
+ *
+ * @details
+ *   This function only applies to LESENSE if period counter is being used as
+ *   a trigger for scan start.
+ *   The calculation is based on the following formula:
+ *   Fscan = LFACLKles / ((1+PCTOP)*2^PCPRESC)
+ *
+ * @note
+ *   Note that the calculation does not necessarily result in the requested
+ *   scan frequency due to integer division. Check the return value for the
+ *   resulted scan frequency.
+ *
+ * @param[in] refFreq
+ *   Select reference LFACLK clock frequency in Hz. If set to 0, the current
+ *   clock frequency is being used as a reference.
+ *
+ * @param[in] scanFreq
+ *   Set the desired scan frequency in Hz.
+ *
+ * @return
+ *   Frequency in Hz calculated and set by this function. Users can use this to
+ *   compare the requested and set values.
+ ******************************************************************************/
+uint32_t LESENSE_ScanFreqSet(uint32_t refFreq, uint32_t const scanFreq)
+{
+  uint32_t tmp;
+  uint32_t pcPresc = 0UL;  /* Period counter prescaler. */
+  uint32_t clkDiv  = 1UL;  /* Clock divisor value (2^pcPresc). */
+  uint32_t pcTop   = 63UL; /* Period counter top value (max. 63). */
+  uint32_t calcScanFreq;   /* Variable for testing the calculation algorithm. */
+
+
+  /* If refFreq is set to 0, the currently configured reference clock is
+   * assumed. */
+  if (!refFreq)
+  {
+    refFreq = CMU_ClockFreqGet(cmuClock_LESENSE);
+  }
+
+  /* Max. value of pcPresc is 128, thus using reference frequency less than
+   * 33554431Hz (33.554431MHz), the frequency calculation in the while loop
+   * below will not overflow. */
+  EFM_ASSERT(refFreq < ((uint32_t)UINT32_MAX / 128UL));
+
+  /* Sanity check of scan frequency value. */
+  EFM_ASSERT((scanFreq > 0U) && (scanFreq <= refFreq));
+
+  /* Calculate the minimum necessary prescaler value in order to provide the
+   * biggest possible resolution for setting scan frequency.
+   * Maximum number of calculation cycles is 7 (value of lesenseClkDiv_128). */
+  while ((refFreq / ((uint32_t)scanFreq * clkDiv) > (pcTop + 1UL))
+         && (pcPresc < lesenseClkDiv_128))
+  {
+    ++pcPresc;
+    clkDiv = (uint32_t)1UL << pcPresc;
+  }
+
+  /* Calculate pcTop value. */
+  pcTop = ((uint32_t)refFreq / ((uint32_t)scanFreq * clkDiv)) - 1UL;
+
+  /* Clear current PCPRESC and PCTOP settings. Be aware of the effect of
+   * non-atomic Read-Modify-Write on LESENSE->TIMCRTL. */
+  tmp = LESENSE->TIMCTRL & (~_LESENSE_TIMCTRL_PCPRESC_MASK
+                            & ~_LESENSE_TIMCTRL_PCTOP_MASK);
+
+  /* Set new values in tmp while reserving other settings. */
+  tmp |= ((uint32_t)pcPresc << _LESENSE_TIMCTRL_PCPRESC_SHIFT)
+         | ((uint32_t)pcTop << _LESENSE_TIMCTRL_PCTOP_SHIFT);
+
+  /* Set values in LESENSE_TIMCTRL register. */
+  LESENSE->TIMCTRL = tmp;
+
+  /* For testing the calculation algorithm. */
+  calcScanFreq = ((uint32_t)refFreq / ((uint32_t)(1UL + pcTop) * clkDiv));
+
+  return calcScanFreq;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Set scan mode of the LESENSE channels.
+ *
+ * @details
+ *   This function configures how the scan start is being triggered. It can be
+ *   used for re-configuring the scan mode while running the application but it
+ *   is also used by LESENSE_Init() for initialization.
+ *
+ * @note
+ *   Users can configure the scan mode by LESENSE_Init() function, but only with
+ *   a significant overhead. This simple function serves the purpose of
+ *   controlling this parameter after the channel has been configured.
+ *   Please be aware the effects of the non-atomic Read-Modify-Write cycle!
+ *
+ * @param[in] scanMode
+ *   Select where to map LESENSE alternate excitation channels.
+ *   @li lesenseScanStartPeriodic - New scan is started each time the period
+ *                                  counter overflows.
+ *   @li lesenseScanStartOneShot - Single scan is performed when
+ *                                 LESENSE_ScanStart() is called.
+ *   @li lesenseScanStartPRS - New scan is triggered by pulse on PRS channel.
+ *
+ * @param[in] start
+ *   If true, LESENSE_ScanStart() is immediately issued after configuration.
+ ******************************************************************************/
+void LESENSE_ScanModeSet(LESENSE_ScanMode_TypeDef const scanMode,
+                         bool const start)
+{
+  uint32_t tmp; /* temporary storage of the CTRL register value */
+
+
+  /* Save the CTRL register value to tmp.
+   * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
+  tmp = LESENSE->CTRL & ~(_LESENSE_CTRL_SCANMODE_MASK);
+  /* Setting the requested scanMode to the CTRL register. Casting signed int
+   * (enum) to unsigned long (uint32_t). */
+  tmp |= (uint32_t)scanMode;
+
+  /* Write the new value to the CTRL register. */
+  LESENSE->CTRL = tmp;
+
+  /* Start sensor scanning if requested. */
+  if (start)
+  {
+    LESENSE_ScanStart();
+  }
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Set start delay of sensor interaction on each channel.
+ *
+ * @details
+ *   This function sets start delay of sensor interaction on each channel.
+ *   It can be used for adjusting the start delay while running the application
+ *   but it is also used by LESENSE_Init() for initialization.
+ *
+ * @note
+ *   Users can configure the start delay by LESENSE_Init() function, but only
+ *   with a significant overhead. This simple function serves the purpose of
+ *   controlling this parameter after the channel has been configured.
+ *   Please be aware the effects of the non-atomic Read-Modify-Write cycle!
+ *
+ * @param[in] startDelay
+ *   Number of LFACLK cycles to delay. Valid range: 0-3 (2 bit).
+ ******************************************************************************/
+void LESENSE_StartDelaySet(uint8_t const startDelay)
+{
+  uint32_t tmp; /* temporary storage of the TIMCTRL register value */
+
+
+  /* Sanity check of startDelay. */
+  EFM_ASSERT(startDelay < 4U);
+
+  /* Save the TIMCTRL register value to tmp.
+   * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
+  tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_STARTDLY_MASK);
+  /* Setting the requested startDelay to the TIMCTRL register. */
+  tmp |= (uint32_t)startDelay << _LESENSE_TIMCTRL_STARTDLY_SHIFT;
+
+  /* Write the new value to the TIMCTRL register. */
+  LESENSE->TIMCTRL = tmp;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Set clock division for LESENSE timers.
+ *
+ * @details
+ *   Use this function to configure the clock division for the LESENSE timers
+ *   used for excitation timing.
+ *   The division setting is global, but the clock source can be selected for
+ *   each channel using LESENSE_ChannelConfig() function, please refer to the
+ *   documentation of it for more details.
+ *
+ * @note
+ *   If AUXHFRCO is used for excitation timing, LFACLK can not exceed 500kHz.
+ *   LFACLK can not exceed 50kHz if the ACMP threshold level (ACMPTHRES) is not
+ *   equal for all channels.
+ *
+ * @param[in] clk
+ *   Select clock to prescale.
+ *    @li lesenseClkHF - set AUXHFRCO clock divisor for HF timer.
+ *    @li lesenseClkLF - set LFACLKles clock divisor for LF timer.
+ *
+ * @param[in] clkDiv
+ *   Clock divisor value. Valid range depends on the @p clk value.
+ ******************************************************************************/
+void LESENSE_ClkDivSet(LESENSE_ChClk_TypeDef const clk,
+                       LESENSE_ClkPresc_TypeDef const clkDiv)
+{
+  uint32_t tmp;
+
+
+  /* Select clock to prescale */
+  switch (clk)
+  {
+    case lesenseClkHF:
+      /* Sanity check of clock divisor for HF clock. */
+      EFM_ASSERT((uint32_t)clkDiv <= lesenseClkDiv_8);
+
+      /* Clear current AUXPRESC settings. */
+      tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_AUXPRESC_MASK);
+
+      /* Set new values in tmp while reserving other settings. */
+      tmp |= ((uint32_t)clkDiv << _LESENSE_TIMCTRL_AUXPRESC_SHIFT);
+
+      /* Set values in LESENSE_TIMCTRL register. */
+      LESENSE->TIMCTRL = tmp;
+      break;
+
+    case lesenseClkLF:
+      /* Clear current LFPRESC settings. */
+      tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_LFPRESC_MASK);
+
+      /* Set new values in tmp while reserving other settings. */
+      tmp |= ((uint32_t)clkDiv << _LESENSE_TIMCTRL_LFPRESC_SHIFT);
+
+      /* Set values in LESENSE_TIMCTRL register. */
+      LESENSE->TIMCTRL = tmp;
+      break;
+
+    default:
+      EFM_ASSERT(0);
+      break;
+  }
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Configure all (16) LESENSE sensor channels.
+ *
+ * @details
+ *   This function configures all the sensor channels of LESENSE interface.
+ *   Please refer to the configuration parameter type definition
+ *   (LESENSE_ChAll_TypeDef) for more details.
+ *
+ * @note
+ *   Channels can be configured individually using LESENSE_ChannelConfig()
+ *   function.
+ *   Notice that pins used by the LESENSE module must be properly configured
+ *   by the user explicitly, in order for the LESENSE to work as intended.
+ *   (When configuring pins, one should remember to consider the sequence of
+ *   configuration, in order to avoid unintended pulses/glitches on output
+ *   pins.)
+ *
+ * @param[in] confChAll
+ *   Configuration structure for all (16) LESENSE sensor channels.
+ ******************************************************************************/
+void LESENSE_ChannelAllConfig(LESENSE_ChAll_TypeDef const *confChAll)
+{
+  uint32_t i;
+
+  /* Iterate through all the 16 channels */
+  for (i = 0U; i < 16U; ++i)
+  {
+    /* Configure scan channels. */
+    LESENSE_ChannelConfig(&confChAll->Ch[i], i);
+  }
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Configure a single LESENSE sensor channel.
+ *
+ * @details
+ *   This function configures a single sensor channel of the LESENSE interface.
+ *   Please refer to the configuration parameter type definition
+ *   (LESENSE_ChDesc_TypeDef) for more details.
+ *
+ * @note
+ *   This function has been designed to minimize the effects of sensor channel
+ *   reconfiguration while LESENSE is in operation, however one shall be aware
+ *   of these effects and the right timing of calling this function.
+ *   Parameter @p useAltEx must be true in the channel configuration in order to
+ *   use alternate excitation pins.
+ *
+ * @param[in] confCh
+ *   Configuration structure for a single LESENSE sensor channel.
+ *
+ * @param[in] chIdx
+ *   Channel index to configure (0-15).
+ ******************************************************************************/
+void LESENSE_ChannelConfig(LESENSE_ChDesc_TypeDef const *confCh,
+                           uint32_t const chIdx)
+{
+  uint32_t tmp; /* Service variable. */
+
+
+  /* Sanity check of configuration parameters */
+  EFM_ASSERT(chIdx < 16U);
+  EFM_ASSERT(confCh->exTime < 64U);
+  EFM_ASSERT(confCh->sampleDelay < 128U);
+  EFM_ASSERT(confCh->measDelay < 128U);
+  /* Not a complete assert, as the max. value of acmpThres depends on other
+   * configuration parameters, check the parameter description of acmpThres for
+   * for more details! */
+  EFM_ASSERT(confCh->acmpThres < 4096U);
+  EFM_ASSERT(!(confCh->chPinExMode == lesenseChPinExDACOut
+               && (chIdx != 2U)
+               && (chIdx != 3U)
+               && (chIdx != 4U)
+               && (chIdx != 5U)));
+  EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh1
+               && ((chIdx != 12U)
+                   && (chIdx != 13U)
+                   && (chIdx != 14U)
+                   && (chIdx != 15U))));
+  EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh0
+               && ((chIdx != 0U)
+                   && (chIdx != 1U)
+                   && (chIdx != 2U)
+                   && (chIdx != 3U))));
+
+  /* Configure chIdx setup in LESENSE idle phase.
+   * Read-modify-write in order to support reconfiguration during LESENSE
+   * operation. */
+  tmp               = (LESENSE->IDLECONF & ~((uint32_t)0x3UL << (chIdx * 2UL)));
+  tmp              |= ((uint32_t)confCh->chPinIdleMode << (chIdx * 2UL));
+  LESENSE->IDLECONF = tmp;
+
+  /* Channel specific timing configuration on scan channel chIdx.
+   * Set excitation time, sampling delay, measurement delay. */
+  LESENSE_ChannelTimingSet(chIdx,
+                           (uint32_t)confCh->exTime,
+                           (uint32_t)confCh->sampleDelay,
+                           (uint32_t)confCh->measDelay);
+
+  /* Channel specific configuration of clocks, sample mode, excitation pin mode
+   * alternate excitation usage and interrupt mode on scan channel chIdx in
+   * LESENSE_CHchIdx_INTERACT. */
+  LESENSE->CH[chIdx].INTERACT =
+        ((uint32_t)confCh->exClk       << _LESENSE_CH_INTERACT_EXCLK_SHIFT)
+        | ((uint32_t)confCh->sampleClk << _LESENSE_CH_INTERACT_SAMPLECLK_SHIFT)
+        | (uint32_t)confCh->sampleMode
+        | (uint32_t)confCh->intMode
+        | (uint32_t)confCh->chPinExMode
+        | ((uint32_t)confCh->useAltEx  << _LESENSE_CH_INTERACT_ALTEX_SHIFT);
+
+  /* Configure channel specific counter comparison mode, optional result
+   * forwarding to decoder, optional counter value storing and optional result
+   * inverting on scan channel chIdx in LESENSE_CHchIdx_EVAL. */
+  LESENSE->CH[chIdx].EVAL =
+        (uint32_t)confCh->compMode
+        | ((uint32_t)confCh->shiftRes    << _LESENSE_CH_EVAL_DECODE_SHIFT)
+        | ((uint32_t)confCh->storeCntRes << _LESENSE_CH_EVAL_STRSAMPLE_SHIFT)
+        | ((uint32_t)confCh->invRes      << _LESENSE_CH_EVAL_SCANRESINV_SHIFT);
+
+  /* Configure analog comparator (ACMP) threshold and decision threshold for
+   * counter separately with the function provided for that. */
+  LESENSE_ChannelThresSet(chIdx,
+                         (uint32_t)confCh->acmpThres,
+                         (uint32_t)confCh->cntThres);
+
+  /* Enable/disable interrupts on channel */
+  BUS_RegBitWrite(&(LESENSE->IEN), chIdx, confCh->enaInt);
+
+  /* Enable/disable CHchIdx pin. */
+  BUS_RegBitWrite(&(LESENSE->ROUTE), chIdx, confCh->enaPin);
+
+  /* Enable/disable scan channel chIdx. */
+  BUS_RegBitWrite(&(LESENSE->CHEN), chIdx, confCh->enaScanCh);
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Configure the LESENSE alternate excitation modes.
+ *
+ * @details
+ *   This function configures the alternate excitation channels of the LESENSE
+ *   interface. Please refer to the configuration parameter type definition
+ *   (LESENSE_ConfAltEx_TypeDef) for more details.
+ *
+ * @note
+ *   Parameter @p useAltEx must be true in the channel configuration structrure
+ *   (LESENSE_ChDesc_TypeDef) in order to use alternate excitation pins on the
+ *   channel.
+ *
+ * @param[in] confAltEx
+ *   Configuration structure for LESENSE alternate excitation pins.
+ ******************************************************************************/
+void LESENSE_AltExConfig(LESENSE_ConfAltEx_TypeDef const *confAltEx)
+{
+  uint32_t i;
+  uint32_t tmp;
+
+
+  /* Configure alternate excitation mapping.
+   * Atomic read-modify-write using BUS_RegBitWrite function in order to
+   * support reconfiguration during LESENSE operation. */
+  BUS_RegBitWrite(&(LESENSE->CTRL),
+                  _LESENSE_CTRL_ALTEXMAP_SHIFT,
+                  confAltEx->altExMap);
+
+  switch (confAltEx->altExMap)
+  {
+    case lesenseAltExMapALTEX:
+      /* Iterate through the 8 possible alternate excitation pin descriptors. */
+      for (i = 0U; i < 8U; ++i)
+      {
+        /* Enable/disable alternate excitation pin i.
+         * Atomic read-modify-write using BUS_RegBitWrite function in order to
+         * support reconfiguration during LESENSE operation. */
+        BUS_RegBitWrite(&(LESENSE->ROUTE),
+                        (16UL + i),
+                        confAltEx->AltEx[i].enablePin);
+
+        /* Setup the idle phase state of alternate excitation pin i.
+         * Read-modify-write in order to support reconfiguration during LESENSE
+         * operation. */
+        tmp                = (LESENSE->ALTEXCONF & ~((uint32_t)0x3UL << (i * 2UL)));
+        tmp               |= ((uint32_t)confAltEx->AltEx[i].idleConf << (i * 2UL));
+        LESENSE->ALTEXCONF = tmp;
+
+        /* Enable/disable always excite on channel i */
+        BUS_RegBitWrite(&(LESENSE->ALTEXCONF),
+                        (16UL + i),
+                        confAltEx->AltEx[i].alwaysEx);
+      }
+      break;
+
+    case lesenseAltExMapACMP:
+      /* Iterate through all the 16 alternate excitation channels */
+      for (i = 0U; i < 16U; ++i)
+      {
+        /* Enable/disable alternate ACMP excitation channel pin i. */
+        /* Atomic read-modify-write using BUS_RegBitWrite function in order to
+         * support reconfiguration during LESENSE operation. */
+        BUS_RegBitWrite(&(LESENSE->ROUTE),
+                        i,
+                        confAltEx->AltEx[i].enablePin);
+      }
+      break;
+    default:
+      /* Illegal value. */
+      EFM_ASSERT(0);
+      break;
+  }
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Enable/disable LESENSE scan channel and the pin assigned to it.
+ *
+ * @details
+ *   Use this function to enable/disable a selected LESENSE scan channel and the
+ *   pin assigned to.
+ *
+ * @note
+ *   Users can enable/disable scan channels and the channel pin by
+ *   LESENSE_ChannelConfig() function, but only with a significant overhead.
+ *   This simple function serves the purpose of controlling these parameters
+ *   after the channel has been configured.
+ *
+ * @param[in] chIdx
+ *   Identifier of the scan channel. Valid range: 0-15.
+ *
+ * @param[in] enaScanCh
+ *   Enable/disable the selected scan channel by setting this parameter to
+ *   true/false respectively.
+ *
+ * @param[in] enaPin
+ *   Enable/disable the pin assigned to the channel selected by @p chIdx.
+ ******************************************************************************/
+void LESENSE_ChannelEnable(uint8_t const chIdx,
+                           bool const enaScanCh,
+                           bool const enaPin)
+{
+  /* Enable/disable the assigned pin of scan channel chIdx.
+   * Note: BUS_RegBitWrite() function is used for setting/clearing single
+   * bit peripheral register bitfields. Read the function description in
+   * em_bus.h for more details. */
+  BUS_RegBitWrite(&(LESENSE->ROUTE), chIdx, enaPin);
+
+  /* Enable/disable scan channel chIdx. */
+  BUS_RegBitWrite(&(LESENSE->CHEN), chIdx, enaScanCh);
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Enable/disable LESENSE scan channel and the pin assigned to it.
+ *
+ * @details
+ *   Use this function to enable/disable LESENSE scan channels and the pins
+ *   assigned to them using a mask.
+ *
+ * @note
+ *   Users can enable/disable scan channels and channel pins by using
+ *   LESENSE_ChannelAllConfig() function, but only with a significant overhead.
+ *   This simple function serves the purpose of controlling these parameters
+ *   after the channel has been configured.
+ *
+ * @param[in] chMask
+ *   Set the corresponding bit to 1 to enable, 0 to disable the selected scan
+ *   channel.
+ *
+ * @param[in] pinMask
+ *   Set the corresponding bit to 1 to enable, 0 to disable the pin on selected
+ *   channel.
+ ******************************************************************************/
+void LESENSE_ChannelEnableMask(uint16_t chMask, uint16_t pinMask)
+{
+  /* Enable/disable all channels at once according to the mask. */
+  LESENSE->CHEN = chMask;
+  /* Enable/disable all channel pins at once according to the mask. */
+  LESENSE->ROUTE = pinMask;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Set LESENSE channel timing parameters.
+ *
+ * @details
+ *   Use this function to set timing parameters on a selected LESENSE channel.
+ *
+ * @note
+ *   Users can configure the channel timing parameters by
+ *   LESENSE_ChannelConfig() function, but only with a significant overhead.
+ *   This simple function serves the purpose of controlling these parameters
+ *   after the channel has been configured.
+ *
+ * @param[in] chIdx
+ *   Identifier of the scan channel. Valid range: 0-15.
+ *
+ * @param[in] exTime
+ *   Excitation time on chIdx. Excitation will last exTime+1 excitation clock
+ *   cycles. Valid range: 0-63 (6 bits).
+ *
+ * @param[in] sampleDelay
+ *   Sample delay on chIdx. Sampling will occur after sampleDelay+1 sample clock
+ *   cycles. Valid range: 0-127 (7 bits).
+ *
+ * @param[in] measDelay
+ *   Measure delay on chIdx. Sensor measuring is delayed for measDelay+1
+ *   excitation clock cycles. Valid range: 0-127 (7 bits).
+ ******************************************************************************/
+void LESENSE_ChannelTimingSet(uint8_t const chIdx,
+                              uint8_t const exTime,
+                              uint8_t const sampleDelay,
+                              uint8_t const measDelay)
+{
+  /* Sanity check of parameters. */
+  EFM_ASSERT(exTime < 64U);
+  EFM_ASSERT(sampleDelay < 128U);
+  EFM_ASSERT(measDelay < 128U);
+
+  /* Channel specific timing configuration on scan channel chIdx.
+   * Setting excitation time, sampling delay, measurement delay. */
+  LESENSE->CH[chIdx].TIMING =
+              ((uint32_t)exTime        << _LESENSE_CH_TIMING_EXTIME_SHIFT)
+              | ((uint32_t)sampleDelay << _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT)
+              | ((uint32_t)measDelay   << _LESENSE_CH_TIMING_MEASUREDLY_SHIFT);
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Set LESENSE channel threshold parameters.
+ *
+ * @details
+ *   Use this function to set threshold parameters on a selected LESENSE
+ *   channel.
+ *
+ * @note
+ *   Users can configure the channel threshold parameters by
+ *   LESENSE_ChannelConfig() function, but only with a significant overhead.
+ *   This simple function serves the purpose of controlling these parameters
+ *   after the channel has been configured.
+ *
+ * @param[in] chIdx
+ *   Identifier of the scan channel. Valid range: 0-15.
+ *
+ * @param[in] acmpThres
+ *   ACMP threshold.
+ *   @li If perCtrl.dacCh0Data or perCtrl.dacCh1Data is set to
+ *   #lesenseDACIfData, acmpThres defines the 12-bit DAC data in the
+ *   corresponding data register of the DAC interface (DACn_CH0DATA and
+ *   DACn_CH1DATA). In this case, the valid range is: 0-4095 (12 bits).
+ *
+ *   @li If perCtrl.dacCh0Data or perCtrl.dacCh1Data is set to
+ *   #lesenseACMPThres, acmpThres defines the 6-bit Vdd scaling factor of ACMP
+ *   negative input (VDDLEVEL in ACMP_INPUTSEL register). In this case, the
+ *   valid range is: 0-63 (6 bits).
+ *
+ * @param[in] cntThres
+ *   Decision threshold for counter comparison.
+ *   Valid range: 0-65535 (16 bits).
+ ******************************************************************************/
+void LESENSE_ChannelThresSet(uint8_t const chIdx,
+                             uint16_t const acmpThres,
+                             uint16_t const cntThres)
+{
+  uint32_t tmp; /* temporary storage */
+
+
+  /* Sanity check for acmpThres only, cntThres is 16bit value. */
+  EFM_ASSERT(acmpThres < 4096U);
+  /* Sanity check for LESENSE channel id. */
+  EFM_ASSERT(chIdx < 16);
+
+  /* Save the INTERACT register value of channel chIdx to tmp.
+   * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
+  tmp = LESENSE->CH[chIdx].INTERACT & ~(_LESENSE_CH_INTERACT_ACMPTHRES_MASK);
+  /* Set the ACMP threshold value to the INTERACT register of channel chIdx. */
+  tmp |= (uint32_t)acmpThres << _LESENSE_CH_INTERACT_ACMPTHRES_SHIFT;
+  /* Write the new value to the INTERACT register. */
+  LESENSE->CH[chIdx].INTERACT = tmp;
+
+  /* Save the EVAL register value of channel chIdx to tmp.
+   * Please be aware the effects of the non-atomic Read-Modify-Write cycle! */
+  tmp = LESENSE->CH[chIdx].EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK);
+  /* Set the counter threshold value to the INTERACT register of channel chIdx. */
+  tmp |= (uint32_t)cntThres << _LESENSE_CH_EVAL_COMPTHRES_SHIFT;
+  /* Write the new value to the EVAL register. */
+  LESENSE->CH[chIdx].EVAL = tmp;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Configure all LESENSE decoder states.
+ *
+ * @details
+ *   This function configures all the decoder states of the LESENSE interface.
+ *   Please refer to the configuration parameter type definition
+ *   (LESENSE_DecStAll_TypeDef) for more details.
+ *
+ * @note
+ *   Decoder states can be configured individually using
+ *   LESENSE_DecoderStateConfig() function.
+ *
+ * @param[in] confDecStAll
+ *   Configuration structure for all (16) LESENSE decoder states.
+ ******************************************************************************/
+void LESENSE_DecoderStateAllConfig(LESENSE_DecStAll_TypeDef const *confDecStAll)
+{
+  uint32_t i;
+
+  /* Iterate through all the 16 decoder states. */
+  for (i = 0U; i < 16U; ++i)
+  {
+    /* Configure decoder state i. */
+    LESENSE_DecoderStateConfig(&confDecStAll->St[i], i);
+  }
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Configure a single LESENSE decoder state.
+ *
+ * @details
+ *   This function configures a single decoder state of the LESENSE interface.
+ *   Please refer to the configuration parameter type definition
+ *   (LESENSE_DecStDesc_TypeDef) for more details.
+ *
+ * @param[in] confDecSt
+ *   Configuration structure for a single LESENSE decoder state.
+ *
+ * @param[in] decSt
+ *   Decoder state index to configure (0-15).
+ ******************************************************************************/
+void LESENSE_DecoderStateConfig(LESENSE_DecStDesc_TypeDef const *confDecSt,
+                                uint32_t const decSt)
+{
+  /* Sanity check of configuration parameters */
+  EFM_ASSERT(decSt < 16U);
+  EFM_ASSERT((uint32_t)confDecSt->confA.compMask < 16U);
+  EFM_ASSERT((uint32_t)confDecSt->confA.compVal < 16U);
+  EFM_ASSERT((uint32_t)confDecSt->confA.nextState < 16U);
+  EFM_ASSERT((uint32_t)confDecSt->confB.compMask < 16U);
+  EFM_ASSERT((uint32_t)confDecSt->confB.compVal < 16U);
+  EFM_ASSERT((uint32_t)confDecSt->confB.nextState < 16U);
+
+  /* Configure state descriptor A (LESENSE_STi_TCONFA) for decoder state i.
+   * Setting sensor compare value, sensor mask, next state index,
+   * transition action, interrupt flag option and state descriptor chaining
+   * configurations. */
+  LESENSE->ST[decSt].TCONFA =
+    (uint32_t)confDecSt->confA.prsAct
+    | ((uint32_t)confDecSt->confA.compMask  << _LESENSE_ST_TCONFA_MASK_SHIFT)
+    | ((uint32_t)confDecSt->confA.compVal   << _LESENSE_ST_TCONFA_COMP_SHIFT)
+    | ((uint32_t)confDecSt->confA.nextState << _LESENSE_ST_TCONFA_NEXTSTATE_SHIFT)
+    | ((uint32_t)confDecSt->confA.setInt    << _LESENSE_ST_TCONFA_SETIF_SHIFT)
+    | ((uint32_t)confDecSt->chainDesc       << _LESENSE_ST_TCONFA_CHAIN_SHIFT);
+
+  /* Configure state descriptor Bi (LESENSE_STi_TCONFB).
+   * Setting sensor compare value, sensor mask, next state index, transition
+   * action and interrupt flag option configurations. */
+  LESENSE->ST[decSt].TCONFB =
+  (uint32_t)confDecSt->confB.prsAct
+    | ((uint32_t)confDecSt->confB.compMask  << _LESENSE_ST_TCONFB_MASK_SHIFT)
+    | ((uint32_t)confDecSt->confB.compVal   << _LESENSE_ST_TCONFB_COMP_SHIFT)
+    | ((uint32_t)confDecSt->confB.nextState << _LESENSE_ST_TCONFB_NEXTSTATE_SHIFT)
+    | ((uint32_t)confDecSt->confB.setInt    << _LESENSE_ST_TCONFB_SETIF_SHIFT);
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Set LESENSE decoder state.
+ *
+ * @details
+ *   This function can be used for setting the initial state of the LESENSE
+ *   decoder.
+ *
+ * @note
+ *   Make sure the LESENSE decoder state is initialized by this function before
+ *   enabling the decoder!
+ *
+ * @param[in] decSt
+ *   Decoder state to set as current state. Valid range: 0-15
+ ******************************************************************************/
+void LESENSE_DecoderStateSet(uint32_t decSt)
+{
+  EFM_ASSERT(decSt < 16U);
+
+  LESENSE->DECSTATE = decSt & _LESENSE_DECSTATE_DECSTATE_MASK;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Get the current state of the LESENSE decoder.
+ *
+ * @return
+ *   This function returns the value of LESENSE_DECSTATE register that
+ *   represents the current state of the LESENSE decoder.
+ ******************************************************************************/
+uint32_t LESENSE_DecoderStateGet(void)
+{
+  return LESENSE->DECSTATE & _LESENSE_DECSTATE_DECSTATE_MASK;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Start scanning of sensors.
+ *
+ * @note
+ *   This function will wait for any pending previous write operation to the
+ *   CMD register to complete before accessing the CMD register. It will also
+ *   wait for the write operation to the CMD register to complete before
+ *   returning. Each write operation to the CMD register may take up to 3 LF
+ *   clock cycles, so the user should expect some delay. The user may implement
+ *   a separate function to write multiple command bits in the CMD register
+ *   in one single operation in order to optimize an application.
+ ******************************************************************************/
+void LESENSE_ScanStart(void)
+{
+  /* Wait for any pending previous write operation to the CMD register to
+     complete before accessing the CMD register. */
+  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
+    ;
+
+  /* Start scanning of sensors */
+  LESENSE->CMD = LESENSE_CMD_START;
+
+  /* Wait for the write operation to the CMD register to complete before
+     returning. */
+  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
+    ;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Stop scanning of sensors.
+ *
+ * @note
+ *   This function will wait for any pending previous write operation to the
+ *   CMD register to complete before accessing the CMD register. It will also
+ *   wait for the write operation to the CMD register to complete before
+ *   returning. Each write operation to the CMD register may take up to 3 LF
+ *   clock cycles, so the user should expect some delay. The user may implement
+ *   a separate function to write multiple command bits in the CMD register
+ *   in one single operation in order to optimize an application.
+ *
+ * @note
+ *   If issued during a scan, the command takes effect after scan completion.
+ ******************************************************************************/
+void LESENSE_ScanStop(void)
+{
+  /* Wait for any pending previous write operation to the CMD register to
+     complete before accessing the CMD register. */
+  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
+    ;
+
+  /* Stop scanning of sensors */
+  LESENSE->CMD = LESENSE_CMD_STOP;
+
+  /* Wait for the write operation to the CMD register to complete before
+     returning. */
+  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
+    ;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Start LESENSE decoder.
+ *
+ * @note
+ *   This function will wait for any pending previous write operation to the
+ *   CMD register to complete before accessing the CMD register. It will also
+ *   wait for the write operation to the CMD register to complete before
+ *   returning. Each write operation to the CMD register may take up to 3 LF
+ *   clock cycles, so the user should expect some delay. The user may implement
+ *   a separate function to write multiple command bits in the CMD register
+ *   in one single operation in order to optimize an application.
+ ******************************************************************************/
+void LESENSE_DecoderStart(void)
+{
+  /* Wait for any pending previous write operation to the CMD register to
+     complete before accessing the CMD register. */
+  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
+    ;
+
+  /* Start decoder */
+  LESENSE->CMD = LESENSE_CMD_DECODE;
+
+  /* Wait for the write operation to the CMD register to complete before
+     returning. */
+  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
+    ;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Clear result buffer.
+ *
+ * @note
+ *   This function will wait for any pending previous write operation to the
+ *   CMD register to complete before accessing the CMD register. It will also
+ *   wait for the write operation to the CMD register to complete before
+ *   returning. Each write operation to the CMD register may take up to 3 LF
+ *   clock cycles, so the user should expect some delay. The user may implement
+ *   a separate function to write multiple command bits in the CMD register
+ *   in one single operation in order to optimize an application.
+ ******************************************************************************/
+void LESENSE_ResultBufferClear(void)
+{
+  /* Wait for any pending previous write operation to the CMD register to
+     complete before accessing the CMD register. */
+  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
+    ;
+
+  LESENSE->CMD = LESENSE_CMD_CLEARBUF;
+
+  /* Wait for the write operation to the CMD register to complete before
+     returning. */
+  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
+    ;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Reset the LESENSE module.
+ *
+ * @details
+ *   Use this function to reset the LESENSE registers.
+ *
+ * @note
+ *   Resetting LESENSE registers is required in each reset or power-on cycle in
+ *   order to configure the default values of the RAM mapped LESENSE registers.
+ *   LESENSE_Reset() can be called on initialization by setting the @p reqReset
+ *   parameter to true in LESENSE_Init().
+ ******************************************************************************/
+void LESENSE_Reset(void)
+{
+  uint32_t i;
+
+  /* Disable all LESENSE interrupts first */
+  LESENSE->IEN = _LESENSE_IEN_RESETVALUE;
+
+  /* Clear all pending LESENSE interrupts */
+  LESENSE->IFC = _LESENSE_IFC_MASK;
+
+  /* Stop the decoder */
+  LESENSE->DECCTRL |= LESENSE_DECCTRL_DISABLE;
+
+  /* Wait for any pending previous write operation to the CMD register to
+     complete before accessing the CMD register. */
+  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
+    ;
+
+  /* Stop sensor scan and clear result buffer */
+  LESENSE->CMD = (LESENSE_CMD_STOP | LESENSE_CMD_CLEARBUF);
+
+  /* Reset LESENSE configuration registers */
+  LESENSE->CTRL      = _LESENSE_CTRL_RESETVALUE;
+  LESENSE->PERCTRL   = _LESENSE_PERCTRL_RESETVALUE;
+  LESENSE->DECCTRL   = _LESENSE_DECCTRL_RESETVALUE;
+  LESENSE->BIASCTRL  = _LESENSE_BIASCTRL_RESETVALUE;
+  LESENSE->CHEN      = _LESENSE_CHEN_RESETVALUE;
+  LESENSE->IDLECONF  = _LESENSE_IDLECONF_RESETVALUE;
+  LESENSE->ALTEXCONF = _LESENSE_ALTEXCONF_RESETVALUE;
+
+  /* Disable LESENSE to control GPIO pins */
+  LESENSE->ROUTE = _LESENSE_ROUTE_RESETVALUE;
+
+  /* Reset all channel configuration registers */
+  for (i = 0U; i < 16U; ++i)
+  {
+    LESENSE->CH[i].TIMING   = _LESENSE_CH_TIMING_RESETVALUE;
+    LESENSE->CH[i].INTERACT = _LESENSE_CH_INTERACT_RESETVALUE;
+    LESENSE->CH[i].EVAL     = _LESENSE_CH_EVAL_RESETVALUE;
+  }
+
+  /* Reset all decoder state configuration registers */
+  for (i = 0U; i < 16U; ++i)
+  {
+    LESENSE->ST[i].TCONFA = _LESENSE_ST_TCONFA_RESETVALUE;
+    LESENSE->ST[i].TCONFB = _LESENSE_ST_TCONFB_RESETVALUE;
+  }
+
+  /* Wait for the write operation to the CMD register to complete before
+     returning. */
+  while (LESENSE_SYNCBUSY_CMD & LESENSE->SYNCBUSY)
+    ;
+}
+
+
+/** @} (end addtogroup LESENSE) */
+/** @} (end addtogroup EM_Library) */
+
+#endif /* defined(LESENSE_COUNT) && (LESENSE_COUNT > 0) */