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