1 /***************************************************************************//**
2  * @file
3  * @brief Capacitive Sense Module (CSEN) peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #include "em_csen.h"
32 #if defined(CSEN_COUNT) && (CSEN_COUNT > 0)
33 
34 #include "sl_assert.h"
35 #include "em_cmu.h"
36 #include <stddef.h>
37 
38 /***************************************************************************//**
39  * @addtogroup csen
40  * @{
41  ******************************************************************************/
42 
43 /*******************************************************************************
44  *******************************   DEFINES   ***********************************
45  ******************************************************************************/
46 
47 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
48 
49 /** Validation of CSEN register block pointer reference for assert statements. */
50 #define CSEN_REF_VALID(ref)   ((ref) == CSEN)
51 
52 /** @endcond */
53 
54 /*******************************************************************************
55  **************************   GLOBAL FUNCTIONS   *******************************
56  ******************************************************************************/
57 
58 /***************************************************************************//**
59  * @brief
60  *   Set the DM integrator initial value.
61  *
62  * @details
63  *   Sets the initial value of the integrator(s) for the Delta Modulation (DM)
64  *   converter. The initial value for the ramp-down integrator has no effect
65  *   if the low-frequency attenuation was not selected by the mode initialization
66  *   function @ref CSEN_InitMode().
67  *
68  * @note
69  *   Confirm CSEN is idle before calling this function.
70  *
71  * @param[in] csen
72  *   A pointer to the CSEN peripheral register block.
73  *
74  * @param[in] up
75  *   An initial value for the ramp-up integrator.
76  *
77  * @param[in] down
78  *  An initial value for the ramp-down integrator. Has no effect if low-frequency
79  *  attenuation is not configured.
80  ******************************************************************************/
CSEN_DMBaselineSet(CSEN_TypeDef * csen,uint32_t up,uint32_t down)81 void CSEN_DMBaselineSet(CSEN_TypeDef *csen, uint32_t up, uint32_t down)
82 {
83   EFM_ASSERT(up < 0x10000);
84   EFM_ASSERT(down < 0x10000);
85 
86   csen->DMBASELINE = (up << _CSEN_DMBASELINE_BASELINEUP_SHIFT)
87                      | (down << _CSEN_DMBASELINE_BASELINEDN_SHIFT);
88 }
89 
90 /***************************************************************************//**
91  * @brief
92  *   Initialize CSEN.
93  *
94  * @details
95  *   Initializes common functionality for all measurement types. In addition,
96  *   measurement mode must be configured. See @ref CSEN_InitMode().
97  *
98  * @note
99  *   This function will stop any ongoing conversion and disable CSEN.
100  *
101  * @param[in] csen
102  *   A pointer to the CSEN peripheral register block.
103  *
104  * @param[in] init
105  *   A pointer to the CSEN initialization structure.
106  ******************************************************************************/
CSEN_Init(CSEN_TypeDef * csen,const CSEN_Init_TypeDef * init)107 void CSEN_Init(CSEN_TypeDef *csen, const CSEN_Init_TypeDef *init)
108 {
109   uint32_t tmp;
110 
111   EFM_ASSERT(CSEN_REF_VALID(csen));
112   EFM_ASSERT(init->warmUpCount < 4);
113 
114   /* Initialize CTRL. This will stop any conversion in progress. */
115   tmp = CSEN_CTRL_STM_DEFAULT;
116 
117   if (init->cpAccuracyHi) {
118     tmp |= CSEN_CTRL_CPACCURACY_HI;
119   }
120 
121   if (init->localSense) {
122     tmp |= _CSEN_CTRL_LOCALSENS_MASK;
123   }
124 
125   if (init->keepWarm) {
126     tmp |= CSEN_CTRL_WARMUPMODE_KEEPCSENWARM;
127   }
128 
129   csen->CTRL = tmp;
130 
131   /* Initialize TIMCTRL. */
132   csen->TIMCTRL = (init->warmUpCount << _CSEN_TIMCTRL_WARMUPCNT_SHIFT)
133                   | (init->pcReload << _CSEN_TIMCTRL_PCTOP_SHIFT)
134                   | (init->pcPrescale << _CSEN_TIMCTRL_PCPRESC_SHIFT);
135 
136   /* PRSSEL only has one field */
137   csen->PRSSEL = init->prsSel << _CSEN_PRSSEL_PRSSEL_SHIFT;
138 
139   /* Set input selections for inputs 0 to 31. */
140   csen->SCANINPUTSEL0 = (init->input0To7 << _CSEN_SCANINPUTSEL0_INPUT0TO7SEL_SHIFT)
141                         | (init->input8To15 << _CSEN_SCANINPUTSEL0_INPUT8TO15SEL_SHIFT)
142                         | (init->input16To23 << _CSEN_SCANINPUTSEL0_INPUT16TO23SEL_SHIFT)
143                         | (init->input24To31 << _CSEN_SCANINPUTSEL0_INPUT24TO31SEL_SHIFT);
144 
145   /* Set input selections for inputs 32 to 63. */
146   csen->SCANINPUTSEL1 = (init->input32To39 << _CSEN_SCANINPUTSEL1_INPUT32TO39SEL_SHIFT)
147                         | (init->input40To47 << _CSEN_SCANINPUTSEL1_INPUT40TO47SEL_SHIFT)
148                         | (init->input48To55 << _CSEN_SCANINPUTSEL1_INPUT48TO55SEL_SHIFT)
149                         | (init->input56To63 << _CSEN_SCANINPUTSEL1_INPUT56TO63SEL_SHIFT);
150 }
151 
152 /***************************************************************************//**
153  * @brief
154  *   Initialize a CSEN measurement mode.
155  *
156  * @details
157  *   Used to configure any type of measurement mode. After the measurement
158  *   has been configured, calling @ref CSEN_Enable() will enable CSEN and
159  *   allow it to start a conversion from the selected trigger source. To
160  *   manually start a conversion, use @ref CSEN_Start(). To check if a
161  *   conversion is in progress, use @ref CSEN_IsBusy(), or alternatively
162  *   use the interrupt flags returned by @ref CSEN_IntGet() to detect when
163  *   a conversion is completed.
164  *
165  * @note
166  *   This function will stop any ongoing conversion and disable CSEN.
167  *
168  * @param[in] csen
169  *   A pointer to the CSEN peripheral register block.
170  *
171  * @param[in] init
172  *   A pointer to the CSEN measurement mode initialization structure.
173  ******************************************************************************/
CSEN_InitMode(CSEN_TypeDef * csen,const CSEN_InitMode_TypeDef * init)174 void CSEN_InitMode(CSEN_TypeDef *csen, const CSEN_InitMode_TypeDef *init)
175 {
176   uint32_t tmp;
177 
178   EFM_ASSERT(CSEN_REF_VALID(csen));
179   EFM_ASSERT(init->dmIterPerCycle < 0x10);
180   EFM_ASSERT(init->dmCycles < 0x10);
181 
182   /* Initialize CTRL. This will stop any conversion in progress.
183    * These composite inputs set multiple fields. They do not need
184    * to be shifted. */
185   tmp = ((uint32_t)init->sampleMode
186          | (uint32_t)init->convSel
187          | (uint32_t)init->cmpMode);
188 
189   tmp |= (init->trigSel << _CSEN_CTRL_STM_SHIFT)
190          | (init->accMode << _CSEN_CTRL_ACU_SHIFT)
191          | (init->sarRes << _CSEN_CTRL_SARCR_SHIFT);
192 
193   if (init->enableDma) {
194     tmp |= CSEN_CTRL_DMAEN_ENABLE;
195   }
196 
197   if (init->sumOnly) {
198     tmp |= CSEN_CTRL_DRSF_ENABLE;
199   }
200 
201   if (init->autoGnd) {
202     tmp |= CSEN_CTRL_AUTOGND_ENABLE;
203   }
204 
205   /* Preserve the fields that were initialized by CSEN_Init(). */
206   tmp |= csen->CTRL & (_CSEN_CTRL_CPACCURACY_MASK
207                        | _CSEN_CTRL_LOCALSENS_MASK
208                        | _CSEN_CTRL_WARMUPMODE_MASK);
209 
210   csen->CTRL = tmp;
211 
212   /* EMACTRL only has one field. */
213   csen->EMACTRL = init->emaSample << _CSEN_EMACTRL_EMASAMPLE_SHIFT;
214 
215   /* CMPTHR only has one field. */
216   csen->CMPTHR = init->cmpThr << _CSEN_CMPTHR_CMPTHR_SHIFT;
217 
218   /* SINGLECTRL only has one field. */
219   csen->SINGLECTRL = init->singleSel << _CSEN_SINGLECTRL_SINGLESEL_SHIFT;
220 
221   /* Set all input enables. */
222   csen->SCANMASK0 = init->inputMask0;
223   csen->SCANMASK1 = init->inputMask1;
224 
225   /* Initialize DMCFG. */
226   tmp = (init->dmRes << _CSEN_DMCFG_CRMODE_SHIFT)
227         | (init->dmCycles << _CSEN_DMCFG_DMCR_SHIFT)
228         | (init->dmIterPerCycle << _CSEN_DMCFG_DMR_SHIFT)
229         | (init->dmDelta << _CSEN_DMCFG_DMG_SHIFT);
230 
231   if (init->dmFixedDelta) {
232     tmp |= CSEN_DMCFG_DMGRDIS;
233   }
234 
235   csen->DMCFG = tmp;
236 
237   /* Initialize ANACTRL. */
238   csen->ANACTRL = (init->resetPhase << _CSEN_ANACTRL_TRSTPROG_SHIFT)
239                   | (init->driveSel << _CSEN_ANACTRL_IDACIREFS_SHIFT)
240                   | (init->gainSel << _CSEN_ANACTRL_IREFPROG_SHIFT);
241 }
242 
243 /***************************************************************************//**
244  * @brief
245  *   Reset CSEN to same state that it was in after a hardware reset.
246  *
247  * @param[in] csen
248  *   A pointer to the CSEN peripheral register block.
249  ******************************************************************************/
CSEN_Reset(CSEN_TypeDef * csen)250 void CSEN_Reset(CSEN_TypeDef *csen)
251 {
252   EFM_ASSERT(CSEN_REF_VALID(csen));
253 
254   /* Resetting CTRL stops any conversion in progress. */
255   csen->CTRL          = _CSEN_CTRL_RESETVALUE;
256   csen->TIMCTRL       = _CSEN_TIMCTRL_RESETVALUE;
257   csen->PRSSEL        = _CSEN_PRSSEL_RESETVALUE;
258   csen->DATA          = _CSEN_DATA_RESETVALUE;
259   csen->SCANMASK0     = _CSEN_SCANMASK0_RESETVALUE;
260   csen->SCANINPUTSEL0 = _CSEN_SCANINPUTSEL0_RESETVALUE;
261   csen->SCANMASK1     = _CSEN_SCANMASK1_RESETVALUE;
262   csen->SCANINPUTSEL1 = _CSEN_SCANINPUTSEL1_RESETVALUE;
263   csen->CMPTHR        = _CSEN_CMPTHR_RESETVALUE;
264   csen->EMA           = _CSEN_EMA_RESETVALUE;
265   csen->EMACTRL       = _CSEN_EMACTRL_RESETVALUE;
266   csen->SINGLECTRL    = _CSEN_SINGLECTRL_RESETVALUE;
267   csen->DMBASELINE    = _CSEN_DMBASELINE_RESETVALUE;
268   csen->DMCFG         = _CSEN_DMCFG_RESETVALUE;
269   csen->ANACTRL       = _CSEN_ANACTRL_RESETVALUE;
270   csen->IEN           = _CSEN_IEN_RESETVALUE;
271   csen->IFC           = _CSEN_IF_MASK;
272 }
273 
274 /** @} (end addtogroup csen) */
275 #endif /* defined(CSEN_COUNT) && (CSEN_COUNT > 0) */
276