• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2022 Beken Corporation
2 //
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 #pragma once
16 #include <common/bk_include.h>
17 #include <driver/pwm_types.h>
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 /* @brief Overview about this API header
24  *
25  */
26 
27 /**
28  * @brief PWM API
29  * @defgroup bk_api_pwm PWM API group
30  * @{
31  */
32 
33 /**
34  * @brief     Init the PWM driver
35  *
36  * This API init the resoure common to all PWM channels:
37  *   - Init PWM driver control memory
38  *   - Configure PWM common clock to 26M
39  *
40  * This API should be called before any other PWM APIs.
41  *
42  * @return
43  *    - BK_OK: succeed
44  *    - others: other errors.
45  */
46 bk_err_t bk_pwm_driver_init(void);
47 
48 /**
49  * @brief     Deinit the PWM driver
50  *
51  * This API free all resource related to PWM and power down all PWM channels.
52  *
53  * @return
54  *    - BK_OK: succeed
55  *    - others: other errors.
56  */
57 bk_err_t bk_pwm_driver_deinit(void);
58 
59 /**
60  * @brief     Init the PWM channel
61  *
62  * This API init the PWM channel:
63  *  - Power up the PWM channel
64  *  - Configure the PWM channel clock to 26M
65  *  - Map the PWM channel to dedicated GPIO port
66  *  - Set the period and duty cycle.
67  *
68  * For duty/cycle relationship, refer to bk_pwm_set_period_duty()
69  *
70  * @return
71  *    - BK_OK: succeed
72  *    - BK_ERR_PWM_NOT_INIT: PWM driver not init
73  *    - BK_ERR_NULL_PARAM: config is NULL
74  *    - BK_ERR_PWM_CHAN_ID: invalid PWM channel
75  *    - BK_ERR_PWM_PERIOD_DUTY: PWM duty/period relationship is invalid
76  *    - others: other errors.
77  */
78 bk_err_t bk_pwm_init(pwm_chan_t chan, const pwm_init_config_t *config);
79 
80 /**
81  * @brief     Deinit a PWM channel
82  *
83  * This API deinit the PWM channel:
84  *   - Stop the PWM channel
85  *   - Reset all configuration of PWM channel to default value
86  *   - Power down the PWM channel
87  *
88  * @return
89  *    - BK_OK: succeed
90  *    - others: other errors.
91  */
92 bk_err_t bk_pwm_deinit(pwm_chan_t chan);
93 
94 /**
95  * @brief     Stop a PWM channel
96  *
97  * This API init the resoure common to all PWM channels:
98  *   - Init PWM driver control memory
99  *   - Configure PWM common clock to 26M
100  *
101  * @return
102  *    - BK_OK: succeed
103  *    - others: other errors.
104  */
105 bk_err_t bk_pwm_start(pwm_chan_t chan);
106 
107 /**
108  * @brief     Stop a PWM channel
109  *
110  * This API init the resoure common to all PWM channels:
111  *   - Init PWM driver control memory
112  *   - Configure PWM common clock to 26M
113  *
114  * @return
115  *    - BK_OK: succeed
116  *    - others: other errors.
117  */
118 bk_err_t bk_pwm_stop(pwm_chan_t chan);
119 
120 /**
121  * @brief     Configure the PWM period and duty cycle.
122  *
123  * This API is used to configure the period and duty time. The unit is cycle of PWM channel clock,
124  * since the PWM channel clock is default to 26M, the unit is 1/26M (1/26 000 000) seconds.
125  *
126  * The beken chip supports up to 3 duties, the exact duty numbers depends on the target type.
127  *
128  * EXample1 - the simplest case::
129  *
130  *     Clock cycle = 1/26M
131  *     Initial signal is High
132  *     duty_cycle = D1 = 3
133  *     duty2_cycle = 0
134  *     duty3_cycle = 0
135  *     period_cycle = 3 + 2 = 5
136  *
137  *                       |<-C->|
138  *                        __    __    __    __    __    __    __    __    __    __    __    __
139  *     Clock Signal:   __|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__
140  *                       __________________             _________________             ___________
141  *     PWM Signal:    __|                  |___________|                 |___________|
142  *
143  *     Duty1:           |<------- D1 ----->|
144  *
145  *     Period:          |<---------- Period1 --------->|<------ Period2 ------------>|
146  *
147  *
148  * Example2 - 3 duty with initial signal high::
149  *
150  *     Clock cycle = 1/26M
151  *     Duty_cycle = D1 = 1
152  *     Duty2_cycle = D2 = 2
153  *     Duty3_cycle = D3 = 3
154  *     period_cycle = D1 + D2 + D3 = 6
155  *
156  *                       |<-C->|
157  *                        __    __    __    __    __    __    __    __    __    __    __    __    __
158  *     Clock Signal:   __|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|
159  *                       ______             _________________ _____             _________________
160  *     PWM Signal:    __|      |___________|                 |     |___________|                 |__
161  *
162  *     Duty1:           |<-D1->|<----D2--->|<------D3------->|
163  *
164  *     Period:          |<--------------- Period1 ---------->|<------------ Period2 ------------>|
165  *
166  *
167  * Example3 - 3 duty with initial signal low::
168  *
169  *     Clock cycle = 1/26M
170  *     Duty_cycle = D1 = 1
171  *     Duty2_cycle = D2 = 2
172  *     Duty3_cycle = D3 = 3
173  *     period_cycle = D1 + D2 + D3 = 6
174  *
175  *                       |<-C->|
176  *                        __    __    __    __    __    __    __    __    __    __    __    __    __
177  *     Clock Signal:   __|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|
178  *                     __       ___________                         ___________
179  *     PWM Signal:       |_____|           |_________________|_____|           |_________________|__
180  *
181  *     Duty1:           |<-D1->|<----D2--->|<------D3------->|
182  *
183  *     Period:          |<--------------- Period1 ---------->|<------------ Period2 -------------|
184  *
185  *
186  * Example4 - 3 duty with initial signal low and period > (D1 + D2 + D3)::
187  *
188  *     Clock cycle = 1/26M
189  *     Duty_cycle = D1 = 1
190  *     Duty2_cycle = D2 = 2
191  *     Duty3_cycle = D3 = 3
192  *     period_cycle = D1 + D2 + D3 + 1 = 7
193  *
194  *                       |<-C->|
195  *                        __    __    __    __    __    __    __    __    __    __    __    __    __
196  *     Clock Signal:   __|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|  |__|
197  *                     __       ___________                   _____       ___________
198  *     PWM Signal:       |_____|           |_________________|     |_____|           |______________
199  *
200  *     Duty1:           |<-D1->|<----D2--->|<------D3------->|
201  *
202  *     Period:          |<--------------- Period ----------------->|
203  *
204  * @attention 1. The period should great or equal to (D1 + D2 + D3)
205  * @attention 2. If the duty Dx is 0, then Dx+1 to D3 should also be 0. If D1 is 0, it indicates the
206  *               duty ratio is 0% and the signal is always low.
207  * @attention 3. If D1 equals period, it indicates the duty ratio is 100% and the signal is always high.
208  * @attention 4. The signal strengh between two successive duties is opposite, e.g. if signal of D1
209  *               is high, then signal of D2 is low.
210  * @attention 5. The initial signal is the signal strengh of D1 if D1 is not 0.
211  * @attention 6. The duty/period configuration is very flexible, different configurations may have
212  *               same result.
213  *
214  * @return
215  *    - BK_OK: succeed
216  *    - BK_ERR_NULL_PARAM: config is NULL
217  *    - BK_ERR_PWM_CHAN_NOT_INIT: PWM channel not init
218  *    - BK_ERR_PWM_CHAN_ID: invalid PWM channel
219  *    - BK_ERR_PWM_PERIOD_DUTY: PWM duty/period relationship is invalid
220  *    - others: other errors.
221  */
222 bk_err_t bk_pwm_set_period_duty(pwm_chan_t chan, pwm_period_duty_config_t *config);
223 
224 /**
225  * @brief     Set the initial signal to low
226  *
227  * Set the initial signal level of the first duty which is indicated by duty_cycle.
228  *
229  * @attention The signal will always be high if the duty_cycle equals period cycle
230  *            (duty ratio is 100%), regardless whether this API is called or NOT.
231  *
232  * @return
233  *    - BK_OK: succeed
234  *    - BK_ERR_PWM_CHAN_NOT_INIT: PWM channel not init
235  *    - BK_ERR_PWM_CHAN_ID: invalid PWM channel
236  *    - others: other errors.
237  */
238 bk_err_t bk_pwm_set_init_signal_low(pwm_chan_t chan);
239 
240 /**
241  * @brief     Set the initial signal to high
242  *
243  * Set the initial signal level of the first duty which is indicated by duty_cycle.
244  *
245  * @attention The signal will always be low if the duty_cycle is 0 (duty ratio is 0%),
246  *            regardless whether this API is called or NOT.
247  *
248  * @return
249  *    - BK_OK: succeed
250  *    - BK_ERR_PWM_CHAN_NOT_INIT: PWM channel not init
251  *    - BK_ERR_PWM_CHAN_ID: invalid PWM channel
252  *    - others: other errors.
253  */
254 bk_err_t bk_pwm_set_init_signal_high(pwm_chan_t chan);
255 
256 /**
257  * @brief     Register the interrupt service routine for PWM channel
258  *
259  * @attention 1. Both bk_pwm_capture_init() and this API can set the ISR, the one called later
260  *            makes sense.
261  *
262  * @return
263  *    - BK_OK: succeed
264  *    - BK_ERR_PWM_NOT_INIT: PWM driver not init
265  *    - BK_ERR_PWM_CHAN_ID: invalid PWM channel
266  *    - others: other errors.
267  */
268 bk_err_t bk_pwm_register_isr(pwm_chan_t chan, pwm_isr_t isr);
269 
270 /**
271  * @brief     Enable interrupt of PWM channel
272  *
273  * The PWM channel interrupt is disabled by default when starting the channel by bk_pwm_start() or
274  * bk_pwm_group_start(), while it's enabled by default when starting the channel by
275  * bk_pwm_capture_start().
276  *
277  * This API is designed mainly for debug purpose, we can use it to enable the interrupt of any PWM
278  * channel, regardless of whether the channel is started by bk_pwm_start() or bk_pwm_group_start() or
279  * bk_pwm_capture_start().
280  *
281  * The bk_pwm_stop() and bk_pwm_group_stop() also disable the interrupt, but the bk_pwm_start()
282  * and bk_pwm_group_start will not enable the interrupt. So if the channel interrupt is enabled,
283  * and then stop and start the channel, we need to call this API to re-enable the interrupt.
284  *
285  * @attention 1. The interrupt can be enabled only after PWM channel is started by bk_pwm_start().
286  *
287  * @return
288  *    - BK_OK: succeed
289  *    - BK_ERR_PWM_NOT_INIT: PWM driver not init
290  *    - BK_ERR_PWM_CHAN_ID: invalid PWM channel
291  *    - BK_ERR_PWM_CHAN_NOT_START: PWM channel is not started
292  *    - others: other errors.
293  */
294 bk_err_t bk_pwm_enable_interrupt(pwm_chan_t chan);
295 
296 /**
297  * @brief     Disable interrupt of PWM channel
298  *
299  * Stop the interrupt of any PWM channel, regardless whether the channel is in PWM mode, or
300  * PWM capture mode, or PWM group mode.
301  *
302  * @attention 1. bk_pwm_capture_start() will enable the interrupt anyway, so if we want to disable
303  *             the interrupt of PWM capture channel, we need to call this API anytime
304  *             bk_pwm_capture_start() is called.
305  *
306  * @param chan the channel ID
307  *
308  * @return
309  *    - BK_OK: succeed
310  *    - BK_ERR_PWM_NOT_INIT: PWM driver not init
311  *    - BK_ERR_PWM_CHAN_ID: invalid PWM channel
312  *    - others: other errors.
313  */
314 bk_err_t bk_pwm_disable_interrupt(pwm_chan_t chan);
315 
316 /**
317  * @brief     Init the PWM group
318  *
319  * This API init the PWM group.
320  * The PWM group is a channel pair that has following attributes:
321  *  - The period is same
322  *  - The initial signal level is opposite
323  *  - Start and stop at the same time
324  *
325  * Below is a picture to demonstrate the relationship between duty and period::
326  *
327  *                  |<------------------------ period_cycle ---------------------------->|
328  *                  |<--chan1_duty_cycle -->|<- D1 --|<--- chan2_duty_cycle --->|<- D2 ->|
329  *                   _______________________
330  *      channe1 1   |                       |____________________________________________|
331  *                                                    __________________________
332  *      channel 2   |________________________________|                          |________|
333  *
334  * The D1/D2 indicates the dead time cycle, it's calculated based on following formula:
335  * D1 = D2 = (period - chan1_duty_cycle - chan2_duty_cycle)/2
336  *
337  * @attention 1. This API doesn't check whether the PWM channel is already used in other mode.
338  *            e.g. If the API doesn't returns error if config->chan1 is already used in capture
339  *            mode, the application need to make sure the channel configured in the group is not
340  *            used for other purpose.
341  * @attention 2. The chan2_duty_cycle is actually the 2nd signal wave for channel 2, as depicted
342  *            in above picture.
343  * @attention 3. This API supports to group any two available channel into a PWM group, however,
344  *            we recommend to group 0/1, 2/3, 4/5 into a group, because hardware can support these
345  *            group directly and we can start the channels in the group at exactly same time.
346  * @attention 4. The chan1_duty_cycle and chan2_duty_cycle should be great than 0.
347  *
348  * @param config configuration of PWM group
349  * @param group store the group ID if the API is succeed.
350  *
351  * @return
352  *    - BK_OK: succeed
353  *    - BK_ERR_PWM_NOT_INIT: PWM driver not init
354  *    - BK_ERR_NULL_PARAM: config or group is NULL
355  *    - BK_ERR_PWM_CHAN_ID: channel 1 or 2 in the group is invalid
356  *    - BK_ERR_PWM_GROUP_SAME_CHAN: channel 1 and 2 are same
357  *    - BK_ERR_PWM_GROUP_EXIST: a group with channel 1 and 2 is already exists
358  *    - BK_ERR_PWM_GROUP_CHAN_USED: a existing group has a channel equals to channel 1 or 2
359  *    - BK_ERR_PWM_GROUP_DUTY: period cycle < (chan1_duty_cycle + chan2_duty_cycle)
360  *    - BK_ERR_PWM_PERIOD_DUTY: PWM duty/period relationship is invalid
361  *    - others: other errors.
362  */
363 bk_err_t bk_pwm_group_init(const pwm_group_init_config_t *config, pwm_group_t *group);
364 
365 /**
366  * @brief     Deinit a PWM group
367  *
368  * This API stops and powers down channels in a PWM group.
369  *
370  * @attention This API returns BK_OK directly if the group doesn't exist.
371  *
372  * @param group the group ID returned bk bk_pwm_group_init()
373  *
374  * @return
375  *    - BK_OK: succeed
376  *    - others: other errors.
377  */
378 bk_err_t bk_pwm_group_deinit(pwm_group_t group);
379 
380 /**
381  * @brief     Configure the PWM group
382  *
383  * Configure the duty and period of a PWM group, for duty/period relationship refer to
384  * bk_pwm_group_init().
385  *
386  * @attention The configuration can't take effect until the current period is ended
387  *
388  * @param group the group ID to be configured
389  * @param config configuration of PWM group
390  *
391  * @return
392  *    - BK_OK: succeed
393  *    - BK_ERR_NULL_PARAM: config or group is NULL
394  *    - BK_ERR_PWM_GROUP_NOT_EXIST: the group doesn't exist
395  *    - BK_ERR_PWM_GROUP_DUTY: period cycle < (chan1_duty_cycle + chan2_duty_cycle)
396  *    - BK_ERR_PWM_PERIOD_DUTY: PWM duty/period relationship is invalid
397  *    - others: other errors.
398  */
399 bk_err_t bk_pwm_group_set_config(pwm_group_t group, const pwm_group_config_t *config);
400 
401 /**
402  * @brief     Start the PWM group
403  *
404  * @param group the group ID to be started
405  *
406  * @return
407  *    - BK_OK: succeed
408  *    - BK_ERR_PWM_GROUP_NOT_EXIST: the group doesn't exist
409  *    - others: other errors.
410  */
411 bk_err_t bk_pwm_group_start(pwm_group_t group);
412 
413 /**
414  * @brief     Stop the PWM group
415  *
416  * @param group the group ID to be stopped
417  *
418  * @return
419  *    - BK_OK: succeed
420  *    - BK_ERR_PWM_GROUP_NOT_EXIST: the group doesn't exist
421  *    - others: other errors.
422  */
423 bk_err_t bk_pwm_group_stop(pwm_group_t group);
424 
425 /**
426  * @brief     Init the PWM capture
427  *
428  * The PWM capture can calculate the cycles between two different edges, currently we support
429  * following mode:
430  * 1. PWM_CAPTURE_POS - calcualte cycles between two pos-edge, the interrupt trigger in post edge
431  * 2. PWM_CAPTURE_NEG - calcualte cycles between two neg-edge, the interrupt trigger in neg edge
432  * 3. PWM_CAPTURE_EDGE - calculate cycles between two edge (pos or neg), the interrupt trigger
433  *                       in post or neg edge.
434  *
435  * Example 1 - init the capture in PWM_CAPTURE_POS mode::
436  *
437  *                     |<------ C1 ---->|<------- C2 ------->|
438  *                      ______           ___________          ________________            _
439  *      PWM input     _|      |_________|           |________|                |__________|
440  *
441  *      Capture value                   |    C1              |             C2            |
442  *
443  * @param chan the capture channel
444  * @param config the configuration of capture
445  *
446  * @return
447  *    - BK_OK: succeed
448  *    - BK_ERR_PWM_NOT_INIT: PWM driver not init
449  *    - BK_ERR_NULL_PARAM: config is NULL
450  *    - BK_ERR_PWM_CHAN_ID: invalid channel
451  *    - BK_ERR_PWM_CAPTURE_EDGE: capture edge is invalid or not supported.
452  *    - others: other errors.
453  */
454 bk_err_t bk_pwm_capture_init(pwm_chan_t chan, const pwm_capture_init_config_t *config);
455 
456 /**
457  * @brief     Deinit the PWM capture
458  *
459  * @param chan the capture channel
460  *
461  * @return
462  *    - BK_OK: succeed
463  *    - BK_ERR_PWM_NOT_INIT: PWM driver not init
464  *    - BK_ERR_PWM_CHAN_ID: invalid channel
465  *    - others: other errors.
466  */
467 bk_err_t bk_pwm_capture_deinit(pwm_chan_t chan);
468 
469 /**
470  * @brief     Start the PWM capture
471  *
472  * @param chan channel to be started
473  *
474  * @return
475  *    - BK_OK: succeed
476  *    - BK_ERR_PWM_NOT_INIT: PWM driver not init
477  *    - BK_ERR_PWM_CHAN_ID: invalid PWM channel
478  *    - others: other errors.
479  */
480 bk_err_t bk_pwm_capture_start(pwm_chan_t chan);
481 
482 /**
483  * @brief     Stop the PWM capture
484  *
485  * @param chan channel to be stopped
486  *
487  * @return
488  *    - BK_OK: succeed
489  *    - BK_ERR_PWM_NOT_INIT: PWM driver not init
490  *    - BK_ERR_PWM_CHAN_ID: invalid PWM channel
491  *    - others: other errors.
492  */
493 bk_err_t bk_pwm_capture_stop(pwm_chan_t chan);
494 
495 /**
496  * @brief     Get the capture value
497  *
498  * @attention The caller need to make sure the parameter chan is correct!
499  *
500  * @param chan PWM channel
501  *
502  * @return capture value
503  */
504 uint32_t bk_pwm_capture_get_value(pwm_chan_t chan);
505 
506 /**
507  * @brief     Set pwm channel as timer mode
508  *
509  * @attention The caller need to make sure the parameter chan is correct!
510  *
511  * @param chan PWM channel
512  *
513  * @return
514  *    - BK_OK: succeed
515  *    - BK_ERR_PWM_CHAN_ID: invalid PWM channel
516  *    - others: other errors.
517  */
518 bk_err_t bk_pwm_set_mode_timer(pwm_chan_t chan);
519 
520 
521 /**
522  * @}
523  */
524 
525 #ifdef __cplusplus
526 }
527 #endif
528