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