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