blob: 0246ebd31087ab9e9034cb8a39a6c0207e4aeece [file] [log] [blame]
/***************************************************************************//**
* @file em_lesense.c
* @brief Low Energy Sensor (LESENSE) Peripheral API
* @version 5.1.2
*******************************************************************************
* @section License
* <b>Copyright 2016 Silicon Laboratories, Inc. 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 emlib
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup LESENSE
* @brief Low Energy Sensor (LESENSE) Peripheral API
* @details
* This module contains functions to control the LESENSE peripheral of Silicon
* Labs 32-bit MCUs and SoCs. LESENSE is a low energy sensor interface capable
* of autonomously collecting and processing data from multiple sensors even
* when in EM2.
* @{
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#if defined(_LESENSE_ROUTE_MASK)
#define GENERIC_LESENSE_ROUTE LESENSE->ROUTE
#else
#define GENERIC_LESENSE_ROUTE LESENSE->ROUTEPEN
#endif
#if defined(_SILICON_LABS_32B_SERIES_0)
/* DACOUT mode only available on channel 0,1,2,3,12,13,14,15 */
#define DACOUT_SUPPORT 0xF00F
#else
/* DACOUT mode only available on channel 4,5,7,10,12,13 */
#define DACOUT_SUPPORT 0x34B0
#endif
/** @endcond */
/*******************************************************************************
************************** 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(const LESENSE_Init_TypeDef * init, bool reqReset)
{
/* Sanity check of initialization values */
EFM_ASSERT((uint32_t)init->timeCtrl.startDelay < 4U);
#if defined(_LESENSE_PERCTRL_DACPRESC_MASK)
EFM_ASSERT((uint32_t)init->perCtrl.dacPresc < 32U);
#endif
/* Reset LESENSE registers if requested. */
if (reqReset)
{
LESENSE_Reset();
}
/* Set sensor start delay for each channel. */
LESENSE_StartDelaySet((uint32_t)init->timeCtrl.startDelay);
#if defined(_LESENSE_TIMCTRL_AUXSTARTUP_MASK)
/* Configure the AUXHRFCO startup delay. */
LESENSE->TIMCTRL = (LESENSE->TIMCTRL & (~_LESENSE_TIMCTRL_AUXSTARTUP_MASK))
| (init->timeCtrl.delayAuxStartup << _LESENSE_TIMCTRL_AUXSTARTUP_SHIFT);
#endif
/* 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
#if defined(_LESENSE_CTRL_ACMP0INV_MASK)
| ((uint32_t)init->coreCtrl.invACMP0 << _LESENSE_CTRL_ACMP0INV_SHIFT)
| ((uint32_t)init->coreCtrl.invACMP1 << _LESENSE_CTRL_ACMP1INV_SHIFT)
#endif
| ((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.dacCh1Data << _LESENSE_PERCTRL_DACCH1DATA_SHIFT)
#if defined(_LESENSE_PERCTRL_DACCH0CONV_MASK)
| ((uint32_t)init->perCtrl.dacCh0ConvMode << _LESENSE_PERCTRL_DACCH0CONV_SHIFT)
| ((uint32_t)init->perCtrl.dacCh0OutMode << _LESENSE_PERCTRL_DACCH0OUT_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
#endif
| ((uint32_t)init->perCtrl.acmp0Mode << _LESENSE_PERCTRL_ACMP0MODE_SHIFT)
| ((uint32_t)init->perCtrl.acmp1Mode << _LESENSE_PERCTRL_ACMP1MODE_SHIFT)
#if defined(_LESENSE_PERCTRL_ACMP0INV_MASK)
| ((uint32_t)init->coreCtrl.invACMP0 << _LESENSE_PERCTRL_ACMP0INV_SHIFT)
| ((uint32_t)init->coreCtrl.invACMP1 << _LESENSE_PERCTRL_ACMP1INV_SHIFT)
#endif
#if defined(_LESENSE_PERCTRL_DACCONVTRIG_MASK)
| ((uint32_t)init->perCtrl.dacScan << _LESENSE_PERCTRL_DACCONVTRIG_SHIFT)
#endif
| (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 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 scanMode,
bool 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 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 clk,
LESENSE_ClkPresc_TypeDef 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(const LESENSE_ChAll_TypeDef * confChAll)
{
uint32_t i;
/* Iterate through all the 16 channels */
for (i = 0U; i < LESENSE_NUM_CHANNELS; ++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(const LESENSE_ChDesc_TypeDef * confCh,
uint32_t chIdx)
{
uint32_t tmp; /* Service variable. */
/* Sanity check of configuration parameters */
EFM_ASSERT(chIdx < LESENSE_NUM_CHANNELS);
EFM_ASSERT(confCh->exTime <= (_LESENSE_CH_TIMING_EXTIME_MASK >> _LESENSE_CH_TIMING_EXTIME_SHIFT));
EFM_ASSERT(confCh->measDelay <= (_LESENSE_CH_TIMING_MEASUREDLY_MASK >> _LESENSE_CH_TIMING_MEASUREDLY_SHIFT));
#if defined(_SILICON_LABS_32B_SERIES_0)
// Sample delay on other devices are 8 bits which fits perfectly in uint8_t
EFM_ASSERT(confCh->sampleDelay <= (_LESENSE_CH_TIMING_SAMPLEDLY_MASK >> _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT));
#endif
/* 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);
if (confCh->chPinExMode == lesenseChPinExDACOut)
{
EFM_ASSERT((0x1 << chIdx) & DACOUT_SUPPORT);
}
#if defined(_LESENSE_IDLECONF_CH0_DACCH0)
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))));
#endif
/* 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,
confCh->exTime,
confCh->sampleDelay,
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)
#if defined(_LESENSE_CH_EVAL_MODE_MASK)
| ((uint32_t)confCh->evalMode << _LESENSE_CH_EVAL_MODE_SHIFT)
#endif
;
/* Configure analog comparator (ACMP) threshold and decision threshold for
* counter separately with the function provided for that. */
LESENSE_ChannelThresSet(chIdx,
confCh->acmpThres,
confCh->cntThres);
/* Enable/disable interrupts on channel */
BUS_RegBitWrite(&LESENSE->IEN, chIdx, confCh->enaInt);
/* Enable/disable CHchIdx pin. */
BUS_RegBitWrite(&GENERIC_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(const LESENSE_ConfAltEx_TypeDef * 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(&GENERIC_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;
#if defined(_LESENSE_CTRL_ALTEXMAP_ACMP)
case lesenseAltExMapACMP:
#else
case lesenseAltExMapCH:
#endif
/* 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(&GENERIC_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 chIdx,
bool enaScanCh,
bool 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(&GENERIC_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. */
GENERIC_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 chIdx,
uint8_t exTime,
uint8_t sampleDelay,
uint16_t measDelay)
{
/* Sanity check of parameters. */
EFM_ASSERT(exTime <= (_LESENSE_CH_TIMING_EXTIME_MASK >> _LESENSE_CH_TIMING_EXTIME_SHIFT));
EFM_ASSERT(measDelay <= (_LESENSE_CH_TIMING_MEASUREDLY_MASK >> _LESENSE_CH_TIMING_MEASUREDLY_SHIFT));
#if defined(_SILICON_LABS_32B_SERIES_0)
// Sample delay on other devices are 8 bits which fits perfectly in uint8_t
EFM_ASSERT(sampleDelay <= (_LESENSE_CH_TIMING_SAMPLEDLY_MASK >> _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT));
#endif
/* 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 chIdx,
uint16_t acmpThres,
uint16_t 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 < LESENSE_NUM_CHANNELS);
/* 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 & ~(0xFFF);
/* Set the ACMP threshold value to the INTERACT register of channel chIdx. */
tmp |= (uint32_t)acmpThres;
/* 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;
}
#if defined(_LESENSE_CH_EVAL_MODE_MASK)
/***************************************************************************//**
* @brief
* Configure Sliding Window evaluation mode for a specific channel
*
* @details
* This function will configure the evaluation mode, the initial
* sensor measurement (COMPTHRES) and the window size. For other channel
* related configuration see the @ref LESENSE_ChannelConfig() function.
*
* @warning
* Beware that the step size and window size configuration are global to all
* LESENSE channels and use the same register field in the hardware. This
* means that any windowSize configuration passed to this function will
* apply for all channels and override all other stepSize/windowSize
* configurations.
*
* @param[in] chIdx
* Identifier of the scan channel. Valid range: 0-15.
*
* @param[in] windowSize
* Window size to be used on all channels.
*
* @param[in] initValue
* The initial sensor value for the channel.
******************************************************************************/
void LESENSE_ChannelSlidingWindow(uint8_t chIdx,
uint32_t windowSize,
uint32_t initValue)
{
LESENSE_CH_TypeDef * ch = &LESENSE->CH[chIdx];
LESENSE_WindowSizeSet(windowSize);
ch->EVAL = (ch->EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK | _LESENSE_CH_EVAL_MODE_MASK))
| (initValue << _LESENSE_CH_EVAL_COMPTHRES_SHIFT)
| LESENSE_CH_EVAL_MODE_SLIDINGWIN;
}
/***************************************************************************//**
* @brief
* Configure step detection evaluation mode for a specific channel
*
* @details
* This function will configure the evaluation mode, the initial
* sensor measurement (COMPTHRES) and the window size. For other channel
* related configuration see the @ref LESENSE_ChannelConfig() function.
*
* @warning
* Beware that the step size and window size configuration are global to all
* LESENSE channels and use the same register field in the hardware. This
* means that any stepSize configuration passed to this function will
* apply for all channels and override all other stepSize/windowSize
* configurations.
*
* @param[in] chIdx
* Identifier of the scan channel. Valid range: 0-15.
*
* @param[in] stepSize
* Step size to be used on all channels.
*
* @param[in] initValue
* The initial sensor value for the channel.
******************************************************************************/
void LESENSE_ChannelStepDetection(uint8_t chIdx,
uint32_t stepSize,
uint32_t initValue)
{
LESENSE_CH_TypeDef * ch = &LESENSE->CH[chIdx];
LESENSE_StepSizeSet(stepSize);
ch->EVAL = (ch->EVAL & ~(_LESENSE_CH_EVAL_COMPTHRES_MASK | _LESENSE_CH_EVAL_MODE_MASK))
| (initValue << _LESENSE_CH_EVAL_COMPTHRES_SHIFT)
| LESENSE_CH_EVAL_MODE_STEPDET;
}
/***************************************************************************//**
* @brief
* Set the window size for all LESENSE channels.
*
* @details
* The window size is used by all channels that are configured as
* @ref lesenseEvalModeSlidingWindow.
*
* @warning
* The window size configuration is using the same register field as the
* step detection size. So the window size configuration will have an
* effect on channels configured with the @ref lesenseEvalModeStepDetection
* evaluation mode as well.
*
* @param[in] windowSize
* The window size to use for all channels.
******************************************************************************/
void LESENSE_WindowSizeSet(uint32_t windowSize)
{
LESENSE->EVALCTRL = (LESENSE->EVALCTRL & ~_LESENSE_EVALCTRL_WINSIZE_MASK)
| windowSize;
}
/***************************************************************************//**
* @brief
* Set the step size for all LESENSE channels.
*
* @details
* The step size is configured using the same register field as use to
* configure window size. So calling this function will overwrite any
* previously configured window size as done by the
* @ref LESENSE_WindowSizeSet() function.
*
* @param[in] stepSize
* The step size to use for all channels.
******************************************************************************/
void LESENSE_StepSizeSet(uint32_t stepSize)
{
LESENSE_WindowSizeSet(stepSize);
}
#endif
/***************************************************************************//**
* @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 or 32) LESENSE decoder states.
******************************************************************************/
void LESENSE_DecoderStateAllConfig(const LESENSE_DecStAll_TypeDef * confDecStAll)
{
uint32_t i;
/* Iterate through all the 16 or 32 decoder states. */
for (i = 0U; i < LESENSE_NUM_DECODER_STATES; ++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) or (0-31) depending on device.
******************************************************************************/
void LESENSE_DecoderStateConfig(const LESENSE_DecStDesc_TypeDef * confDecSt,
uint32_t decSt)
{
/* Sanity check of configuration parameters */
EFM_ASSERT(decSt < LESENSE_NUM_DECODER_STATES);
EFM_ASSERT((uint32_t)confDecSt->confA.compMask < 16U);
EFM_ASSERT((uint32_t)confDecSt->confA.compVal < 16U);
EFM_ASSERT((uint32_t)confDecSt->confA.nextState < LESENSE_NUM_DECODER_STATES);
EFM_ASSERT((uint32_t)confDecSt->confB.compMask < 16U);
EFM_ASSERT((uint32_t)confDecSt->confB.compVal < 16U);
EFM_ASSERT((uint32_t)confDecSt->confB.nextState < LESENSE_NUM_DECODER_STATES);
/* 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 or 0-31
* depending on device.
******************************************************************************/
void LESENSE_DecoderStateSet(uint32_t decSt)
{
EFM_ASSERT(decSt <= _LESENSE_DECSTATE_DECSTATE_MASK);
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;
}
#if defined(_LESENSE_PRSCTRL_MASK)
/***************************************************************************//**
* @brief
* Enable or disable PRS output from the LESENSE decoder.
*
* @param[in] enable
* enable/disable the PRS output from the LESENSE decoder. true to enable and
* false to disable.
*
* @param[in] decMask
* Decoder state compare value mask
*
* @param[in] decVal
* Decoder state compare value.
******************************************************************************/
void LESENSE_DecoderPrsOut(bool enable, uint32_t decMask, uint32_t decVal)
{
LESENSE->PRSCTRL = (enable << _LESENSE_PRSCTRL_DECCMPEN_SHIFT)
| (decMask << _LESENSE_PRSCTRL_DECCMPMASK_SHIFT)
| (decVal << _LESENSE_PRSCTRL_DECCMPVAL_SHIFT);
}
#endif
/***************************************************************************//**
* @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;
#if defined(_LESENSE_EVALCTRL_MASK)
LESENSE->EVALCTRL = _LESENSE_EVALCTRL_RESETVALUE;
LESENSE->PRSCTRL = _LESENSE_PRSCTRL_RESETVALUE;
#endif
LESENSE->CHEN = _LESENSE_CHEN_RESETVALUE;
LESENSE->IDLECONF = _LESENSE_IDLECONF_RESETVALUE;
LESENSE->ALTEXCONF = _LESENSE_ALTEXCONF_RESETVALUE;
/* Disable LESENSE to control GPIO pins */
#if defined(_LESENSE_ROUTE_MASK)
LESENSE->ROUTE = _LESENSE_ROUTE_RESETVALUE;
#else
LESENSE->ROUTEPEN = _LESENSE_ROUTEPEN_RESETVALUE;
#endif
/* Reset all channel configuration registers */
for (i = 0U; i < LESENSE_NUM_CHANNELS; ++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 < LESENSE_NUM_DECODER_STATES; ++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 emlib) */
#endif /* defined(LESENSE_COUNT) && (LESENSE_COUNT > 0) */