1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_cmt.h"
10
11 /*******************************************************************************
12 * Definitions
13 ******************************************************************************/
14
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.cmt"
18 #endif
19
20 /* The standard intermediate frequency (IF). */
21 #define CMT_INTERMEDIATEFREQUENCY_8MHZ (8000000U)
22 /* CMT data modulate mask. */
23 #define CMT_MODULATE_COUNT_WIDTH (8U)
24 /* CMT diver 1. */
25 #define CMT_CMTDIV_ONE (1)
26 /* CMT diver 2. */
27 #define CMT_CMTDIV_TWO (2)
28 /* CMT diver 4. */
29 #define CMT_CMTDIV_FOUR (4)
30 /* CMT diver 8. */
31 #define CMT_CMTDIV_EIGHT (8)
32
33 /*******************************************************************************
34 * Prototypes
35 ******************************************************************************/
36
37 /*!
38 * @brief Get instance number for CMT module.
39 *
40 * @param base CMT peripheral base address.
41 */
42 static uint32_t CMT_GetInstance(CMT_Type *base);
43
44 /*******************************************************************************
45 * Variables
46 ******************************************************************************/
47
48 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
49 /*! @brief Pointers to cmt clocks for each instance. */
50 static const clock_ip_name_t s_cmtClock[FSL_FEATURE_SOC_CMT_COUNT] = CMT_CLOCKS;
51 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
52
53 /*! @brief Pointers to cmt bases for each instance. */
54 static CMT_Type *const s_cmtBases[] = CMT_BASE_PTRS;
55
56 /*! @brief Pointers to cmt IRQ number for each instance. */
57 static const IRQn_Type s_cmtIrqs[] = CMT_IRQS;
58
59 /*******************************************************************************
60 * Codes
61 ******************************************************************************/
62
CMT_GetInstance(CMT_Type * base)63 static uint32_t CMT_GetInstance(CMT_Type *base)
64 {
65 uint32_t instance;
66
67 /* Find the instance index from base address mappings. */
68 for (instance = 0; instance < ARRAY_SIZE(s_cmtBases); instance++)
69 {
70 if (s_cmtBases[instance] == base)
71 {
72 break;
73 }
74 }
75
76 assert(instance < ARRAY_SIZE(s_cmtBases));
77
78 return instance;
79 }
80
81 /*!
82 * brief Gets the CMT default configuration structure. This API
83 * gets the default configuration structure for the CMT_Init().
84 * Use the initialized structure unchanged in CMT_Init() or modify
85 * fields of the structure before calling the CMT_Init().
86 *
87 * param config The CMT configuration structure pointer.
88 */
CMT_GetDefaultConfig(cmt_config_t * config)89 void CMT_GetDefaultConfig(cmt_config_t *config)
90 {
91 assert(NULL != config);
92
93 /* Initializes the configure structure to zero. */
94 (void)memset(config, 0, sizeof(*config));
95
96 /* Default infrared output is enabled and set with high active, the divider is set to 1. */
97 config->isInterruptEnabled = false;
98 config->isIroEnabled = true;
99 config->iroPolarity = kCMT_IROActiveHigh;
100 config->divider = kCMT_SecondClkDiv1;
101 }
102
103 /*!
104 * brief Initializes the CMT module.
105 *
106 * This function ungates the module clock and sets the CMT internal clock,
107 * interrupt, and infrared output signal for the CMT module.
108 *
109 * param base CMT peripheral base address.
110 * param config The CMT basic configuration structure.
111 * param busClock_Hz The CMT module input clock - bus clock frequency.
112 */
CMT_Init(CMT_Type * base,const cmt_config_t * config,uint32_t busClock_Hz)113 void CMT_Init(CMT_Type *base, const cmt_config_t *config, uint32_t busClock_Hz)
114 {
115 assert(NULL != config);
116 assert(busClock_Hz >= CMT_INTERMEDIATEFREQUENCY_8MHZ);
117
118 uint8_t divider;
119
120 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
121 /* Ungate clock. */
122 CLOCK_EnableClock(s_cmtClock[CMT_GetInstance(base)]);
123 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
124
125 /* Sets clock divider. The divider set in pps should be set
126 to make sycClock_Hz/divder = 8MHz */
127 base->PPS = CMT_PPS_PPSDIV(busClock_Hz / CMT_INTERMEDIATEFREQUENCY_8MHZ - 1U);
128 divider = base->MSC;
129 divider &= ~(uint8_t)CMT_MSC_CMTDIV_MASK;
130 divider |= CMT_MSC_CMTDIV(config->divider);
131 base->MSC = divider;
132
133 /* Set the IRO signal. */
134 base->OC = CMT_OC_CMTPOL(config->iroPolarity) | CMT_OC_IROPEN(config->isIroEnabled);
135
136 /* Set interrupt. */
137 if (true == config->isInterruptEnabled)
138 {
139 CMT_EnableInterrupts(base, (uint32_t)kCMT_EndOfCycleInterruptEnable);
140 (void)EnableIRQ(s_cmtIrqs[CMT_GetInstance(base)]);
141 }
142 }
143
144 /*!
145 * brief Disables the CMT module and gate control.
146 *
147 * This function disables CMT modulator, interrupts, and gates the
148 * CMT clock control. CMT_Init must be called to use the CMT again.
149 *
150 * param base CMT peripheral base address.
151 */
CMT_Deinit(CMT_Type * base)152 void CMT_Deinit(CMT_Type *base)
153 {
154 /*Disable the CMT modulator. */
155 base->MSC = 0;
156
157 /* Disable the interrupt. */
158 CMT_DisableInterrupts(base, (uint32_t)kCMT_EndOfCycleInterruptEnable);
159 (void)DisableIRQ(s_cmtIrqs[CMT_GetInstance(base)]);
160
161 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
162 /* Gate the clock. */
163 CLOCK_DisableClock(s_cmtClock[CMT_GetInstance(base)]);
164 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
165 }
166
167 /*!
168 * brief Selects the mode for CMT.
169 *
170 * param base CMT peripheral base address.
171 * param mode The CMT feature mode enumeration. See "cmt_mode_t".
172 * param modulateConfig The carrier generation and modulator configuration.
173 */
CMT_SetMode(CMT_Type * base,cmt_mode_t mode,cmt_modulate_config_t * modulateConfig)174 void CMT_SetMode(CMT_Type *base, cmt_mode_t mode, cmt_modulate_config_t *modulateConfig)
175 {
176 uint8_t mscReg = base->MSC;
177
178 /* Judge the mode. */
179 if (mode != kCMT_DirectIROCtl)
180 {
181 assert(NULL != modulateConfig);
182
183 /* Set carrier generator. */
184 CMT_SetCarrirGenerateCountOne(base, modulateConfig->highCount1, modulateConfig->lowCount1);
185 if (mode == kCMT_FSKMode)
186 {
187 CMT_SetCarrirGenerateCountTwo(base, modulateConfig->highCount2, modulateConfig->lowCount2);
188 }
189
190 /* Set carrier modulator. */
191 CMT_SetModulateMarkSpace(base, modulateConfig->markCount, modulateConfig->spaceCount);
192 mscReg &= ~((uint8_t)CMT_MSC_FSK_MASK | (uint8_t)CMT_MSC_BASE_MASK);
193 mscReg |= (uint8_t)mode;
194 }
195 else
196 {
197 mscReg &= ~(uint8_t)CMT_MSC_MCGEN_MASK;
198 }
199 /* Set the CMT mode. */
200 base->MSC = mscReg;
201 }
202
203 /*!
204 * brief Gets the mode of the CMT module.
205 *
206 * param base CMT peripheral base address.
207 * return The CMT mode.
208 * kCMT_DirectIROCtl Carrier modulator is disabled; the IRO signal is directly in software control.
209 * kCMT_TimeMode Carrier modulator is enabled in time mode.
210 * kCMT_FSKMode Carrier modulator is enabled in FSK mode.
211 * kCMT_BasebandMode Carrier modulator is enabled in baseband mode.
212 */
CMT_GetMode(CMT_Type * base)213 cmt_mode_t CMT_GetMode(CMT_Type *base)
214 {
215 uint8_t mode = base->MSC;
216 cmt_mode_t ret;
217
218 if (0U == (mode & CMT_MSC_MCGEN_MASK))
219 { /* Carrier modulator disabled and the IRO signal is in direct software control. */
220 ret = kCMT_DirectIROCtl;
221 }
222 else
223 {
224 /* Carrier modulator is enabled. */
225 if (0U != (mode & CMT_MSC_BASE_MASK))
226 {
227 /* Base band mode. */
228 ret = kCMT_BasebandMode;
229 }
230 else if (0U != (mode & CMT_MSC_FSK_MASK))
231 {
232 /* FSK mode. */
233 ret = kCMT_FSKMode;
234 }
235 else
236 {
237 /* Time mode. */
238 ret = kCMT_TimeMode;
239 }
240 }
241
242 return ret;
243 }
244
245 /*!
246 * brief Gets the actual CMT clock frequency.
247 *
248 * param base CMT peripheral base address.
249 * param busClock_Hz CMT module input clock - bus clock frequency.
250 * return The CMT clock frequency.
251 */
CMT_GetCMTFrequency(CMT_Type * base,uint32_t busClock_Hz)252 uint32_t CMT_GetCMTFrequency(CMT_Type *base, uint32_t busClock_Hz)
253 {
254 uint32_t frequency;
255 uint32_t divider;
256
257 /* Get intermediate frequency. */
258 frequency = busClock_Hz / (((uint32_t)base->PPS & CMT_PPS_PPSDIV_MASK) + 1U);
259
260 /* Get the second divider. */
261 divider = (((uint32_t)base->MSC & CMT_MSC_CMTDIV_MASK) >> CMT_MSC_CMTDIV_SHIFT);
262 /* Get CMT frequency. */
263 switch ((cmt_second_clkdiv_t)divider)
264 {
265 case kCMT_SecondClkDiv1:
266 frequency = frequency / (uint32_t)CMT_CMTDIV_ONE;
267 break;
268 case kCMT_SecondClkDiv2:
269 frequency = frequency / (uint32_t)CMT_CMTDIV_TWO;
270 break;
271 case kCMT_SecondClkDiv4:
272 frequency = frequency / (uint32_t)CMT_CMTDIV_FOUR;
273 break;
274 case kCMT_SecondClkDiv8:
275 frequency = frequency / (uint32_t)CMT_CMTDIV_EIGHT;
276 break;
277 default:
278 frequency = frequency / (uint32_t)CMT_CMTDIV_ONE;
279 break;
280 }
281
282 return frequency;
283 }
284
285 /*!
286 * brief Sets the modulation mark and space time period for the CMT modulator.
287 *
288 * This function sets the mark time period of the CMT modulator counter
289 * to control the mark time of the output modulated signal from the carrier generator output signal.
290 * If the CMT clock frequency is Fcmt and the carrier out signal frequency is fcg:
291 * - In Time and Baseband mode: The mark period of the generated signal equals (markCount + 1) / (Fcmt/8).
292 * The space period of the generated signal equals spaceCount / (Fcmt/8).
293 * - In FSK mode: The mark period of the generated signal equals (markCount + 1)/fcg.
294 * The space period of the generated signal equals spaceCount / fcg.
295 *
296 * param base Base address for current CMT instance.
297 * param markCount The number of clock period for CMT modulator signal mark period,
298 * in the range of 0 ~ 0xFFFF.
299 * param spaceCount The number of clock period for CMT modulator signal space period,
300 * in the range of the 0 ~ 0xFFFF.
301 */
CMT_SetModulateMarkSpace(CMT_Type * base,uint32_t markCount,uint32_t spaceCount)302 void CMT_SetModulateMarkSpace(CMT_Type *base, uint32_t markCount, uint32_t spaceCount)
303 {
304 /* Set modulate mark. */
305 base->CMD1 = (uint8_t)((markCount >> CMT_MODULATE_COUNT_WIDTH) & CMT_CMD1_MB_MASK);
306 base->CMD2 = (uint8_t)(markCount & CMT_CMD2_MB_MASK);
307 /* Set modulate space. */
308 base->CMD3 = (uint8_t)((spaceCount >> CMT_MODULATE_COUNT_WIDTH) & CMT_CMD3_SB_MASK);
309 base->CMD4 = (uint8_t)(spaceCount & CMT_CMD4_SB_MASK);
310 }
311
312 /*!
313 * brief Sets the IRO (infrared output) signal state.
314 *
315 * Changes the states of the IRO signal when the kCMT_DirectIROMode mode is set
316 * and the IRO signal is enabled.
317 *
318 * param base CMT peripheral base address.
319 * param state The control of the IRO signal. See "cmt_infrared_output_state_t"
320 */
CMT_SetIroState(CMT_Type * base,cmt_infrared_output_state_t state)321 void CMT_SetIroState(CMT_Type *base, cmt_infrared_output_state_t state)
322 {
323 uint8_t ocReg = base->OC;
324
325 ocReg &= ~(uint8_t)CMT_OC_IROL_MASK;
326 ocReg |= CMT_OC_IROL(state);
327
328 /* Set the infrared output signal control. */
329 base->OC = ocReg;
330 }
331