| /***************************************************************************//** |
| * @file em_lesense.c |
| * @brief Low Energy Sensor (LESENSE) Peripheral API |
| * @version 5.6.0 |
| ******************************************************************************* |
| * # License |
| * <b>Copyright 2016 Silicon Laboratories, Inc. 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. |
| * See the initialization parameter type definition |
| * (@ref LESENSE_Init_TypeDef) for more details. |
| * |
| * @note |
| * @ref LESENSE_Init() is designed to initialize 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 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 for the LESENSE to work as |
| * intended. |
| * (When configuring pins, one should remember to consider the sequence of |
| * configuration to avoid unintended pulses/glitches on output |
| * pins.) |
| * |
| * @param[in] init |
| * The LESENSE initialization structure. |
| * |
| * @param[in] reqReset |
| * Request to call @ref LESENSE_Reset() first to initialize all |
| * LESENSE registers with default values. |
| ******************************************************************************/ |
| 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 the 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, and 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); |
| |
| /* The LESENSE peripheral control configuration. |
| * Set DAC0 and DAC1 data source, conversion mode, and output mode. Set the DAC |
| * prescaler and reference. Set ACMP0 and ACMP1 control mode. Set the ACMP and DAC |
| * duty cycle (warm up) mode. */ |
| LESENSE->PERCTRL = 0 |
| #if defined(_LESENSE_PERCTRL_DACCH0EN_MASK) |
| | ((uint32_t)init->perCtrl.dacCh0En << _LESENSE_PERCTRL_DACCH0EN_SHIFT) |
| | ((uint32_t)init->perCtrl.dacCh1En << _LESENSE_PERCTRL_DACCH1EN_SHIFT) |
| #endif |
| | ((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 |
| #if defined(_LESENSE_PERCTRL_DACCONVTRIG_MASK) |
| | ((uint32_t)init->perCtrl.dacStartupHalf << _LESENSE_PERCTRL_DACSTARTUP_SHIFT) |
| | ((uint32_t)init->perCtrl.dacScan << _LESENSE_PERCTRL_DACCONVTRIG_SHIFT) |
| #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 |
| | (uint32_t)init->perCtrl.warmupMode; |
| |
| /* The LESENSE decoder general control configuration. |
| * Set the decoder input source and 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 the 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 the initial LESENSE decoder state. */ |
| LESENSE_DecoderStateSet((uint32_t)init->decCtrl.initState); |
| |
| /* The LESENSE bias control configuration. */ |
| LESENSE->BIASCTRL = (uint32_t)init->coreCtrl.biasMode; |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Set the scan frequency for periodic scanning. |
| * |
| * @details |
| * This function only applies to LESENSE if a period counter is 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); |
| } |
| |
| /* The maximum value of pcPresc is 128. AS a result, using the reference frequency less than |
| * 33554431 Hz (33.554431 MHz), the frequency calculation in the while loop |
| * below will not overflow. */ |
| EFM_ASSERT(refFreq < ((uint32_t)UINT32_MAX / 128UL)); |
| |
| /* A sanity check of scan frequency value. */ |
| EFM_ASSERT((scanFreq > 0U) && (scanFreq <= refFreq)); |
| |
| /* Calculate the minimum necessary prescaler value to provide the |
| * biggest possible resolution for setting the scan frequency. |
| * The 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 the 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 the 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 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. |
| * Be aware of the effects of the non-atomic Read-Modify-Write cycle. |
| * |
| * @param[in] scanMode |
| * Select the location to map LESENSE alternate excitation channels. |
| * @li lesenseScanStartPeriodic - A new scan is started each time the period |
| * counter overflows. |
| * @li lesenseScanStartOneShot - A single scan is performed when |
| * LESENSE_ScanStart() is called. |
| * @li lesenseScanStartPRS - A new scan is triggered by pulse on the 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. |
| * Be aware of 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 |
| * (enumeration) to unsigned long (uint32_t). */ |
| tmp |= (uint32_t)scanMode; |
| |
| /* Write the new value to the CTRL register. */ |
| LESENSE->CTRL = tmp; |
| |
| /* Start the sensor scanning if requested. */ |
| if (start) { |
| LESENSE_ScanStart(); |
| } |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Set the start delay of the sensor interaction on each channel. |
| * |
| * @details |
| * This function sets the start delay of the 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. |
| * Be aware of the effects of the non-atomic Read-Modify-Write cycle. |
| * |
| * @param[in] startDelay |
| * A number of LFACLK cycles to delay. A 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 the startDelay. */ |
| EFM_ASSERT(startDelay < 4U); |
| |
| /* Save the TIMCTRL register value to tmp. |
| * Be aware of 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 the 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. See |
| * documentation for more details. |
| * |
| * @note |
| * If AUXHFRCO is used for excitation timing, LFACLK can't exceed 500 kHz. |
| * LFACLK can't exceed 50 kHz if the ACMP threshold level (ACMPTHRES) is not |
| * equal for all channels. |
| * |
| * @param[in] clk |
| * Select the clock to prescale. |
| * @li lesenseClkHF - set AUXHFRCO clock divisor for HF timer. |
| * @li lesenseClkLF - set LFACLKles clock divisor for LF timer. |
| * |
| * @param[in] clkDiv |
| * The clock divisor value. A valid range depends on the @p clk value. |
| ******************************************************************************/ |
| void LESENSE_ClkDivSet(LESENSE_ChClk_TypeDef clk, |
| LESENSE_ClkPresc_TypeDef clkDiv) |
| { |
| uint32_t tmp; |
| |
| /* Select the clock to prescale. */ |
| switch (clk) { |
| case lesenseClkHF: |
| /* A sanity check of the clock divisor for the HF clock. */ |
| EFM_ASSERT((uint32_t)clkDiv <= lesenseClkDiv_8); |
| |
| /* Clear the current AUXPRESC settings. */ |
| tmp = LESENSE->TIMCTRL & ~(_LESENSE_TIMCTRL_AUXPRESC_MASK); |
| |
| /* Set the 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 the LESENSE_TIMCTRL register. */ |
| LESENSE->TIMCTRL = tmp; |
| break; |
| |
| default: |
| EFM_ASSERT(0); |
| break; |
| } |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Configure all (16) LESENSE sensor channels. |
| * |
| * @details |
| * This function configures all sensor channels of the LESENSE interface. |
| * See 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 for LESENSE to work as intended. |
| * (When configuring pins, consider the sequence of the |
| * configuration to avoid unintended pulses/glitches on output |
| * pins.) |
| * |
| * @param[in] confChAll |
| * A configuration structure for all (16) LESENSE sensor channels. |
| ******************************************************************************/ |
| void LESENSE_ChannelAllConfig(const LESENSE_ChAll_TypeDef * confChAll) |
| { |
| uint32_t i; |
| |
| /* Iterate through all 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. |
| * See 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, be aware |
| * of these effects and the right timing to call this function. |
| * Parameter @p useAltEx must be true in the channel configuration to |
| * use alternate excitation pins. |
| * |
| * @param[in] confCh |
| * A configuration structure for a single LESENSE sensor channel. |
| * |
| * @param[in] chIdx |
| * A channel index to configure (0-15). |
| ******************************************************************************/ |
| void LESENSE_ChannelConfig(const LESENSE_ChDesc_TypeDef * confCh, |
| uint32_t chIdx) |
| { |
| uint32_t tmp; /* A service variable. */ |
| |
| /* A 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 maximum value of acmpThres depends on other |
| * configuration parameters. Check the parameter description of acmpThres |
| * 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 the chIdx setup in LESENSE idle phase. |
| * Read-modify-write to support reconfiguration during the LESENSE |
| * operation. */ |
| tmp = (LESENSE->IDLECONF & ~((uint32_t)0x3UL << (chIdx * 2UL))); |
| tmp |= ((uint32_t)confCh->chPinIdleMode << (chIdx * 2UL)); |
| LESENSE->IDLECONF = tmp; |
| |
| /* A channel-specific timing configuration on scan channel chIdx. |
| * Set excitation time, sampling delay, and measurement delay. */ |
| LESENSE_ChannelTimingSet(chIdx, |
| confCh->exTime, |
| confCh->sampleDelay, |
| confCh->measDelay); |
| |
| /* A 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 the 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 the analog comparator (ACMP) threshold and decision threshold for |
| * the 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. See the configuration parameter type definition |
| * (LESENSE_ConfAltEx_TypeDef) for more details. |
| * |
| * @note |
| * The @p useAltEx parameter must be true in the channel configuration structure |
| * (LESENSE_ChDesc_TypeDef) to use alternate excitation pins on the |
| * channel. |
| * |
| * @param[in] confAltEx |
| * A configuration structure for LESENSE alternate excitation pins. |
| ******************************************************************************/ |
| void LESENSE_AltExConfig(const LESENSE_ConfAltEx_TypeDef * confAltEx) |
| { |
| uint32_t i; |
| uint32_t tmp; |
| |
| /* Configure the alternate excitation mapping. |
| * Atomic read-modify-write using BUS_RegBitWrite function to |
| * support reconfiguration during the 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 the alternate excitation pin i. |
| * Atomic read-modify-write using BUS_RegBitWrite function to |
| * support reconfiguration during the LESENSE operation. */ |
| BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE, |
| (16UL + i), |
| confAltEx->AltEx[i].enablePin); |
| |
| /* Set up the idle phase state of the alternate excitation pin i. |
| * Read-modify-write to support reconfiguration during the 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 16 alternate excitation channels. */ |
| for (i = 0U; i < 16U; ++i) { |
| /* Enable/disable the alternate ACMP excitation channel pin i. */ |
| /* An atomic read-modify-write using BUS_RegBitWrite function to |
| * support reconfiguration during the LESENSE operation. */ |
| BUS_RegBitWrite(&GENERIC_LESENSE_ROUTE, |
| i, |
| confAltEx->AltEx[i].enablePin); |
| } |
| break; |
| default: |
| /* An 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 it. |
| * |
| * @note |
| * Users can enable/disable scan channels and the channel pin with |
| * the LESENSE_ChannelConfig() function, but only with a significant overhead. |
| * This simple function controls these parameters |
| * after the channel has been configured. |
| * |
| * @param[in] chIdx |
| * An identifier of the scan channel. A 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 bit fields. 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 the |
| * LESENSE_ChannelAllConfig() function, but only with a significant overhead. |
| * This simple function controls 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 with the |
| * LESENSE_ChannelConfig() function, but only with a significant overhead. |
| * This simple function controls these parameters |
| * after the channel has been configured. |
| * |
| * @param[in] chIdx |
| * An identifier of the scan channel. A valid range is 0-15. |
| * |
| * @param[in] exTime |
| * An excitation time on chIdx. The excitation will last exTime+1 excitation clock |
| * cycles. A valid range is 0-63 (6 bits). |
| * |
| * @param[in] sampleDelay |
| * Sample delay on chIdx. Sampling will occur after sampleDelay+1 sample clock |
| * cycles. A valid range is 0-127 (7 bits). |
| * |
| * @param[in] measDelay |
| * A measure delay on chIdx. Sensor measuring is delayed for measDelay+1 |
| * excitation clock cycles. A valid range is 0-127 (7 bits). |
| ******************************************************************************/ |
| void LESENSE_ChannelTimingSet(uint8_t chIdx, |
| uint8_t exTime, |
| uint8_t sampleDelay, |
| uint16_t measDelay) |
| { |
| /* A 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) |
| // A sample delay on other devices is 8 bits which fits perfectly in uint8_t. |
| EFM_ASSERT(sampleDelay <= (_LESENSE_CH_TIMING_SAMPLEDLY_MASK >> _LESENSE_CH_TIMING_SAMPLEDLY_SHIFT)); |
| #endif |
| |
| /* A channel-specific timing configuration on the scan channel chIdx. |
| * Setting excitation time, sampling delay, and 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 with the |
| * LESENSE_ChannelConfig() function, but only with a significant overhead. |
| * This simple function serves controls these parameters |
| * after the channel has been configured. |
| * |
| * @param[in] chIdx |
| * An identifier of the scan channel. A valid range is 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 |
| * A decision threshold for counter comparison. |
| * A valid range is 0-65535 (16 bits). |
| ******************************************************************************/ |
| void LESENSE_ChannelThresSet(uint8_t chIdx, |
| uint16_t acmpThres, |
| uint16_t cntThres) |
| { |
| uint32_t tmp; /* A temporary storage */ |
| |
| /* A sanity check for acmpThres only, cntThres is a 16 bit value. */ |
| EFM_ASSERT(acmpThres < 4096U); |
| /* A sanity check for the LESENSE channel ID. */ |
| EFM_ASSERT(chIdx < LESENSE_NUM_CHANNELS); |
| |
| /* Save the INTERACT register value of channel chIdx to tmp. |
| * Be aware of 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 the 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. |
| * Be aware of 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 the 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 a 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 |
| * Note 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 |
| * An identifier of the scan channel. A valid range is 0-15. |
| * |
| * @param[in] windowSize |
| * A 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 the 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 |
| * Note 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 |
| * An identifier of the scan channel. A valid range is 0-15. |
| * |
| * @param[in] stepSize |
| * A 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. As a result, 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 used to |
| * configure window size. Therefore, 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. |
| * See 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 |
| * A configuration structure for all (16 or 32) LESENSE decoder states. |
| ******************************************************************************/ |
| void LESENSE_DecoderStateAllConfig(const LESENSE_DecStAll_TypeDef * confDecStAll) |
| { |
| uint32_t i; |
| |
| /* Iterate through all 16 or 32 decoder states. */ |
| for (i = 0U; i < LESENSE_NUM_DECODER_STATES; ++i) { |
| /* A 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. |
| * See the configuration parameter type definition |
| * (LESENSE_DecStDesc_TypeDef) for more details. |
| * |
| * @param[in] confDecSt |
| * A configuration structure for a single LESENSE decoder state. |
| * |
| * @param[in] decSt |
| * A decoder state index to configure (0-15) or (0-31) depending on the 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 the state descriptor A (LESENSE_STi_TCONFA) for the 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 the 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 the 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 |
| * A decoder state to set as the current state. A valid range is 0-15 or 0-31, |
| * depending on the 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 the 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 the 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 |
| * A decoder state compare value mask. |
| * |
| * @param[in] decVal |
| * A decoder state comparison 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 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 expect some delay. The user may implement |
| * a separate function to write multiple command bits in the CMD register |
| * in one single operation 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 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 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 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 the 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 expect some delay. The user may implement |
| * a separate function to write multiple command bits in the CMD register |
| * in one single operation 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 the 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 the 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 expect some delay. The user may implement |
| * a separate function to write multiple command bits in the CMD register |
| * in one single operation 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 LESENSE registers. |
| * |
| * @note |
| * Resetting LESENSE registers is required in each reset or power-on cycle |
| * 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 the sensor scan and clear the 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) */ |