1 /*
2  * Copyright (c) 2006-2024 RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2022-07-13     Rbb666       first version
9  */
10 #include "drv_pwm.h"
11 
12 #ifdef RT_USING_PWM
13 
14 #include <drivers/dev_pwm.h>
15 #include "drv_gpio.h"
16 
17 /*#define DRV_DEBUG*/
18 #define LOG_TAG "drv.pwm"
19 #include <drv_log.h>
20 
21 struct rt_device_pwm pwm_device;
22 
23 struct ifx_pwm
24 {
25     struct rt_device_pwm pwm_device;
26     cyhal_pwm_t *pwm_obj;
27     rt_uint8_t channel;
28     char *name;
29     rt_uint8_t gpio;
30 };
31 
32 static struct ifx_pwm ifx_pwm_obj[] =
33 {
34 #ifdef BSP_USING_PWM0_CH0_PORT0
35     PWM0_CH0_PORT0_CONFIG,
36 #endif
37 
38 #ifdef BSP_USING_PWM0_CH2_PORT11_COMPL
39     PWM0_CH2_PORT11_COMPL_CONFIG,
40 #endif
41 
42 #ifdef BSP_USING_PWM0_CH3_PORT11
43     PWM0_CH3_PORT11_CONFIG,
44 #endif
45 
46 #ifdef BSP_USING_PWM0_CH4_PORT5_COMPL
47     PWM0_CH4_PORT5_COMPL_CONFIG,
48 #endif
49 
50 #ifdef BSP_USING_PWM0_CH7_PORT2
51     PWM0_CH7_PORT2_CONFIG,
52 #endif
53 
54 #ifdef BSP_USING_PWM0_CH7_PORT5
55     PWM0_CH7_PORT5_CONFIG,
56 #endif
57 
58 #ifdef BSP_USING_PWM0_CH7_PORT5_COMPL
59     PWM0_CH7_PORT5_COMPL_CONFIG,
60 #endif
61 
62 #ifdef BSP_USING_PWM0_CH7_PORT7
63     PWM0_CH7_PORT7_CONFIG,
64 #endif
65 
66 #ifdef BSP_USING_PWM0_CH7_PORT9
67     PWM0_CH7_PORT9_CONFIG,
68 #endif
69 
70 #ifdef BSP_USING_PWM0_CH7_PORT10
71     PWM0_CH7_PORT10_CONFIG,
72 #endif
73 
74 #ifdef BSP_USING_PWM0_CH7_PORT12
75     PWM0_CH7_PORT12_CONFIG,
76 #endif
77 
78 #ifdef BSP_USING_PWM0_CH7_PORT13
79     PWM0_CH3_PORT13_CONFIG,
80 #endif
81 };
82 
drv_pwm_enable(cyhal_pwm_t * htim,struct rt_pwm_configuration * configuration,rt_bool_t enable)83 static rt_err_t drv_pwm_enable(cyhal_pwm_t *htim, struct rt_pwm_configuration *configuration, rt_bool_t enable)
84 {
85     /* get the value of channel */
86     rt_uint32_t channel = configuration->channel;
87 
88     if (!configuration->complementary || configuration->complementary)
89     {
90         if (!enable)
91         {
92                         htim->tcpwm.resource.channel_num = channel;
93             cyhal_pwm_stop(htim);
94         }
95         else
96         {
97                         htim->tcpwm.resource.channel_num = channel;
98             cyhal_pwm_start(htim);
99         }
100     }
101 
102     return RT_EOK;
103 }
104 
drv_pwm_set(cyhal_pwm_t * htim,struct rt_pwm_configuration * configuration)105 static rt_err_t drv_pwm_set(cyhal_pwm_t *htim, struct rt_pwm_configuration *configuration)
106 {
107     rt_uint64_t tim_clock;
108     rt_uint32_t period, pulse;
109 
110     tim_clock = (rt_uint32_t)(htim->tcpwm.clock_hz);
111 
112     htim->tcpwm.resource.channel_num = configuration->channel;
113 
114     period = (unsigned long long)configuration->period / 1000ULL;
115 
116     pulse = (unsigned long long)configuration->pulse / 1000ULL;
117 
118     cyhal_pwm_set_period(htim, period, pulse);
119 
120     return RT_EOK;
121 }
122 
drv_pwm_get(cyhal_pwm_t * htim,struct rt_pwm_configuration * configuration)123 static rt_err_t drv_pwm_get(cyhal_pwm_t *htim, struct rt_pwm_configuration *configuration)
124 {
125     uint32_t Period = Cy_TCPWM_PWM_GetPeriod0(htim->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(htim->tcpwm.resource));
126 
127     uint32_t Compare = Cy_TCPWM_PWM_GetCounter(htim->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(htim->tcpwm.resource));
128 
129     configuration->period = Period;
130 
131     configuration->pulse = Compare;
132 
133     return RT_EOK;
134 }
135 
drv_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)136 static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
137 {
138     struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
139     cyhal_pwm_t *htim = (cyhal_pwm_t *)device->parent.user_data;
140 
141     switch (cmd)
142     {
143     case PWMN_CMD_ENABLE:
144         configuration->complementary = RT_TRUE;
145 
146     case PWM_CMD_ENABLE:
147         return drv_pwm_enable(htim, configuration, RT_TRUE);
148 
149     case PWMN_CMD_DISABLE:
150         configuration->complementary = RT_FALSE;
151 
152     case PWM_CMD_DISABLE:
153         return drv_pwm_enable(htim, configuration, RT_FALSE);
154 
155     case PWM_CMD_SET:
156         return drv_pwm_set(htim, configuration);
157 
158     case PWM_CMD_GET:
159         return drv_pwm_get(htim, configuration);
160 
161     default:
162         return -RT_EINVAL;
163     }
164 }
165 
166 static struct rt_pwm_ops drv_ops = {drv_pwm_control};
167 
ifx_hw_pwm_init(struct ifx_pwm * device)168 static rt_err_t ifx_hw_pwm_init(struct ifx_pwm *device)
169 {
170     rt_err_t result = RT_EOK;
171 
172     RT_ASSERT(device != RT_NULL);
173 
174     if (cyhal_pwm_init_adv(device->pwm_obj, device->gpio, NC, CYHAL_PWM_LEFT_ALIGN, true, 0u, false, RT_NULL) != RT_EOK)
175     {
176         LOG_E("%s channel%d config failed", device->name, device->channel);
177         result = -RT_ERROR;
178         goto __exit;
179     }
180 
181 __exit:
182     return result;
183 }
184 
rt_hw_pwm_init(void)185 static int rt_hw_pwm_init(void)
186 {
187     int i;
188     int result = RT_EOK;
189 
190     for (i = 0; i < sizeof(ifx_pwm_obj) / sizeof(ifx_pwm_obj[0]); i++)
191     {
192         ifx_pwm_obj[i].pwm_obj = rt_malloc(sizeof(cyhal_pwm_t));
193         RT_ASSERT(ifx_pwm_obj[i].pwm_obj != RT_NULL);
194 
195         /* pwm init */
196         if (ifx_hw_pwm_init(&ifx_pwm_obj[i]) != RT_EOK)
197         {
198             LOG_E("%s init failed", ifx_pwm_obj[i].name);
199             result = -RT_ERROR;
200             goto __exit;
201         }
202         else
203         {
204             if (rt_device_pwm_register(&ifx_pwm_obj[i].pwm_device, ifx_pwm_obj[i].name, &drv_ops, ifx_pwm_obj[i].pwm_obj) == RT_EOK)
205             {
206                 LOG_D("%s register success", ifx_pwm_obj[i].name);
207             }
208             else
209             {
210                 LOG_D("%s register failed", ifx_pwm_obj[i].name);
211                 result = -RT_ERROR;
212             }
213         }
214     }
215 
216 __exit:
217     return result;
218 }
219 INIT_BOARD_EXPORT(rt_hw_pwm_init);
220 
221 #define PWM_DEV_NAME "pwm0"
222 #define PWM_DEV_CHANNEL 4
223 
224 struct rt_device_pwm *pwm_dev;
225 
pwm_sample(int argc,char * argv[])226 static int pwm_sample(int argc, char *argv[])
227 {
228     rt_uint32_t period, pulse, dir;
229 
230     period = 1 * 1000 * 1000;
231     dir = 1;
232     pulse = 0;
233 
234     pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
235 
236     if (pwm_dev == RT_NULL)
237     {
238         rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);
239         return -RT_ERROR;
240     }
241 
242     rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
243     rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
244 
245     rt_kprintf("Now PWM[%s] Channel[%d] Period[%d] Pulse[%d]\n", PWM_DEV_NAME, PWM_DEV_CHANNEL, period, pulse);
246 
247     while (1)
248     {
249         rt_thread_mdelay(50);
250 
251         if (dir)
252         {
253             pulse += 100000;
254         }
255         else
256         {
257             pulse -= 100000;
258         }
259 
260         if (pulse >= period)
261         {
262             dir = 0;
263         }
264 
265         if (0 == pulse)
266         {
267             dir = 1;
268         }
269 
270         rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
271     }
272 }
273 MSH_CMD_EXPORT(pwm_sample, <pwm0> channel7 sample);
274 #endif
275