• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <stdio.h>
17 #include <errno.h>
18 #include "duet.h"
19 #include "duet_cm4.h"
20 #include "duet_pinmux.h"
21 #include "duet_pwm.h"
22 
PWM_IRQHandler(void)23 void PWM_IRQHandler(void)
24 {
25     //    duet_intrpt_enter();
26     //    duet_intrpt_exit();
27 }
28 
29 // pwm pinmux init
duet_pwm_pinmux_init(duet_pwm_dev_t * pwm)30 void duet_pwm_pinmux_init(duet_pwm_dev_t *pwm)
31 {
32     switch (pwm->port) {
33         case PWM_OUTPUT_CH0:
34             // pin mux control
35             // PWM0_PAD PAD14 1
36             duet_pinmux_config(PAD14, PF_PWM0);
37             break;
38         case PWM_OUTPUT_CH1:
39             // PWM1_PAD PAD10 1
40             duet_pinmux_config(PAD10, PF_PWM1);
41             break;
42         case PWM_OUTPUT_CH2:
43             // PWM2_PAD PAD15 1
44             duet_pinmux_config(PAD15, PF_PWM2);
45             break;
46         case PWM_OUTPUT_CH3:
47             // PWM3_PAD PAD11 1
48             duet_pinmux_config(PAD11, PF_PWM3);
49             break;
50         case PWM_OUTPUT_CH4:
51             // PWM4_PAD PAD6  4
52             duet_pinmux_config(PAD6, PF_PWM4);
53             break;
54         case PWM_OUTPUT_CH5:
55             // PWM5_PAD PAD0  4
56             duet_pinmux_config(PAD0, PF_PWM5);
57             break;
58         case PWM_OUTPUT_CH6:
59             // PWM6_PAD PAD7  4
60             duet_pinmux_config(PAD7, PF_PWM6);
61             break;
62         case PWM_OUTPUT_CH7:
63             // PWM7_PAD PAD1  4
64             duet_pinmux_config(PAD1, PF_PWM7);
65             break;
66         default:
67             break;
68     }
69 }
70 
71 // pwm freq and duty cycle config
duet_pwm_cfg(duet_pwm_dev_t * pwm)72 void duet_pwm_cfg(duet_pwm_dev_t *pwm)
73 {
74     uint32_t tmp_value;
75     switch (pwm->port) {
76         case PWM_OUTPUT_CH0:
77             PWM->PWMCTL |= PWM_COUNT_MODE; // 0: count-up mode, 1: count-up/down mode
78             tmp_value = PWM->PWM01LOAD & (~(0x0000FFFF));
79             tmp_value |= (SYSTEM_CLOCK / pwm->config.freq - 1);
80             PWM->PWM01LOAD = tmp_value;
81 
82             tmp_value = PWM->PWM0CMP & (~(0x0000FFFF));
83             tmp_value |= (uint16_t)(SYSTEM_CLOCK / pwm->config.freq * (1 - pwm->config.duty_cycle));
84             PWM->PWM0CMP = tmp_value;
85             PWM->PWM01DB = 0;
86             break;
87         case PWM_OUTPUT_CH1:
88             PWM->PWMCTL |= PWM_COUNT_MODE; // 0: count-up mode, 1: count-up/down mode
89             tmp_value = PWM->PWM01LOAD & (~(0x0000FFFF));
90             tmp_value |= (SYSTEM_CLOCK / pwm->config.freq - 1);
91             PWM->PWM01LOAD = tmp_value;
92 
93             tmp_value = PWM->PWM0CMP & (~(0xFFFF0000));
94             tmp_value |= (uint16_t)(SYSTEM_CLOCK / pwm->config.freq * (1 - pwm->config.duty_cycle)) << 16;
95             PWM->PWM0CMP = tmp_value;
96             PWM->PWM01DB = 0;
97             break;
98         case PWM_OUTPUT_CH2:
99             PWM->PWMCTL |= (PWM_COUNT_MODE << 1); // 0: count-up mode, 1: count-up/down mode
100             tmp_value = PWM->PWM01LOAD & (~(0xFFFF0000));
101             tmp_value |= ((uint16_t)(SYSTEM_CLOCK / pwm->config.freq - 1) << 16);
102             PWM->PWM01LOAD = tmp_value;
103 
104             tmp_value = PWM->PWM1CMP & (~(0x0000FFFF));
105             tmp_value |= (uint16_t)(SYSTEM_CLOCK / pwm->config.freq * (1 - pwm->config.duty_cycle));
106             PWM->PWM1CMP = tmp_value;
107             PWM->PWM01DB = 0;
108             break;
109         case PWM_OUTPUT_CH3:
110             PWM->PWMCTL |= (PWM_COUNT_MODE << 1); // 0: count-up mode, 1: count-up/down mode
111             tmp_value = PWM->PWM01LOAD & (~(0xFFFF0000));
112             tmp_value |= ((uint16_t)(SYSTEM_CLOCK / pwm->config.freq - 1) << 16);
113             PWM->PWM01LOAD = tmp_value;
114 
115             tmp_value = PWM->PWM1CMP & (~(0xFFFF0000));
116             tmp_value |= (uint16_t)(SYSTEM_CLOCK / pwm->config.freq * (1 - pwm->config.duty_cycle)) << 16;
117             PWM->PWM1CMP = tmp_value;
118             PWM->PWM01DB = 0;
119             break;
120         case PWM_OUTPUT_CH4:
121             PWM->PWMCTL |= (PWM_COUNT_MODE << 2); // 0: count-up mode, 1: count-up/down mode
122             tmp_value = PWM->PWM23LOAD & (~(0x0000FFFF));
123             tmp_value |= (SYSTEM_CLOCK / pwm->config.freq - 1);
124             PWM->PWM23LOAD = tmp_value;
125 
126             tmp_value = PWM->PWM2CMP & (~(0x0000FFFF));
127             tmp_value |= (uint16_t)(SYSTEM_CLOCK / pwm->config.freq * (1 - pwm->config.duty_cycle));
128             PWM->PWM2CMP = tmp_value;
129             PWM->PWM23DB = 0;
130             break;
131         case PWM_OUTPUT_CH5:
132             PWM->PWMCTL |= (PWM_COUNT_MODE << 2); // 0: count-up mode, 1: count-up/down mode
133             tmp_value = PWM->PWM23LOAD & (~(0x0000FFFF));
134             tmp_value |= (SYSTEM_CLOCK / pwm->config.freq - 1);
135             PWM->PWM23LOAD = tmp_value;
136 
137             tmp_value = PWM->PWM2CMP & (~(0xFFFF0000));
138             tmp_value |= (uint16_t)(SYSTEM_CLOCK / pwm->config.freq * (1 - pwm->config.duty_cycle)) << 16;
139             PWM->PWM2CMP = tmp_value;
140             PWM->PWM23DB = 0;
141             break;
142         case PWM_OUTPUT_CH6:
143             PWM->PWMCTL |= (PWM_COUNT_MODE << 3); // 0: count-up mode, 1: count-up/down mode
144             tmp_value = PWM->PWM23LOAD & (~(0xFFFF0000));
145             tmp_value |= ((uint16_t)(SYSTEM_CLOCK / pwm->config.freq - 1) << 16);
146             PWM->PWM23LOAD = tmp_value;
147 
148             tmp_value = PWM->PWM3CMP & (~(0x0000FFFF));
149             tmp_value |= (uint16_t)(SYSTEM_CLOCK / pwm->config.freq * (1 - pwm->config.duty_cycle));
150             PWM->PWM3CMP = tmp_value;
151             PWM->PWM23DB = 0;
152             break;
153         case PWM_OUTPUT_CH7:
154             PWM->PWMCTL |= (PWM_COUNT_MODE << 3); // 0: count-up mode, 1: count-up/down mode
155             tmp_value = PWM->PWM23LOAD & (~(0xFFFF0000));
156             tmp_value |= ((uint16_t)(SYSTEM_CLOCK / pwm->config.freq - 1) << 16);
157             PWM->PWM23LOAD = tmp_value;
158 
159             tmp_value = PWM->PWM3CMP & (~(0xFFFF0000));
160             tmp_value |= (uint16_t)(SYSTEM_CLOCK / pwm->config.freq * (1 - pwm->config.duty_cycle)) << 16;
161             PWM->PWM3CMP = tmp_value;
162             PWM->PWM23DB = 0;
163             break;
164         default:
165             break;
166     }
167 }
168 
169 /**
170  * Initialises a PWM pin
171  *
172  *
173  * @param[in]  pwm  the PWM device
174  *
175  * @return  0 : on success, EIO : if an error occurred with any step
176  */
duet_pwm_init(duet_pwm_dev_t * pwm)177 int32_t duet_pwm_init(duet_pwm_dev_t *pwm)
178 {
179     uint32_t reg_value;
180     if (NULL == pwm) {
181         return EIO;
182     }
183     if (pwm->port >= DUET_PWM_CH_NUM) {
184         return EIO;
185     }
186     // pinmux
187     duet_pwm_pinmux_init(pwm);
188 
189     // pwm clock enable
190     reg_value = REG_RD(PERI_CLK_EN_REG1) & (~PWM_BUS_CLK_BIT);
191     REG_WR(PERI_CLK_EN_REG1, (reg_value | (PWM_BUS_CLK_BIT)));
192 
193     PWM->PWMCFG &= ~(1 << pwm->port);
194     // PWM->PWMCFG |= (CNT_CLK_DIV_EN | CLK_DIV_CFG);
195     duet_pwm_cfg(pwm);
196     PWM->PWMINVERTTRIG = 0; // invert control
197     return 0;
198 }
199 
200 /**
201  * Starts Pulse-Width Modulation signal output on a PWM pin
202  *
203  * @param[in]  pwm  the PWM device
204  *
205  * @return  0 : on success, EIO : if an error occurred with any step
206  */
duet_pwm_start(duet_pwm_dev_t * pwm)207 int32_t duet_pwm_start(duet_pwm_dev_t *pwm)
208 {
209     if (NULL == pwm) {
210         return EIO;
211     }
212     if (pwm->port >= DUET_PWM_CH_NUM) {
213         return EIO;
214     }
215     PWM->PWMCFG |= (1 << pwm->port);
216     return 0;
217 }
218 
219 /**
220  * Stops output on a PWM pin
221  *
222  * @param[in]  pwm  the PWM device
223  *
224  * @return  0 : on success, EIO : if an error occurred with any step
225  */
duet_pwm_stop(duet_pwm_dev_t * pwm)226 int32_t duet_pwm_stop(duet_pwm_dev_t *pwm)
227 {
228     if (NULL == pwm) {
229         return EIO;
230     }
231     if (pwm->port >= DUET_PWM_CH_NUM) {
232         return EIO;
233     }
234     PWM->PWMCFG &= ~(1 << pwm->port);
235     return 0;
236 }
237 
238 /**
239  * change the para of pwm
240  *
241  * @param[in]  pwm  the PWM device
242  * @param[in]  para the para of pwm
243  *
244  * @return  0 : on success, EIO : if an error occurred with any step
245  */
duet_pwm_para_chg(duet_pwm_dev_t * pwm,duet_pwm_config_t para)246 int32_t duet_pwm_para_chg(duet_pwm_dev_t *pwm, duet_pwm_config_t para)
247 {
248     if (NULL == pwm) {
249         return EIO;
250     }
251     if (pwm->port >= DUET_PWM_CH_NUM) {
252         return EIO;
253     }
254     // duet_pwm_stop(pwm);
255     pwm->config = para;
256     duet_pwm_cfg(pwm);
257     // duet_pwm_start(pwm);
258     return 0;
259 }
260 
261 /**
262  * De-initialises an PWM interface, Turns off an PWM hardware interface
263  *
264  * @param[in]  pwm  the interface which should be de-initialised
265  *
266  * @return  0 : on success, EIO : if an error occurred with any step
267  */
duet_pwm_finalize(duet_pwm_dev_t * pwm)268 int32_t duet_pwm_finalize(duet_pwm_dev_t *pwm)
269 {
270     // pwm clock disable
271     // uint32_t reg_value;
272     if (NULL == pwm) {
273         return EIO;
274     }
275     if (pwm->port >= DUET_PWM_CH_NUM) {
276         return EIO;
277     }
278     // one clk enable for 8 pwm channel
279     // reg_value = REG_RD(PERI_CLK_CFG);
280     // REG_WR(PERI_CLK_CFG, (reg_value&(~PWM_CLK_EN)));
281     return duet_pwm_stop(pwm);
282 }
283 
284