1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2020-06-27 AHTYDHD the first version
9 */
10
11 #include "drv_pwm.h"
12 #include <stdint.h>
13 #include <stdbool.h>
14 #include "inc/hw_memmap.h"
15 #include "driverlib/pwm.h"
16 #include "driverlib/sysctl.h"
17
18 #ifdef RT_USING_PWM
19 #include "pwm_config.h"
20 #include "tm4c123_config.h"
21 #include <string.h>
22
23 #define LOG_TAG "drv.pwm"
24 #include <drv_log.h>
25
26 enum
27 {
28 #ifdef BSP_USING_PWM0
29 PWM0_INDEX,
30 #endif
31 #ifdef BSP_USING_PWM1
32 PWM1_INDEX,
33 #endif
34 #ifdef BSP_USING_PWM2
35 PWM2_INDEX,
36 #endif
37 #ifdef BSP_USING_PWM3
38 PWM3_INDEX,
39 #endif
40 #ifdef BSP_USING_PWM4
41 PWM4_INDEX,
42 #endif
43 #ifdef BSP_USING_PWM5
44 PWM5_INDEX,
45 #endif
46 #ifdef BSP_USING_PWM6
47 PWM6_INDEX,
48 #endif
49 #ifdef BSP_USING_PWM7
50 PWM7_INDEX,
51 #endif
52 };
53
54 static struct tm4c123_pwm_config pwm_config[] =
55 {
56 #ifdef BSP_USING_PWM0
57 PWM0_CONFIG,
58 #endif
59 #ifdef BSP_USING_PWM1
60 PWM1_CONFIG,
61 #endif
62 #ifdef BSP_USING_PWM2
63 PWM2_CONFIG,
64 #endif
65 #ifdef BSP_USING_PWM3
66 PWM3_CONFIG,
67 #endif
68 #ifdef BSP_USING_PWM4
69 PWM4_CONFIG,
70 #endif
71 #ifdef BSP_USING_PWM5
72 PWM5_CONFIG,
73 #endif
74 #ifdef BSP_USING_PWM6
75 PWM6_CONFIG,
76 #endif
77 #ifdef BSP_USING_PWM7
78 PWM7_CONFIG,
79 #endif
80 };
81
82 static struct tm4c123_pwm pwm_obj[sizeof(pwm_config) / sizeof(pwm_config[0])] = {0};
83
84 static rt_err_t tm4c123_pwm_control(struct rt_device_pwm *device, int cmd, void *arg);
85 static struct rt_pwm_ops drv_ops =
86 {
87 tm4c123_pwm_control
88 };
89
drv_pwm_enable(char * name,struct rt_pwm_configuration * configuration,rt_bool_t enable)90 static rt_err_t drv_pwm_enable(char *name, struct rt_pwm_configuration *configuration, rt_bool_t enable)
91 {
92
93 int num = name[3] - 0x30;
94
95 if (!enable)
96 {
97 if (num <= 3)
98 {
99 /* Converts the channel number to the channel number of Hal library */
100 PWMOutputState(PWM0_BASE, PWM_OUT_0_BIT << (num * 2 + (configuration->channel - 1)), false);
101 }
102 else
103 {
104 PWMOutputState(PWM1_BASE, PWM_OUT_0_BIT << ((num % 4) * 2 + (configuration->channel - 1)), false);
105 }
106 }
107 else
108 {
109 if (num <= 3)
110 {
111 PWMOutputState(PWM0_BASE, PWM_OUT_0_BIT << (num * 2 + (configuration->channel - 1)), true);
112 }
113 else
114 {
115 PWMOutputState(PWM1_BASE, PWM_OUT_0_BIT << ((num % 4) * 2 + (configuration->channel - 1)), true);
116 }
117 }
118
119 return RT_EOK;
120 }
121
drv_pwm_get(char * name,struct rt_pwm_configuration * configuration)122 static rt_err_t drv_pwm_get(char *name, struct rt_pwm_configuration *configuration)
123 {
124
125 switch (name[3])
126 {
127 case '0':
128 configuration->period = PWMGenPeriodGet(PWM0_BASE, PWM_GEN_0);
129 configuration->pulse = PWMPulseWidthGet(PWM0_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1));
130 break;
131 case '1':
132 configuration->period = PWMGenPeriodGet(PWM0_BASE, PWM_GEN_1);
133 configuration->pulse = PWMPulseWidthGet(PWM0_BASE, PWM_OUT_2 + (uint32_t)(configuration->channel - 1));
134 break;
135 case '2':
136 configuration->period = PWMGenPeriodGet(PWM0_BASE, PWM_GEN_2);
137 configuration->pulse = PWMPulseWidthGet(PWM0_BASE, PWM_OUT_4 + (uint32_t)(configuration->channel - 1));
138 break;
139 case '3':
140 configuration->period = PWMGenPeriodGet(PWM0_BASE, PWM_GEN_3);
141 configuration->pulse = PWMPulseWidthGet(PWM0_BASE, PWM_OUT_6 + (uint32_t)(configuration->channel - 1));
142 break;
143 case '4':
144 configuration->period = PWMGenPeriodGet(PWM1_BASE, PWM_GEN_0);
145 configuration->pulse = PWMPulseWidthGet(PWM1_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1));
146 break;
147 case '5':
148 configuration->period = PWMGenPeriodGet(PWM1_BASE, PWM_GEN_1);
149 configuration->pulse = PWMPulseWidthGet(PWM1_BASE, PWM_OUT_2 + (uint32_t)(configuration->channel - 1));
150 break;
151 case '6':
152 configuration->period = PWMGenPeriodGet(PWM1_BASE, PWM_GEN_2);
153 configuration->pulse = PWMPulseWidthGet(PWM1_BASE, PWM_OUT_4 + (uint32_t)(configuration->channel - 1));
154 break;
155 case '7':
156 configuration->period = PWMGenPeriodGet(PWM1_BASE, PWM_GEN_3);
157 configuration->pulse = PWMPulseWidthGet(PWM1_BASE, PWM_OUT_6 + (uint32_t)(configuration->channel - 1));
158 break;
159 default:
160 break;
161 }
162 return RT_EOK;
163 }
164
drv_pwm_set(char * name,struct rt_pwm_configuration * configuration)165 static rt_err_t drv_pwm_set(char *name, struct rt_pwm_configuration *configuration)
166 {
167
168 uint32_t sysPwmClock = SysCtlPWMClockGet();
169 switch (name[3])
170 {
171 case '0':
172 PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, configuration->period / 1000 * (sysPwmClock / 1000000)); // t(s)/(1/f) = ticks ns/1000/1000000
173 PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
174 PWMGenEnable(PWM0_BASE, PWM_GEN_0);
175 break;
176 case '1':
177 PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, configuration->period / 1000 * (sysPwmClock / 1000000));
178 PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
179 PWMGenEnable(PWM0_BASE, PWM_GEN_1);
180 break;
181 case '2':
182 PWMGenPeriodSet(PWM0_BASE, PWM_GEN_2, configuration->period / 1000 * (sysPwmClock / 1000000));
183 PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
184 PWMGenEnable(PWM0_BASE, PWM_GEN_2);
185 break;
186 case '3':
187 PWMGenPeriodSet(PWM0_BASE, PWM_GEN_3, configuration->period / 1000 * (sysPwmClock / 1000000));
188 PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
189 PWMGenEnable(PWM0_BASE, PWM_GEN_3);
190 break;
191 case '4':
192 PWMGenPeriodSet(PWM1_BASE, PWM_GEN_0, configuration->period / 1000 * (sysPwmClock / 1000000));
193 PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
194 PWMGenEnable(PWM1_BASE, PWM_GEN_0);
195 break;
196 case '5':
197 PWMGenPeriodSet(PWM1_BASE, PWM_GEN_1, configuration->period / 1000 * (sysPwmClock / 1000000));
198 PWMPulseWidthSet(PWM1_BASE, PWM_OUT_2 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
199 PWMGenEnable(PWM1_BASE, PWM_GEN_1);
200 break;
201 case '6':
202 PWMGenPeriodSet(PWM1_BASE, PWM_GEN_2, configuration->period / 1000 * (sysPwmClock / 1000000));
203 PWMPulseWidthSet(PWM1_BASE, PWM_OUT_4 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
204 PWMGenEnable(PWM1_BASE, PWM_GEN_2);
205 break;
206 case '7':
207 PWMGenPeriodSet(PWM1_BASE, PWM_GEN_3, configuration->period / 1000 * (sysPwmClock / 1000000));
208 PWMPulseWidthSet(PWM1_BASE, PWM_OUT_6 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
209 PWMGenEnable(PWM1_BASE, PWM_GEN_3);
210 break;
211 default:
212 break;
213 }
214
215 return RT_EOK;
216 }
217
tm4c123_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)218 static rt_err_t tm4c123_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
219
220 {
221 struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
222
223 switch (cmd)
224 {
225 case PWM_CMD_ENABLE:
226 return drv_pwm_enable(device->parent.parent.name, configuration, RT_TRUE);
227 case PWM_CMD_DISABLE:
228 return drv_pwm_enable(device->parent.parent.name, configuration, RT_FALSE);
229 case PWM_CMD_SET:
230 return drv_pwm_set(device->parent.parent.name, configuration);
231 case PWM_CMD_GET:
232 return drv_pwm_get(device->parent.parent.name, configuration);
233 default:
234 return -RT_EINVAL;
235 }
236 }
237
tm4c123_hw_pwm_init(struct tm4c123_pwm * device)238 static rt_err_t tm4c123_hw_pwm_init(struct tm4c123_pwm *device)
239 {
240 rt_err_t result = RT_EOK;
241 RT_ASSERT(device != RT_NULL);
242
243 pwm_hw_config();
244 switch (device->config->name[3])
245 {
246 case '0':
247 PWMGenConfigure(PWM0_BASE, PWM_GEN_0, device->config->counterMode |
248 device->config->syncMode);
249 break;
250 case '1':
251 PWMGenConfigure(PWM0_BASE, PWM_GEN_1, device->config->counterMode |
252 device->config->syncMode);
253 break;
254 case '2':
255 PWMGenConfigure(PWM0_BASE, PWM_GEN_2, device->config->counterMode |
256 device->config->syncMode);
257 break;
258 case '3':
259 PWMGenConfigure(PWM0_BASE, PWM_GEN_3, device->config->counterMode |
260 device->config->syncMode);
261 break;
262 case '4':
263 PWMGenConfigure(PWM1_BASE, PWM_GEN_0, device->config->counterMode |
264 device->config->syncMode);
265 break;
266 case '5':
267 PWMGenConfigure(PWM1_BASE, PWM_GEN_1, device->config->counterMode |
268 device->config->syncMode);
269 break;
270 case '6':
271 PWMGenConfigure(PWM1_BASE, PWM_GEN_2, device->config->counterMode |
272 device->config->syncMode);
273 break;
274 case '7':
275 PWMGenConfigure(PWM1_BASE, PWM_GEN_3, device->config->counterMode |
276 device->config->syncMode);
277 break;
278 default:
279 LOG_E("%s PWMGenConfigure failed", device->config->name);
280 result = -RT_ERROR;
281 return result;
282 }
283
284 return result;
285 }
286
rt_hw_pwm_init(void)287 int rt_hw_pwm_init(void)
288 {
289 int i = 0;
290 rt_size_t obj_num = sizeof(pwm_obj) / sizeof(struct tm4c123_pwm);
291 rt_err_t result = RT_EOK;
292
293 for (i = 0 ; i < obj_num; i++)
294 {
295 pwm_obj[i].config = &pwm_config[i];
296 pwm_obj[i].pwm_device.ops = &drv_ops;
297 /*pwm_init*/
298 if (tm4c123_hw_pwm_init(&pwm_obj[i]) != RT_EOK)
299 {
300 LOG_E("%s init failed", pwm_obj[i].config->name);
301 result = -RT_ERROR;
302 return result;
303 }
304 else
305 {
306 LOG_D("%s init success", pwm_obj[i].config->name);
307
308 /* register pwm device */
309 if (rt_device_pwm_register(&pwm_obj[i].pwm_device, pwm_obj[i].config->name, &drv_ops, RT_NULL) == RT_EOK)
310 {
311 LOG_D("%s register success", pwm_obj[i].config->name);
312 }
313 else
314 {
315 LOG_E("%s register failed", pwm_obj[i].config->name);
316 result = -RT_ERROR;
317 }
318 }
319 }
320 return result;
321 }
322
323 #endif /* RT_USING_PWM */
324
325 /************************** end of file ******************/
326