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  * 2021-11-11     breo.com     first version
9  */
10 
11 #include <board.h>
12 #include "drv_pwm.h"
13 
14 #ifdef RT_USING_PWM
15     #if !defined(BSP_USING_TIM1_CH1) && !defined(BSP_USING_TIM1_CH2) && \
16         !defined(BSP_USING_TIM1_CH3) && !defined(BSP_USING_TIM1_CH4) && \
17         !defined(BSP_USING_TIM2_CH1) && !defined(BSP_USING_TIM2_CH2) && \
18         !defined(BSP_USING_TIM2_CH3) && !defined(BSP_USING_TIM2_CH4) && \
19         !defined(BSP_USING_TIM3_CH1) && !defined(BSP_USING_TIM3_CH2) && \
20         !defined(BSP_USING_TIM3_CH3) && !defined(BSP_USING_TIM3_CH4) && \
21         !defined(BSP_USING_TIM4_CH1) && !defined(BSP_USING_TIM4_CH2) && \
22         !defined(BSP_USING_TIM4_CH3) && !defined(BSP_USING_TIM4_CH4) && \
23         !defined(BSP_USING_TIM5_CH1) && !defined(BSP_USING_TIM5_CH2) && \
24         !defined(BSP_USING_TIM5_CH3) && !defined(BSP_USING_TIM5_CH4) && \
25         !defined(BSP_USING_TIM8_CH1) && !defined(BSP_USING_TIM8_CH2) && \
26         !defined(BSP_USING_TIM8_CH3) && !defined(BSP_USING_TIM8_CH4)
27         #error "Please define at least one BSP_USING_TIMx_CHx"
28     #endif
29 #endif /* RT_USING_PWM */
30 
31 #define MAX_PERIOD 65535
32 #define MIN_PERIOD 3
33 
34 #ifdef BSP_USING_PWM
35 
36 struct n32_pwm
37 {
38     TIM_Module *tim_handle;
39     const char *name;
40     struct rt_device_pwm pwm_device;
41     int8_t tim_en;
42     uint8_t ch_en;
43     uint32_t period;
44     uint32_t psc;
45 };
46 
47 static struct n32_pwm n32_pwm_obj[] =
48 {
49 #if defined(BSP_USING_TIM1_CH1) || defined(BSP_USING_TIM1_CH2) || \
50         defined(BSP_USING_TIM1_CH3) || defined(BSP_USING_TIM1_CH4)
51     {
52         .tim_handle = TIM1,
53         .name = "tim1pwm",
54     },
55 #endif
56 
57 #if defined(BSP_USING_TIM2_CH1) || defined(BSP_USING_TIM2_CH2) || \
58         defined(BSP_USING_TIM2_CH3) || defined(BSP_USING_TIM2_CH4)
59     {
60         .tim_handle = TIM2,
61         .name = "tim2pwm",
62     },
63 #endif
64 
65 #if defined(BSP_USING_TIM3_CH1) || defined(BSP_USING_TIM3_CH2) || \
66         defined(BSP_USING_TIM3_CH3) || defined(BSP_USING_TIM3_CH4)
67     {
68         .tim_handle = TIM3,
69         .name = "tim3pwm",
70     },
71 #endif
72 
73 #if defined(BSP_USING_TIM4_CH1) || defined(BSP_USING_TIM4_CH2) || \
74         defined(BSP_USING_TIM4_CH3) || defined(BSP_USING_TIM4_CH4)
75     {
76         .tim_handle = TIM4,
77         .name = "tim4pwm",
78     },
79 #endif
80 
81 #if defined(BSP_USING_TIM5_CH1) || defined(BSP_USING_TIM5_CH2) || \
82         defined(BSP_USING_TIM5_CH3) || defined(BSP_USING_TIM5_CH4)
83     {
84         .tim_handle = TIM5,
85         .name = "tim5pwm",
86     },
87 #endif
88 
89 #if defined(BSP_USING_TIM8_CH1) || defined(BSP_USING_TIM8_CH2) || \
90         defined(BSP_USING_TIM8_CH3) || defined(BSP_USING_TIM8_CH4)
91     {
92         .tim_handle = TIM8,
93         .name = "tim8pwm",
94     }
95 #endif
96 
97 };
98 
99 static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg);
100 static struct rt_pwm_ops drv_ops =
101 {
102     drv_pwm_control
103 };
104 
drv_pwm_enable(struct n32_pwm * pwm_dev,struct rt_pwm_configuration * configuration,rt_bool_t enable)105 static rt_err_t drv_pwm_enable(struct n32_pwm *pwm_dev, struct rt_pwm_configuration *configuration, rt_bool_t enable)
106 {
107     /* Get the value of channel */
108     rt_uint32_t channel = configuration->channel;
109     TIM_Module *TIMx = pwm_dev->tim_handle;
110 
111     if (enable)
112     {
113         pwm_dev->ch_en |= 0x1 << channel;
114     }
115     else
116     {
117         pwm_dev->ch_en &= ~(0x1 << channel);
118     }
119 
120     if (enable)
121     {
122         if (channel == 1)
123         {
124             TIM_EnableCapCmpCh(TIMx, TIM_CH_1, TIM_CAP_CMP_ENABLE);
125         }
126         else if (channel == 2)
127         {
128             TIM_EnableCapCmpCh(TIMx, TIM_CH_2, TIM_CAP_CMP_ENABLE);
129         }
130         else if (channel == 3)
131         {
132             TIM_EnableCapCmpCh(TIMx, TIM_CH_3, TIM_CAP_CMP_ENABLE);
133         }
134         else if (channel == 4)
135         {
136             TIM_EnableCapCmpCh(TIMx, TIM_CH_4, TIM_CAP_CMP_ENABLE);
137         }
138     }
139     else
140     {
141         if (channel == 1)
142         {
143             TIM_EnableCapCmpCh(TIMx, TIM_CH_1, TIM_CAP_CMP_DISABLE);
144         }
145         else if (channel == 2)
146         {
147             TIM_EnableCapCmpCh(TIMx, TIM_CH_2, TIM_CAP_CMP_DISABLE);
148         }
149         else if (channel == 3)
150         {
151             TIM_EnableCapCmpCh(TIMx, TIM_CH_3, TIM_CAP_CMP_DISABLE);
152         }
153         else if (channel == 4)
154         {
155             TIM_EnableCapCmpCh(TIMx, TIM_CH_4, TIM_CAP_CMP_DISABLE);
156         }
157     }
158 
159     if (pwm_dev->ch_en)
160     {
161         pwm_dev->tim_en = 0x1;
162         TIM_Enable(TIMx, ENABLE);
163     }
164     else
165     {
166         pwm_dev->tim_en = 0x0;
167         TIM_Enable(TIMx, DISABLE);
168     }
169 
170     return RT_EOK;
171 }
172 
drv_pwm_get(struct n32_pwm * pwm_dev,struct rt_pwm_configuration * configuration)173 static rt_err_t drv_pwm_get(struct n32_pwm *pwm_dev, struct rt_pwm_configuration *configuration)
174 {
175     RCC_ClocksType  RCC_Clockstruct;
176     rt_uint32_t ar, div, cc1, cc2, cc3, cc4;
177     rt_uint64_t tim_clock;
178     rt_uint32_t channel = configuration->channel;
179     TIM_Module *TIMx = pwm_dev->tim_handle;
180 
181     ar   = TIMx->AR;
182     div  = TIMx->PSC;
183     cc1  = TIMx->CCDAT1;
184     cc2  = TIMx->CCDAT2;
185     cc3  = TIMx->CCDAT3;
186     cc4  = TIMx->CCDAT4;
187 
188     RCC_GetClocksFreqValue(&RCC_Clockstruct);
189 
190     tim_clock = RCC_Clockstruct.Pclk2Freq;
191 
192     /* Convert nanosecond to frequency and duty cycle. */
193     tim_clock /= 1000000UL;
194     configuration->period = (ar + 1) * (div + 1) * 1000UL / tim_clock;
195     if (channel == 1)
196         configuration->pulse = (cc1 + 1) * (div + 1) * 1000UL / tim_clock;
197     if (channel == 2)
198         configuration->pulse = (cc2 + 1) * (div + 1) * 1000UL / tim_clock;
199     if (channel == 3)
200         configuration->pulse = (cc3 + 1) * (div + 1) * 1000UL / tim_clock;
201     if (channel == 4)
202         configuration->pulse = (cc4 + 1) * (div + 1) * 1000UL / tim_clock;
203 
204     return RT_EOK;
205 }
206 
drv_pwm_set(struct n32_pwm * pwm_dev,struct rt_pwm_configuration * configuration)207 static rt_err_t drv_pwm_set(struct n32_pwm *pwm_dev, struct rt_pwm_configuration *configuration)
208 {
209     TIM_Module *TIMx = pwm_dev->tim_handle;
210     rt_uint32_t channel = configuration->channel;
211     rt_uint32_t period;
212     rt_uint64_t psc;
213     rt_uint32_t pulse;
214 
215     RCC_ClocksType RCC_Clock;
216     RCC_GetClocksFreqValue(&RCC_Clock);
217     rt_uint64_t input_clock;
218     if ((TIM1 == TIMx) || (TIM8 == TIMx))
219     {
220         RCC_ConfigTim18Clk(RCC_TIM18CLK_SRC_SYSCLK);
221         input_clock = RCC_Clock.SysclkFreq;
222     }
223     else
224     {
225         if (1 == (RCC_Clock.HclkFreq / RCC_Clock.Pclk1Freq))
226             input_clock = RCC_Clock.Pclk1Freq;
227         else
228             input_clock = RCC_Clock.Pclk1Freq * 2;
229     }
230 
231     input_clock /= 1000000UL;
232     /* Convert nanosecond to frequency and duty cycle. */
233     period = (unsigned long long)configuration->period * input_clock / 1000ULL;
234     psc = period / MAX_PERIOD + 1;
235     period = period / psc;
236     if (period < MIN_PERIOD)
237     {
238         period = MIN_PERIOD;
239     }
240     if ((pwm_dev->period != period) || (pwm_dev->psc != psc))
241     {
242         /* Tim base configuration */
243         TIM_TimeBaseInitType TIM_TIMeBaseStructure;
244         TIM_InitTimBaseStruct(&TIM_TIMeBaseStructure);
245         TIM_TIMeBaseStructure.Period = period - 1;
246         TIM_TIMeBaseStructure.Prescaler = psc - 1;
247         TIM_TIMeBaseStructure.ClkDiv = 0;
248         TIM_TIMeBaseStructure.CntMode = TIM_CNT_MODE_UP;
249         TIM_InitTimeBase(TIMx, &TIM_TIMeBaseStructure);
250     }
251 
252     pulse = (unsigned long long)configuration->pulse * input_clock / psc / 1000ULL;
253     if (pulse > period)
254     {
255         pulse = period;
256     }
257 
258     /* PWM1 Mode configuration: Channel1 */
259     OCInitType  TIM_OCInitStructure;
260     TIM_InitOcStruct(&TIM_OCInitStructure);
261     TIM_OCInitStructure.OcMode = TIM_OCMODE_PWM1;
262     TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
263     TIM_OCInitStructure.Pulse = pulse;
264     TIM_OCInitStructure.OcPolarity = TIM_OC_POLARITY_HIGH;
265 
266     if (channel == 1)
267     {
268         TIM_InitOc1(TIMx, &TIM_OCInitStructure);
269         TIM_ConfigOc1Preload(TIMx, TIM_OC_PRE_LOAD_ENABLE);
270         if (!(pwm_dev->ch_en & (0x1 << channel)))
271             TIM_EnableCapCmpCh(TIMx, TIM_CH_1, TIM_CAP_CMP_DISABLE);
272     }
273     else if (channel == 2)
274     {
275         TIM_InitOc2(TIMx, &TIM_OCInitStructure);
276         TIM_ConfigOc2Preload(TIMx, TIM_OC_PRE_LOAD_ENABLE);
277         if (!(pwm_dev->ch_en & (0x1 << channel)))
278             TIM_EnableCapCmpCh(TIMx, TIM_CH_2, TIM_CAP_CMP_DISABLE);
279     }
280     else if (channel == 3)
281     {
282         TIM_InitOc3(TIMx, &TIM_OCInitStructure);
283         TIM_ConfigOc3Preload(TIMx, TIM_OC_PRE_LOAD_ENABLE);
284         if (!(pwm_dev->ch_en & (0x1 << channel)))
285             TIM_EnableCapCmpCh(TIMx, TIM_CH_3, TIM_CAP_CMP_DISABLE);
286     }
287     else if (channel == 4)
288     {
289         TIM_InitOc4(TIMx, &TIM_OCInitStructure);
290         TIM_ConfigOc4Preload(TIMx, TIM_OC_PRE_LOAD_ENABLE);
291         if (!(pwm_dev->ch_en & (0x1 << channel)))
292             TIM_EnableCapCmpCh(TIMx, TIM_CH_4, TIM_CAP_CMP_DISABLE);
293     }
294 
295     TIM_ConfigArPreload(TIMx, ENABLE);
296     TIM_EnableCtrlPwmOutputs(TIMx, ENABLE);
297 
298     return RT_EOK;
299 }
300 
drv_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)301 static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
302 {
303     struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
304     struct n32_pwm *pwm_dev = (struct n32_pwm *)(device->parent.user_data);
305 
306     switch (cmd)
307     {
308     case PWM_CMD_ENABLE:
309         return drv_pwm_enable(pwm_dev, configuration, RT_TRUE);
310     case PWM_CMD_DISABLE:
311         return drv_pwm_enable(pwm_dev, configuration, RT_FALSE);
312     case PWM_CMD_SET:
313         return drv_pwm_set(pwm_dev, configuration);
314     case PWM_CMD_GET:
315         return drv_pwm_get(pwm_dev, configuration);
316     default:
317         return -RT_EINVAL;
318     }
319 }
320 
rt_hw_pwm_init(void)321 static int rt_hw_pwm_init(void)
322 {
323     int i = 0;
324     int result = RT_EOK;
325 
326     for (i = 0; i < sizeof(n32_pwm_obj) / sizeof(n32_pwm_obj[0]); i++)
327     {
328         if (rt_device_pwm_register(&n32_pwm_obj[i].pwm_device,
329                                    n32_pwm_obj[i].name, &drv_ops, &(n32_pwm_obj[i])) == RT_EOK)
330         {
331             /* Init timer pin and enable clock */
332             void n32_msp_tim_init(void *Instance);
333             n32_msp_tim_init(n32_pwm_obj[i].tim_handle);
334         }
335         else
336         {
337             result = -RT_ERROR;
338         }
339     }
340 
341     return result;
342 }
343 INIT_BOARD_EXPORT(rt_hw_pwm_init);
344 
345 #endif
346 
347