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  * 2023-10-20       ChuShicheng      first version
9  */
10 #include "drv_pwm.h"
11 #include "board.h"
12 #include "hardware/pwm.h"
13 #include "hardware/gpio.h"
14 
15 #ifdef BSP_USING_PWM
16 
17 #define DBG_LEVEL   DBG_LOG
18 #include <rtdbg.h>
19 #define LOG_TAG "DRV.PWM"
20 
21 struct pico_pwm
22 {
23     struct rt_device_pwm pwm_device;
24     rt_uint8_t slice_num;
25     rt_uint8_t pin_a;
26     rt_uint8_t pin_b;
27     rt_uint8_t a_all_flag;   /* 1: Two pins simultaneously output PWM A channel */
28     rt_uint8_t b_all_flag;   /* 1: Two pins simultaneously output PWM B channel */
29     char *name;
30 };
31 
32 static struct pico_pwm pico_pwm_obj[] =
33 {
34 #ifdef BSP_USING_PWM0
35     {
36         .name = "pwm0",
37         .slice_num = 0,
38         .pin_a = BSP_PWM0_A_PIN,
39         .pin_b = BSP_PWM0_B_PIN,
40 #ifdef BSP_PWM0_A_ALL
41         .a_all_flag = 1,
42 #endif /* BSP_PWM0_A_ALL */
43 #ifdef BSP_PWM0_B_ALL
44         .b_all_flag = 1,
45 #endif /* BSP_PWM0_B_ALL */
46     },
47 #endif /* BSP_USING_PWM0 */
48 #ifdef BSP_USING_PWM1
49     {
50         .name = "pwm1",
51         .slice_num = 1,
52         .pin_a = BSP_PWM1_A_PIN,
53         .pin_b = BSP_PWM1_B_PIN,
54 #ifdef BSP_PWM1_A_ALL
55         .a_all_flag = 1,
56 #endif /* BSP_PWM1_A_ALL */
57 #ifdef BSP_PWM1_B_ALL
58         .b_all_flag = 1,
59 #endif /* BSP_PWM1_B_ALL */
60     },
61 #endif /* BSP_USING_PWM1 */
62 #ifdef BSP_USING_PWM2
63     {
64         .name = "pwm2",
65         .slice_num = 2,
66         .pin_a = BSP_PWM2_A_PIN,
67         .pin_b = BSP_PWM2_B_PIN,
68 #ifdef BSP_PWM2_A_ALL
69         .a_all_flag = 1,
70 #endif /* BSP_PWM2_A_ALL */
71 #ifdef BSP_PWM2_B_ALL
72         .b_all_flag = 1,
73 #endif /* BSP_PWM2_B_ALL */
74     },
75 #endif /* BSP_USING_PWM2 */
76 #ifdef BSP_USING_PWM3
77     {
78         .name = "pwm3",
79         .slice_num = 3,
80         .pin_a = BSP_PWM3_A_PIN,
81         .pin_b = BSP_PWM3_B_PIN,
82 #ifdef BSP_PWM3_A_ALL
83         .a_all_flag = 1,
84 #endif /* BSP_PWM3_A_ALL */
85 #ifdef BSP_PWM3_B_ALL
86         .b_all_flag = 1,
87 #endif /* BSP_PWM3_B_ALL */
88     },
89 #endif /* BSP_USING_PWM3 */
90 #ifdef BSP_USING_PWM4
91     {
92         .name = "pwm4",
93         .slice_num = 4,
94         .pin_a = BSP_PWM4_A_PIN,
95         .pin_b = BSP_PWM4_B_PIN,
96 #ifdef BSP_PWM4_A_ALL
97         .a_all_flag = 1,
98 #endif /* BSP_PWM4_A_ALL */
99 #ifdef BSP_PWM4_B_ALL
100         .b_all_flag = 1,
101 #endif /* BSP_PWM4_B_ALL */
102     },
103 #endif /* BSP_USING_PWM4 */
104 #ifdef BSP_USING_PWM5
105     {
106         .name = "pwm5",
107         .slice_num = 5,
108         .pin_a = BSP_PWM5_A_PIN,
109         .pin_b = BSP_PWM5_B_PIN,
110 #ifdef BSP_PWM5_A_ALL
111         .a_all_flag = 1,
112 #endif /* BSP_PWM5_A_ALL */
113 #ifdef BSP_PWM5_B_ALL
114         .b_all_flag = 1,
115 #endif /* BSP_PWM5_B_ALL */
116     },
117 #endif /* BSP_USING_PWM5 */
118 #ifdef BSP_USING_PWM6
119     {
120         .name = "pwm6",
121         .slice_num = 6,
122         .pin_a = BSP_PWM6_A_PIN,
123         .pin_b = BSP_PWM6_B_PIN,
124 #ifdef BSP_PWM6_A_ALL
125         .a_all_flag = 1,
126 #endif /* BSP_PWM6_A_ALL */
127 #ifdef BSP_PWM6_B_ALL
128         .b_all_flag = 1,
129 #endif /* BSP_PWM6_B_ALL */
130     },
131 #endif /* BSP_USING_PWM6 */
132 #ifdef BSP_USING_PWM7
133     {
134         .name = "pwm7",
135         .slice_num = 7,
136         .pin_a = BSP_PWM7_A_PIN,
137         .pin_b = BSP_PWM7_B_PIN,
138     },
139 #endif /* BSP_USING_PWM7 */
140 };
141 
142 
_pwm_set(rt_uint8_t slice_num,struct rt_pwm_configuration * configuration)143 static rt_err_t _pwm_set(rt_uint8_t slice_num, struct rt_pwm_configuration *configuration)
144 {
145     uint32_t period_hz = 1000000000 / configuration->period;
146     uint32_t pulse = 1000000000 / configuration->pulse;
147 
148     pwm_config config = pwm_get_default_config();
149     pwm_config_set_clkdiv(&config, 1.33f);
150     pwm_init(slice_num, &config, true);
151     pwm_set_wrap(slice_num, 100000000 / period_hz);
152     pwm_set_chan_level(slice_num, configuration->channel, 100000000 / pulse);
153 
154     return RT_EOK;
155 }
156 
_pwm_get(rt_uint8_t slice_num,struct rt_pwm_configuration * configuration)157 static rt_err_t _pwm_get(rt_uint8_t slice_num, struct rt_pwm_configuration *configuration)
158 {
159     uint32_t period_hz = pwm_hw->slice[slice_num].top;
160 
161     configuration->period = period_hz * 10;
162 
163     configuration->pulse = pwm_hw->slice[slice_num].cc * 10;
164 
165     return RT_EOK;
166 }
167 
_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)168 static rt_err_t _pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
169 {
170     struct pico_pwm *_pwm = rt_container_of(device, struct pico_pwm, pwm_device);
171     struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
172 
173     switch (cmd)
174     {
175     case PWM_CMD_ENABLE:
176         pwm_set_enabled (_pwm->slice_num, RT_TRUE);
177         return RT_EOK;
178     case PWM_CMD_DISABLE:
179         pwm_set_enabled (_pwm->slice_num, RT_FALSE);
180         return RT_EOK;
181     case PWM_CMD_SET:
182         return _pwm_set(_pwm->slice_num, configuration);
183     case PWM_CMD_GET:
184         return _pwm_get(_pwm->slice_num, configuration);
185     default:
186         return -RT_EINVAL;
187     }
188 }
189 
190 static struct rt_pwm_ops _pwm_ops =
191 {
192     _pwm_control
193 };
194 
rt_hw_pwm_init(void)195 int rt_hw_pwm_init(void)
196 {
197     int result = RT_EOK;
198 
199     for (int i = 0; i < sizeof(pico_pwm_obj) / sizeof(pico_pwm_obj[0]); i++)
200     {
201         if(pico_pwm_obj[i].a_all_flag)
202         {
203             gpio_set_function(pico_pwm_obj[i].slice_num * 2, GPIO_FUNC_PWM);
204             gpio_set_function(pico_pwm_obj[i].slice_num * 2 + 16, GPIO_FUNC_PWM);
205         }
206         else
207         {
208             gpio_set_function(pico_pwm_obj[i].pin_a, GPIO_FUNC_PWM);
209         }
210         if(pico_pwm_obj[i].b_all_flag)
211         {
212             gpio_set_function(pico_pwm_obj[i].slice_num * 2 + 1, GPIO_FUNC_PWM);
213             gpio_set_function(pico_pwm_obj[i].slice_num * 2 + 17, GPIO_FUNC_PWM);
214         }
215         else
216         {
217             gpio_set_function(pico_pwm_obj[i].pin_b, GPIO_FUNC_PWM);
218         }
219         result = rt_device_pwm_register(&pico_pwm_obj[i].pwm_device, pico_pwm_obj[i].name, &_pwm_ops, 0);
220         if(result != RT_EOK)
221         {
222             LOG_E("%s register fail.", pico_pwm_obj[i].name);
223         }
224     }
225 
226     return result;
227 }
228 INIT_DEVICE_EXPORT(rt_hw_pwm_init);
229 
230 #endif /* BSP_USING_PWM */
231