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