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