em_lesense.c 40 KB

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