1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2018-04-17 WangBing the first version.
9 * 2019-04-22 tyustli add imxrt series support
10 *
11 */
12 #include <rtthread.h>
13
14 #ifdef BSP_USING_HWTIMER
15
16 #define LOG_TAG "drv.hwtimer"
17 #include <drv_log.h>
18
19 #include <rtdevice.h>
20 #include "drv_hwtimer.h"
21 #include "fsl_gpt.h"
22
23 #if defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL
24 #error "Please don't define 'FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL'!"
25 #endif
26
27 /* Select IPG Clock as PERCLK_CLK clock source */
28 #define EXAMPLE_GPT_CLOCK_SOURCE_SELECT (0U)
29 /* Clock divider for PERCLK_CLK clock source */
30 #define EXAMPLE_GPT_CLOCK_DIVIDER_SELECT (5U)
31 /* Get source clock for GPT driver (GPT prescaler = 6) */
32 #ifdef SOC_IMXRT1170_SERIES
33 #undef EXAMPLE_GPT_CLOCK_DIVIDER_SELECT
34 #define EXAMPLE_GPT_CLOCK_DIVIDER_SELECT (2U)
35 // 1170 use this root directly, we have already divide this clk, can read it directly
36 #define EXAMPLE_GPT_CLK_FREQ (CLOCK_GetRootClockFreq(kCLOCK_Root_Gpt1))
37 #else
38 #define EXAMPLE_GPT_CLK_FREQ (CLOCK_GetFreq(kCLOCK_IpgClk) / (EXAMPLE_GPT_CLOCK_DIVIDER_SELECT + 1U))
39 #endif
40
NVIC_Configuration(void)41 static void NVIC_Configuration(void)
42 {
43 #ifdef BSP_USING_HWTIMER1
44 EnableIRQ(GPT1_IRQn);
45 #endif
46
47 #ifdef BSP_USING_HWTIMER2
48 EnableIRQ(GPT2_IRQn);
49 #endif
50 }
51
imxrt_hwtimer_control(rt_hwtimer_t * timer,rt_uint32_t cmd,void * args)52 static rt_err_t imxrt_hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
53 {
54 rt_err_t err = RT_EOK;
55 GPT_Type *hwtimer_dev;
56 hwtimer_dev = (GPT_Type *)timer->parent.user_data;
57
58 RT_ASSERT(timer != RT_NULL);
59
60 switch (cmd)
61 {
62 case HWTIMER_CTRL_FREQ_SET:
63 {
64 uint32_t clk;
65 uint32_t pre;
66 clk = EXAMPLE_GPT_CLK_FREQ;
67 pre = clk / *((uint32_t *)args) - 1;
68 GPT_SetClockDivider(hwtimer_dev, pre);
69 }
70 break;
71 default:
72 err = -RT_ENOSYS;
73 break;
74 }
75 return err;
76 }
77
imxrt_hwtimer_count_get(rt_hwtimer_t * timer)78 static rt_uint32_t imxrt_hwtimer_count_get(rt_hwtimer_t *timer)
79 {
80 rt_uint32_t CurrentTimer_Count;
81 GPT_Type *hwtimer_dev;
82 hwtimer_dev = (GPT_Type *)timer->parent.user_data;
83
84 RT_ASSERT(timer != RT_NULL);
85
86 CurrentTimer_Count = GPT_GetCurrentTimerCount(hwtimer_dev);
87
88 return CurrentTimer_Count;
89 }
90
imxrt_hwtimer_init(rt_hwtimer_t * timer,rt_uint32_t state)91 static void imxrt_hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state)
92 {
93 GPT_Type *hwtimer_dev;
94 gpt_config_t gptConfig;
95 hwtimer_dev = (GPT_Type *)timer->parent.user_data;
96
97 RT_ASSERT(timer != RT_NULL);
98
99 if (state == 1)
100 {
101 #ifdef SOC_IMXRT1170_SERIES
102 #ifdef BSP_USING_HWTIMER1
103 /*Clock setting for GPT*/
104 CLOCK_SetRootClockMux(kCLOCK_Root_Gpt1, EXAMPLE_GPT_CLOCK_SOURCE_SELECT);
105 CLOCK_SetRootClockDiv(kCLOCK_Root_Gpt1, EXAMPLE_GPT_CLOCK_DIVIDER_SELECT);
106 #endif
107 #ifdef BSP_USING_HWTIMER2
108 /*Clock setting for GPT*/
109 CLOCK_SetRootClockMux(kCLOCK_Root_Gpt2, EXAMPLE_GPT_CLOCK_SOURCE_SELECT);
110 CLOCK_SetRootClockDiv(kCLOCK_Root_Gpt2, EXAMPLE_GPT_CLOCK_DIVIDER_SELECT);
111 #endif
112 #else
113 /*Clock setting for GPT*/
114 CLOCK_SetMux(kCLOCK_PerclkMux, EXAMPLE_GPT_CLOCK_SOURCE_SELECT);
115 CLOCK_SetDiv(kCLOCK_PerclkDiv, EXAMPLE_GPT_CLOCK_DIVIDER_SELECT);
116 #endif
117
118 /* Initialize GPT module by default config */
119 GPT_GetDefaultConfig(&gptConfig);
120 GPT_Init(hwtimer_dev, &gptConfig);
121 }
122 }
123
imxrt_hwtimer_start(rt_hwtimer_t * timer,rt_uint32_t cnt,rt_hwtimer_mode_t mode)124 static rt_err_t imxrt_hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
125 {
126 GPT_Type *hwtimer_dev;
127 hwtimer_dev = (GPT_Type *)timer->parent.user_data;
128
129 RT_ASSERT(timer != RT_NULL);
130
131 hwtimer_dev->CR |= (mode != HWTIMER_MODE_PERIOD) ? GPT_CR_FRR_MASK : 0U;
132
133 GPT_SetOutputCompareValue(hwtimer_dev, kGPT_OutputCompare_Channel1, cnt);
134
135 GPT_EnableInterrupts(hwtimer_dev, kGPT_OutputCompare1InterruptEnable);
136
137 NVIC_Configuration();
138
139 GPT_StartTimer(hwtimer_dev);
140
141 return RT_EOK;
142 }
143
imxrt_hwtimer_stop(rt_hwtimer_t * timer)144 static void imxrt_hwtimer_stop(rt_hwtimer_t *timer)
145 {
146 GPT_Type *hwtimer_dev;
147 hwtimer_dev = (GPT_Type *)timer->parent.user_data;
148
149 RT_ASSERT(timer != RT_NULL);
150
151 GPT_StopTimer(hwtimer_dev);
152 }
153
154 static const struct rt_hwtimer_ops imxrt_hwtimer_ops =
155 {
156 .init = imxrt_hwtimer_init,
157 .start = imxrt_hwtimer_start,
158 .stop = imxrt_hwtimer_stop,
159 .count_get = imxrt_hwtimer_count_get,
160 .control = imxrt_hwtimer_control,
161 };
162
163 static const struct rt_hwtimer_info imxrt_hwtimer_info =
164 {
165 25000000, /* the maximum count frequency can be set */
166 6103, /* the minimum count frequency can be set */
167 0xFFFFFFFF,
168 HWTIMER_CNTMODE_UP,
169 };
170
171 #ifdef BSP_USING_HWTIMER1
172 static rt_hwtimer_t GPT_timer1;
173 #endif /*BSP_USING_HWTIMER1*/
174
175 #ifdef BSP_USING_HWTIMER2
176 static rt_hwtimer_t GPT_timer2;
177 #endif
178
rt_hw_hwtimer_init(void)179 int rt_hw_hwtimer_init(void)
180 {
181 int ret = RT_EOK;
182
183 #ifdef BSP_USING_HWTIMER1
184 GPT_timer1.info = &imxrt_hwtimer_info;
185 GPT_timer1.ops = &imxrt_hwtimer_ops;
186 ret = rt_device_hwtimer_register(&GPT_timer1, "gpt1", GPT1);
187
188 if (ret != RT_EOK)
189 {
190 LOG_E("gpt1 register failed\n");
191 }
192 #endif
193
194 #ifdef BSP_USING_HWTIMER2
195 GPT_timer2.info = &imxrt_hwtimer_info;
196 GPT_timer2.ops = &imxrt_hwtimer_ops;
197 ret = rt_device_hwtimer_register(&GPT_timer2, "gpt2", GPT2);
198
199 if (ret != RT_EOK)
200 {
201 LOG_E("gpt1 register failed\n");
202 }
203 #endif
204
205 return ret;
206 }
207
208 #ifdef BSP_USING_HWTIMER1
209
GPT1_IRQHandler(void)210 void GPT1_IRQHandler(void)
211 {
212 if (GPT_GetStatusFlags(GPT1, kGPT_OutputCompare1Flag) != 0)
213 {
214 GPT_ClearStatusFlags(GPT1, kGPT_OutputCompare1Flag);
215 rt_device_hwtimer_isr(&GPT_timer1);
216 }
217
218 /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F, Cortex-M7, Cortex-M7F Store immediate overlapping
219 exception return operation might vector to incorrect interrupt */
220 #if defined __CORTEX_M && (__CORTEX_M == 4U || __CORTEX_M == 7U)
221 __DSB();
222 #endif
223 }
224
225 #endif /*BSP_USING_HWTIMER1*/
226
227 #ifdef BSP_USING_HWTIMER2
228
GPT2_IRQHandler(void)229 void GPT2_IRQHandler(void)
230 {
231 if (GPT_GetStatusFlags(GPT2, kGPT_OutputCompare1Flag) != 0)
232 {
233 GPT_ClearStatusFlags(GPT2, kGPT_OutputCompare1Flag);
234 rt_device_hwtimer_isr(&GPT_timer2);
235 }
236
237 /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F, Cortex-M7, Cortex-M7F Store immediate overlapping
238 exception return operation might vector to incorrect interrupt */
239 #if defined __CORTEX_M && (__CORTEX_M == 4U || __CORTEX_M == 7U)
240 __DSB();
241 #endif
242 }
243 #endif /*BSP_USING_HWTIMER2*/
244
245 INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);
246
247 #endif /* BSP_USING_HWTIMER */
248