1 /*
2  * Copyright (c) 2006-2025, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2020-07-26     supperthomas first version
9  *
10  */
11 
12 
13 #include <board.h>
14 #include "rtdevice.h"
15 #include "rtservice.h"
16 
17 #ifdef RT_USING_PWM
18 
19 #include <nrfx_pwm.h>
20 
21 struct mcu_pwm
22 {
23     struct rt_device_pwm pwm_device;
24 
25     nrfx_pwm_t *pwm_handle;
26     nrf_pwm_values_individual_t m_demo1_seq_values;
27     nrf_pwm_sequence_t m_demo1_seq;
28 
29     rt_uint8_t channel;
30     char *name;
31     rt_uint64_t pwm_src_clk;
32     uint8_t channel_0_pin;
33     uint8_t channel_1_pin;
34     uint8_t channel_2_pin;
35     uint8_t channel_3_pin;
36 };
37 
38 enum
39 {
40 #ifdef BSP_USING_PWM0
41     PWM0_INDEX,
42 #endif
43 #ifdef BSP_USING_PWM1
44     PWM1_INDEX,
45 #endif
46 #ifdef BSP_USING_PWM2
47     PWM2_INDEX,
48 #endif
49 #ifdef BSP_USING_PWM3
50     PWM3_INDEX,
51 #endif
52 };
53 #ifdef BSP_USING_PWM0
54 static nrfx_pwm_t m_pwm0 = NRFX_PWM_INSTANCE(0);
55 #define PWM0_CONFIG                             \
56     {                                           \
57        .pwm_handle              =  &m_pwm0,     \
58        .name                    = "pwm0",       \
59        .pwm_src_clk             = 1000000,      \
60     }
61 #endif
62 
63 #ifdef BSP_USING_PWM1
64 static nrfx_pwm_t m_pwm1 = NRFX_PWM_INSTANCE(1);
65 #define PWM1_CONFIG                             \
66     {                                           \
67        .pwm_handle              =  &m_pwm1,         \
68        .name                    = "pwm1",       \
69        .pwm_src_clk             = 1000000,             \
70     }
71 #endif
72 
73 #ifdef BSP_USING_PWM2
74 static nrfx_pwm_t m_pwm2 = NRFX_PWM_INSTANCE(2);
75 #define PWM2_CONFIG                             \
76     {                                           \
77        .pwm_handle              =  &m_pwm2,         \
78        .name                    = "pwm2",       \
79        .pwm_src_clk             = 1000000,             \
80     }
81 #endif
82 
83 #ifdef BSP_USING_PWM3
84 static nrfx_pwm_t m_pwm3 = NRFX_PWM_INSTANCE(3);
85 #define PWM3_CONFIG                             \
86     {                                           \
87        .pwm_handle              =  &m_pwm3,         \
88        .name                    = "pwm3",       \
89        .pwm_src_clk             = 1000000,             \
90     }
91 #endif
92 
93 static struct mcu_pwm mcu_pwm_obj[] =
94 {
95 #ifdef BSP_USING_PWM0
96     PWM0_CONFIG,
97 #endif
98 #ifdef BSP_USING_PWM1
99     PWM1_CONFIG,
100 #endif
101 
102 #ifdef BSP_USING_PWM2
103     PWM2_CONFIG,
104 #endif
105 
106 #ifdef BSP_USING_PWM3
107     PWM3_CONFIG,
108 #endif
109 };
110 
111 static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg);
112 static struct rt_pwm_ops drv_ops =
113 {
114     drv_pwm_control
115 };
116 
drv_pwm_enable(struct mcu_pwm * p_mcu,struct rt_pwm_configuration * configuration,rt_bool_t enable)117 static rt_err_t drv_pwm_enable(struct mcu_pwm *p_mcu, struct rt_pwm_configuration *configuration, rt_bool_t enable)
118 {
119     if (!enable)
120     {
121         nrfx_pwm_stop(p_mcu->pwm_handle, true);
122     }
123     else
124     {
125         (void)nrfx_pwm_simple_playback(p_mcu->pwm_handle, &p_mcu->m_demo1_seq, 1, NRFX_PWM_FLAG_LOOP);
126     }
127 
128     return RT_EOK;
129 }
130 
mcu_get_channel_number(uint8_t channel)131 uint8_t mcu_get_channel_number(uint8_t channel)
132 {
133     if (channel & 0x01)
134     {
135         return 0;
136     }
137     else if (channel & 0x02)
138     {
139         return 1;
140     }
141     else if (channel & 0x04)
142     {
143         return 2;
144     }
145     else if (channel & 0x08)
146     {
147         return 3;
148     }
149     return 0;
150 }
151 
drv_pwm_get(struct mcu_pwm * pwm_handle,struct rt_pwm_configuration * configuration)152 static rt_err_t drv_pwm_get(struct mcu_pwm *pwm_handle, struct rt_pwm_configuration *configuration)
153 {
154     rt_uint8_t channel_number = mcu_get_channel_number(configuration->channel);
155     uint8_t tick_pscond;
156 
157     tick_pscond = pwm_handle->pwm_src_clk / 1000000UL;
158     configuration->period = pwm_handle->pwm_handle->p_registers->COUNTERTOP * 1000UL / tick_pscond;
159     configuration->pulse = pwm_handle->pwm_handle->p_registers->SEQ[channel_number].PTR / tick_pscond;
160 
161     return RT_EOK;
162 }
163 
nrfx_set_prioid(nrfx_pwm_t * pwm_handle,uint32_t perioid)164 static void nrfx_set_prioid(nrfx_pwm_t *pwm_handle, uint32_t perioid)
165 {
166     pwm_handle->p_registers->COUNTERTOP = perioid;
167 }
168 
drv_pwm_set(struct mcu_pwm * p_mcu,struct rt_pwm_configuration * configuration)169 static rt_err_t drv_pwm_set(struct mcu_pwm *p_mcu, struct rt_pwm_configuration *configuration)
170 {
171     rt_uint32_t period, pulse;
172     uint8_t tick_pscond;
173     tick_pscond = p_mcu->pwm_src_clk / 1000000UL;
174 
175     p_mcu->pwm_handle->p_registers->COUNTERTOP = (unsigned long long)configuration->period * tick_pscond;
176     if (configuration->channel & 0x01)
177     {
178         p_mcu->m_demo1_seq_values.channel_0 = configuration->pulse;
179     }
180 
181     if (configuration->channel & 0x02)
182     {
183         p_mcu->m_demo1_seq_values.channel_1 = configuration->pulse;
184     }
185 
186     if (configuration->channel & 0x04)
187     {
188         p_mcu->m_demo1_seq_values.channel_2 = configuration->pulse;
189     }
190 
191     if (configuration->channel & 0x08)
192     {
193         p_mcu->m_demo1_seq_values.channel_3 = configuration->pulse;
194     }
195     return RT_EOK;
196 }
197 
drv_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)198 static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
199 {
200     struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
201     void *pwm_handle = (void *)device->parent.user_data;
202     nrfx_pwm_t *p_handle = (nrfx_pwm_t *)pwm_handle;
203     struct mcu_pwm *p_mcu = rt_container_of(p_handle, struct mcu_pwm, pwm_handle);
204     switch (cmd)
205     {
206     case PWM_CMD_ENABLE:
207         return drv_pwm_enable(p_mcu, configuration, RT_TRUE);
208     case PWM_CMD_DISABLE:
209         return drv_pwm_enable(p_mcu, configuration, RT_FALSE);
210     case PWM_CMD_SET:
211         return drv_pwm_set(p_mcu, configuration);
212     case PWM_CMD_GET:
213         return drv_pwm_get(p_mcu, configuration);
214     default:
215         return -RT_EINVAL;
216     }
217 }
218 
mcu_hw_pwm_init(struct mcu_pwm * device)219 static rt_err_t mcu_hw_pwm_init(struct mcu_pwm *device)
220 {
221 #define NRFX_PWM_PIN_INVERTED    0x80
222 #define _PRIO_APP_LOWEST    7
223     nrfx_pwm_config_t config0 =
224     {
225         .irq_priority = _PRIO_APP_LOWEST,
226         .base_clock   = NRF_PWM_CLK_1MHz,  /* default value */
227         .count_mode   = NRF_PWM_MODE_UP,
228         .top_value    = 5000,              /* default vaule */
229         .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
230         .step_mode    = NRF_PWM_STEP_AUTO
231     };
232     rt_err_t result = RT_EOK;
233     if (device->pwm_src_clk == 1000000)
234     {
235         config0.base_clock = NRF_PWM_CLK_1MHz;
236     }
237     else if (device->pwm_src_clk == 2000000)
238     {
239         config0.base_clock = NRF_PWM_CLK_2MHz;
240     }
241     else if (device->pwm_src_clk == 8000000)
242     {
243         config0.base_clock = NRF_PWM_CLK_8MHz;
244     }
245     else
246     {
247         config0.base_clock = NRF_PWM_CLK_1MHz;
248     }
249 
250     if (device->channel & 0x01)
251     {
252         config0.output_pins[0] = device->channel_0_pin | NRFX_PWM_PIN_INVERTED;
253     }
254 
255     if (device->channel & 0x02)
256     {
257         config0.output_pins[1] = device->channel_1_pin | NRFX_PWM_PIN_INVERTED;
258     }
259 
260     if (device->channel & 0x04)
261     {
262         config0.output_pins[2] = device->channel_2_pin | NRFX_PWM_PIN_INVERTED;
263     }
264 
265     if (device->channel & 0x08)
266     {
267         config0.output_pins[3] = device->channel_3_pin | NRFX_PWM_PIN_INVERTED;
268     }
269     device->m_demo1_seq.values.p_individual = &device->m_demo1_seq_values;
270     device->m_demo1_seq.length = NRF_PWM_VALUES_LENGTH(device->m_demo1_seq_values),
271                         nrfx_pwm_init(device->pwm_handle, &config0, NULL, NULL);
272     return result;
273 }
274 
pwm_get_channel(void)275 static void pwm_get_channel(void)
276 {
277 #ifdef BSP_USING_PWM0_CH0
278     mcu_pwm_obj[PWM0_INDEX].channel |= 1 << 0;
279     mcu_pwm_obj[PWM0_INDEX].channel_0_pin = BSP_USING_PWM0_CH0;
280 #endif
281 #ifdef BSP_USING_PWM0_CH1
282     mcu_pwm_obj[PWM0_INDEX].channel |= 1 << 1;
283     mcu_pwm_obj[PWM0_INDEX].channel_1_pin = BSP_USING_PWM0_CH1;
284 #endif
285 #ifdef BSP_USING_PWM0_CH2
286     mcu_pwm_obj[PWM0_INDEX].channel |= 1 << 2;
287     mcu_pwm_obj[PWM0_INDEX].channel_2_pin = BSP_USING_PWM0_CH2;
288 #endif
289 #ifdef BSP_USING_PWM0_CH3
290     mcu_pwm_obj[PWM0_INDEX].channel |= 1 << 3;
291     mcu_pwm_obj[PWM0_INDEX].channel_3_pin = BSP_USING_PWM0_CH3;
292 #endif
293 #ifdef BSP_USING_PWM1_CH0
294     mcu_pwm_obj[PWM1_INDEX].channel |= 1 << 0;
295     mcu_pwm_obj[PWM1_INDEX].channel_0_pin = BSP_USING_PWM1_CH0;
296 #endif
297 #ifdef BSP_USING_PWM1_CH1
298     mcu_pwm_obj[PWM1_INDEX].channel |= 1 << 1;
299     mcu_pwm_obj[PWM1_INDEX].channel_1_pin = BSP_USING_PWM1_CH1;
300 #endif
301 #ifdef BSP_USING_PWM1_CH2
302     mcu_pwm_obj[PWM1_INDEX].channel |= 1 << 2;
303     mcu_pwm_obj[PWM1_INDEX].channel_2_pin = BSP_USING_PWM1_CH2;
304 #endif
305 #ifdef BSP_USING_PWM1_CH3
306     mcu_pwm_obj[PWM1_INDEX].channel |= 1 << 3;
307     mcu_pwm_obj[PWM1_INDEX].channel_3_pin = BSP_USING_PWM1_CH3;
308 #endif
309 #ifdef BSP_USING_PWM2_CH0
310     mcu_pwm_obj[PWM2_INDEX].channel |= 1 << 0;
311     mcu_pwm_obj[PWM2_INDEX].channel_0_pin = BSP_USING_PWM2_CH0;
312 #endif
313 #ifdef BSP_USING_PWM2_CH1
314     mcu_pwm_obj[PWM2_INDEX].channel |= 1 << 1;
315     mcu_pwm_obj[PWM2_INDEX].channel_1_pin = BSP_USING_PWM2_CH1;
316 #endif
317 #ifdef BSP_USING_PWM2_CH2
318     mcu_pwm_obj[PWM2_INDEX].channel |= 1 << 2;
319     mcu_pwm_obj[PWM2_INDEX].channel_2_pin = BSP_USING_PWM2_CH2;
320 #endif
321 #ifdef BSP_USING_PWM2_CH3
322     mcu_pwm_obj[PWM2_INDEX].channel |= 1 << 3;
323     mcu_pwm_obj[PWM2_INDEX].channel_3_pin = BSP_USING_PWM2_CH3;
324 #endif
325 #ifdef BSP_USING_PWM3_CH0
326     mcu_pwm_obj[PWM3_INDEX].channel |= 1 << 0;
327     mcu_pwm_obj[PWM3_INDEX].channel_0_pin = BSP_USING_PWM3_CH0;
328 #endif
329 #ifdef BSP_USING_PWM3_CH1
330     mcu_pwm_obj[PWM3_INDEX].channel |= 1 << 1;
331     mcu_pwm_obj[PWM3_INDEX].channel_1_pin = BSP_USING_PWM3_CH1;
332 #endif
333 #ifdef BSP_USING_PWM3_CH2
334     mcu_pwm_obj[PWM3_INDEX].channel |= 1 << 2;
335     mcu_pwm_obj[PWM3_INDEX].channel_2_pin = BSP_USING_PWM3_CH2;
336 #endif
337 #ifdef BSP_USING_PWM3_CH3
338     mcu_pwm_obj[PWM3_INDEX].channel |= 1 << 3;
339     mcu_pwm_obj[PWM3_INDEX].channel_3_pin = BSP_USING_PWM3_CH3;
340 #endif
341 }
342 
mcu_pwm_init(void)343 static int mcu_pwm_init(void)
344 {
345     int i = 0;
346     int result = RT_EOK;
347 
348     pwm_get_channel();
349     for (i = 0; i < sizeof(mcu_pwm_obj) / sizeof(mcu_pwm_obj[0]); i++)
350     {
351         /* pwm init */
352         if (mcu_hw_pwm_init(&mcu_pwm_obj[i]) != RT_EOK)
353         {
354             rt_kprintf("\r\n %s init failed", mcu_pwm_obj[i].name);
355             result = -RT_ERROR;
356             goto __exit;
357         }
358         else
359         {
360             rt_kprintf("\r\n %s init success", mcu_pwm_obj[i].name);
361 
362             /* register pwm device */
363             if (rt_device_pwm_register(&mcu_pwm_obj[i].pwm_device, mcu_pwm_obj[i].name, &drv_ops, &mcu_pwm_obj[i].pwm_handle) == RT_EOK)
364             {
365                 rt_kprintf("\r\n %s register success", mcu_pwm_obj[i].name);
366             }
367             else
368             {
369                 rt_kprintf("\r\n %s register failed", mcu_pwm_obj[i].name);
370                 result = -RT_ERROR;
371             }
372         }
373     }
374 __exit:
375     return result;
376 }
377 INIT_DEVICE_EXPORT(mcu_pwm_init);
378 
379 
380 
381 /* test example */
382 #define PWM_DEV_NAME        "pwm0"  /* PWM  name*/
383 #define PWM_DEV_CHANNEL     15       /* PWM  channel */
384 
385 struct rt_device_pwm *pwm_dev;
386 
pwm_led_sample(int argc,char * argv[])387 static int pwm_led_sample(int argc, char *argv[])
388 {
389     rt_uint32_t period, pulse, dir;
390 
391     period = 50000;   /* 50ms*/
392     dir = 1;
393     pulse = 0;
394 
395 
396     pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
397     if (pwm_dev == RT_NULL)
398     {
399         rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);
400         return -RT_ERROR;
401     }
402 
403     rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
404     rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
405 
406     while (1)
407     {
408         rt_thread_mdelay(50);
409         if (dir)
410         {
411             pulse += 500;
412         }
413         else
414         {
415             pulse -= 500;
416         }
417 
418         if (pulse >= period)
419         {
420             dir = 0;
421         }
422 
423         if (0 == pulse)
424         {
425             dir = 1;
426         }
427 
428 
429         rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
430     }
431 }
432 MSH_CMD_EXPORT(pwm_led_sample, pwm sample);
433 
434 #endif
435 
436