1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2019, 2023 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_cmp.h"
10
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.cmp"
14 #endif
15
16 /*******************************************************************************
17 * Prototypes
18 ******************************************************************************/
19 /*!
20 * @brief Get instance number for CMP module.
21 *
22 * @param base CMP peripheral base address
23 */
24 static uint32_t CMP_GetInstance(CMP_Type *base);
25
26 /*******************************************************************************
27 * Variables
28 ******************************************************************************/
29 /*! @brief Pointers to CMP bases for each instance. */
30 static CMP_Type *const s_cmpBases[] = CMP_BASE_PTRS;
31 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
32 /*! @brief Pointers to CMP clocks for each instance. */
33 static const clock_ip_name_t s_cmpClocks[] = CMP_CLOCKS;
34 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
35
36 /*******************************************************************************
37 * Codes
38 ******************************************************************************/
CMP_GetInstance(CMP_Type * base)39 static uint32_t CMP_GetInstance(CMP_Type *base)
40 {
41 uint32_t instance;
42
43 /* Find the instance index from base address mappings. */
44 for (instance = 0; instance < ARRAY_SIZE(s_cmpBases); instance++)
45 {
46 if (s_cmpBases[instance] == base)
47 {
48 break;
49 }
50 }
51
52 assert(instance < ARRAY_SIZE(s_cmpBases));
53
54 return instance;
55 }
56
57 /*!
58 * brief Initializes the CMP.
59 *
60 * This function initializes the CMP module. The operations included are as follows.
61 * - Enabling the clock for CMP module.
62 * - Configuring the comparator.
63 * - Enabling the CMP module.
64 * Note that for some devices, multiple CMP instances share the same clock gate. In this case, to enable the clock for
65 * any instance enables all CMPs. See the appropriate MCU reference manual for the clock assignment of the CMP.
66 *
67 * param base CMP peripheral base address.
68 * param config Pointer to the configuration structure.
69 */
CMP_Init(CMP_Type * base,const cmp_config_t * config)70 void CMP_Init(CMP_Type *base, const cmp_config_t *config)
71 {
72 assert(NULL != config);
73
74 uint8_t tmp8;
75
76 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
77 /* Enable the clock. */
78 CLOCK_EnableClock(s_cmpClocks[CMP_GetInstance(base)]);
79 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
80
81 /* Configure. */
82 CMP_Enable(base, false); /* Disable the CMP module during configuring. */
83 /* CMPx_CR1. */
84 tmp8 = (uint8_t)(base->CR1 & ~(CMP_CR1_PMODE_MASK | CMP_CR1_INV_MASK | CMP_CR1_COS_MASK | CMP_CR1_OPE_MASK));
85 if (true == config->enableHighSpeed)
86 {
87 tmp8 |= CMP_CR1_PMODE_MASK;
88 }
89 if (true == config->enableInvertOutput)
90 {
91 tmp8 |= CMP_CR1_INV_MASK;
92 }
93 if (true == config->useUnfilteredOutput)
94 {
95 tmp8 |= CMP_CR1_COS_MASK;
96 }
97 if (true == config->enablePinOut)
98 {
99 tmp8 |= CMP_CR1_OPE_MASK;
100 }
101 #if defined(FSL_FEATURE_CMP_HAS_TRIGGER_MODE) && FSL_FEATURE_CMP_HAS_TRIGGER_MODE
102 if (true == config->enableTriggerMode)
103 {
104 tmp8 |= CMP_CR1_TRIGM_MASK;
105 }
106 else
107 {
108 tmp8 &= ~(uint8_t)CMP_CR1_TRIGM_MASK;
109 }
110 #endif /* FSL_FEATURE_CMP_HAS_TRIGGER_MODE */
111 base->CR1 = tmp8;
112
113 /* CMPx_CR0. */
114 tmp8 = base->CR0 & ~(uint8_t)CMP_CR0_HYSTCTR_MASK;
115 tmp8 |= CMP_CR0_HYSTCTR(config->hysteresisMode);
116 base->CR0 = tmp8;
117
118 CMP_Enable(base, config->enableCmp); /* Enable the CMP module after configured or not. */
119 }
120
121 /*!
122 * brief De-initializes the CMP module.
123 *
124 * This function de-initializes the CMP module. The operations included are as follows.
125 * - Disabling the CMP module.
126 * - Disabling the clock for CMP module.
127 *
128 * This function disables the clock for the CMP.
129 * Note that for some devices, multiple CMP instances share the same clock gate. In this case, before disabling the
130 * clock for the CMP, ensure that all the CMP instances are not used.
131 *
132 * param base CMP peripheral base address.
133 */
CMP_Deinit(CMP_Type * base)134 void CMP_Deinit(CMP_Type *base)
135 {
136 // Disable the CMP module.
137 base->CR0 = 0U;
138 base->CR1 = 0U;
139
140 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
141 /* Disable the clock. */
142 CLOCK_DisableClock(s_cmpClocks[CMP_GetInstance(base)]);
143 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
144 }
145
146 /*!
147 * brief Initializes the CMP user configuration structure.
148 *
149 * This function initializes the user configuration structure to these default values.
150 * code
151 * config->enableCmp = true;
152 * config->hysteresisMode = kCMP_HysteresisLevel0;
153 * config->enableHighSpeed = false;
154 * config->enableInvertOutput = false;
155 * config->useUnfilteredOutput = false;
156 * config->enablePinOut = false;
157 * config->enableTriggerMode = false;
158 * endcode
159 * param config Pointer to the configuration structure.
160 */
CMP_GetDefaultConfig(cmp_config_t * config)161 void CMP_GetDefaultConfig(cmp_config_t *config)
162 {
163 assert(NULL != config);
164
165 /* Initializes the configure structure to zero. */
166 (void)memset(config, 0, sizeof(*config));
167
168 config->enableCmp = true; /* Enable the CMP module after initialization. */
169 config->hysteresisMode = kCMP_HysteresisLevel0;
170 config->enableHighSpeed = false;
171 config->enableInvertOutput = false;
172 config->useUnfilteredOutput = false;
173 config->enablePinOut = false;
174 #if defined(FSL_FEATURE_CMP_HAS_TRIGGER_MODE) && FSL_FEATURE_CMP_HAS_TRIGGER_MODE
175 config->enableTriggerMode = false;
176 #endif /* FSL_FEATURE_CMP_HAS_TRIGGER_MODE */
177 }
178
179 /*!
180 * brief Sets the input channels for the comparator.
181 *
182 * This function sets the input channels for the comparator.
183 * Note that two input channels cannot be set the same way in the application. When the user selects the same input
184 * from the analog mux to the positive and negative port, the comparator is disabled automatically.
185 *
186 * param base CMP peripheral base address.
187 * param positiveChannel Positive side input channel number. Available range is 0-7.
188 * param negativeChannel Negative side input channel number. Available range is 0-7.
189 */
CMP_SetInputChannels(CMP_Type * base,uint8_t positiveChannel,uint8_t negativeChannel)190 void CMP_SetInputChannels(CMP_Type *base, uint8_t positiveChannel, uint8_t negativeChannel)
191 {
192 uint8_t tmp8 = base->MUXCR;
193
194 tmp8 &= ~(uint8_t)(CMP_MUXCR_PSEL_MASK | CMP_MUXCR_MSEL_MASK);
195 tmp8 |= CMP_MUXCR_PSEL(positiveChannel) | CMP_MUXCR_MSEL(negativeChannel);
196 base->MUXCR = tmp8;
197 }
198
199 #if defined(FSL_FEATURE_CMP_HAS_DMA) && FSL_FEATURE_CMP_HAS_DMA
200 /*!
201 * brief Enables/disables the DMA request for rising/falling events.
202 *
203 * This function enables/disables the DMA request for rising/falling events. Either event triggers the generation of
204 * the DMA request from CMP if the DMA feature is enabled. Both events are ignored for generating the DMA request from
205 * the CMP
206 * if the DMA is disabled.
207 *
208 * param base CMP peripheral base address.
209 * param enable Enables or disables the feature.
210 */
CMP_EnableDMA(CMP_Type * base,bool enable)211 void CMP_EnableDMA(CMP_Type *base, bool enable)
212 {
213 uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
214
215 if (enable)
216 {
217 tmp8 |= CMP_SCR_DMAEN_MASK;
218 }
219 else
220 {
221 tmp8 &= ~(uint8_t)CMP_SCR_DMAEN_MASK;
222 }
223 base->SCR = tmp8;
224 }
225 #endif /* FSL_FEATURE_CMP_HAS_DMA */
226
227 /*!
228 * brief Configures the filter.
229 *
230 * param base CMP peripheral base address.
231 * param config Pointer to the configuration structure.
232 */
CMP_SetFilterConfig(CMP_Type * base,const cmp_filter_config_t * config)233 void CMP_SetFilterConfig(CMP_Type *base, const cmp_filter_config_t *config)
234 {
235 assert(NULL != config);
236
237 uint8_t tmp8;
238
239 #if defined(FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT) && FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT
240 /* Choose the clock source for sampling. */
241 if (config->enableSample)
242 {
243 base->CR1 |= CMP_CR1_SE_MASK; /* Choose the external SAMPLE clock. */
244 }
245 else
246 {
247 base->CR1 &= (uint8_t)(~CMP_CR1_SE_MASK); /* Choose the internal divided bus clock. */
248 }
249 #endif /* FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT */
250 /* Set the filter count. */
251 tmp8 = (uint8_t)(base->CR0 & ~CMP_CR0_FILTER_CNT_MASK);
252 tmp8 |= CMP_CR0_FILTER_CNT(config->filterCount);
253 base->CR0 = tmp8;
254 /* Set the filter period. It is used as the divider to bus clock. */
255 base->FPR = CMP_FPR_FILT_PER(config->filterPeriod);
256 }
257
258 /*!
259 * brief Configures the internal DAC.
260 *
261 * param base CMP peripheral base address.
262 * param config Pointer to the configuration structure. "NULL" disables the feature.
263 */
CMP_SetDACConfig(CMP_Type * base,const cmp_dac_config_t * config)264 void CMP_SetDACConfig(CMP_Type *base, const cmp_dac_config_t *config)
265 {
266 uint8_t tmp8 = 0U;
267
268 if (NULL == config)
269 {
270 /* Passing "NULL" as input parameter means no available configuration. So the DAC feature is disabled.*/
271 base->DACCR = 0U;
272 return;
273 }
274 /* CMPx_DACCR. */
275 tmp8 |= CMP_DACCR_DACEN_MASK; /* Enable the internal DAC. */
276 if (kCMP_VrefSourceVin2 == config->referenceVoltageSource)
277 {
278 tmp8 |= CMP_DACCR_VRSEL_MASK;
279 }
280 tmp8 |= CMP_DACCR_VOSEL(config->DACValue);
281
282 base->DACCR = tmp8;
283 }
284
285 /*!
286 * brief Enables the interrupts.
287 *
288 * param base CMP peripheral base address.
289 * param mask Mask value for interrupts. See "_cmp_interrupt_enable".
290 */
CMP_EnableInterrupts(CMP_Type * base,uint32_t mask)291 void CMP_EnableInterrupts(CMP_Type *base, uint32_t mask)
292 {
293 uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
294
295 if (0U != ((uint32_t)kCMP_OutputRisingInterruptEnable & mask))
296 {
297 tmp8 |= CMP_SCR_IER_MASK;
298 }
299 if (0U != ((uint32_t)kCMP_OutputFallingInterruptEnable & mask))
300 {
301 tmp8 |= CMP_SCR_IEF_MASK;
302 }
303 base->SCR = tmp8;
304 }
305
306 /*!
307 * brief Disables the interrupts.
308 *
309 * param base CMP peripheral base address.
310 * param mask Mask value for interrupts. See "_cmp_interrupt_enable".
311 */
CMP_DisableInterrupts(CMP_Type * base,uint32_t mask)312 void CMP_DisableInterrupts(CMP_Type *base, uint32_t mask)
313 {
314 uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
315
316 if (0U != ((uint32_t)kCMP_OutputRisingInterruptEnable & mask))
317 {
318 tmp8 &= ~(uint8_t)CMP_SCR_IER_MASK;
319 }
320 if (0U != ((uint32_t)kCMP_OutputFallingInterruptEnable & mask))
321 {
322 tmp8 &= ~(uint8_t)CMP_SCR_IEF_MASK;
323 }
324 base->SCR = tmp8;
325 }
326
327 /*!
328 * brief Gets the status flags.
329 *
330 * param base CMP peripheral base address.
331 *
332 * return Mask value for the asserted flags. See "_cmp_status_flags".
333 */
CMP_GetStatusFlags(CMP_Type * base)334 uint32_t CMP_GetStatusFlags(CMP_Type *base)
335 {
336 uint32_t ret32 = 0U;
337
338 if (0U != (CMP_SCR_CFR_MASK & base->SCR))
339 {
340 ret32 |= (uint32_t)kCMP_OutputRisingEventFlag;
341 }
342 if (0U != (CMP_SCR_CFF_MASK & base->SCR))
343 {
344 ret32 |= (uint32_t)kCMP_OutputFallingEventFlag;
345 }
346 if (0U != (CMP_SCR_COUT_MASK & base->SCR))
347 {
348 ret32 |= (uint32_t)kCMP_OutputAssertEventFlag;
349 }
350 return ret32;
351 }
352
353 /*!
354 * brief Clears the status flags.
355 *
356 * param base CMP peripheral base address.
357 * param mask Mask value for the flags. See "_cmp_status_flags".
358 */
CMP_ClearStatusFlags(CMP_Type * base,uint32_t mask)359 void CMP_ClearStatusFlags(CMP_Type *base, uint32_t mask)
360 {
361 uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
362
363 if (0U != ((uint32_t)kCMP_OutputRisingEventFlag & mask))
364 {
365 tmp8 |= CMP_SCR_CFR_MASK;
366 }
367 if (0U != ((uint32_t)kCMP_OutputFallingEventFlag & mask))
368 {
369 tmp8 |= CMP_SCR_CFF_MASK;
370 }
371 base->SCR = tmp8;
372 }
373