|
16 | 16 | #if !defined(BSP_USING_PWM1_CH0) && !defined(BSP_USING_PWM1_CH1) && !defined(BSP_USING_PWM1_CH2) && !defined(BSP_USING_PWM1_CH3) && \ |
17 | 17 | !defined(BSP_USING_PWM2_CH0) && !defined(BSP_USING_PWM2_CH1) && !defined(BSP_USING_PWM2_CH2) && !defined(BSP_USING_PWM2_CH3) && \ |
18 | 18 | !defined(BSP_USING_PWM3_CH0) && !defined(BSP_USING_PWM3_CH1) && !defined(BSP_USING_PWM3_CH2) && !defined(BSP_USING_PWM3_CH3) && \ |
19 | | - !defined(BSP_USING_PWM4_CH0) && !defined(BSP_USING_PWM4_CH1) && !defined(BSP_USING_PWM4_CH2) && !defined(BSP_USING_PWM4_CH3) |
20 | | -#error "Please define at least one BSP_USING_PWMx_CHx" |
| 19 | + !defined(BSP_USING_PWM4_CH0) && !defined(BSP_USING_PWM4_CH1) && !defined(BSP_USING_PWM4_CH2) && !defined(BSP_USING_PWM4_CH3) && \ |
| 20 | + !defined(BSP_USING_QTMR1_CH0) && !defined(BSP_USING_QTMR1_CH1) && !defined(BSP_USING_QTMR1_CH2) && !defined(BSP_USING_QTMR1_CH3) && \ |
| 21 | + !defined(BSP_USING_QTMR2_CH0) && !defined(BSP_USING_QTMR2_CH1) && !defined(BSP_USING_QTMR2_CH2) && !defined(BSP_USING_QTMR2_CH3) && \ |
| 22 | + !defined(BSP_USING_QTMR3_CH0) && !defined(BSP_USING_QTMR3_CH1) && !defined(BSP_USING_QTMR3_CH2) && !defined(BSP_USING_QTMR3_CH3) && \ |
| 23 | + !defined(BSP_USING_QTMR4_CH0) && !defined(BSP_USING_QTMR4_CH1) && !defined(BSP_USING_QTMR4_CH2) && !defined(BSP_USING_QTMR4_CH3) |
| 24 | +#error "Please define at least one BSP_USING_PWMx_CHx or BSP_USING_QTMRx_CHx" |
21 | 25 | #endif |
22 | 26 |
|
23 | 27 | #define LOG_TAG "drv.pwm" |
24 | 28 | #include <drv_log.h> |
25 | 29 |
|
26 | 30 | #include <rtdevice.h> |
27 | 31 | #include "fsl_pwm.h" |
| 32 | +#if defined(FSL_FEATURE_SOC_TMR_COUNT) && FSL_FEATURE_SOC_TMR_COUNT > 0 |
| 33 | + #include "fsl_qtmr.h" |
| 34 | +#endif |
28 | 35 | #include "drv_pwm.h" |
29 | 36 |
|
30 | 37 | #define DEFAULT_PRE 5 |
@@ -317,6 +324,224 @@ static rt_err_t imxrt_pwm4_init(PWM_Type *base) |
317 | 324 |
|
318 | 325 | #endif /* BSP_USING_PWM4 */ |
319 | 326 |
|
| 327 | +static rt_err_t imxrt_drv_qtmr_control(struct rt_device_pwm *device, int cmd, void *arg); |
| 328 | + |
| 329 | +static struct rt_pwm_ops imxrt_drv_qtmr_ops = |
| 330 | +{ |
| 331 | + .control = imxrt_drv_qtmr_control |
| 332 | +}; |
| 333 | + |
| 334 | +static rt_err_t imxrt_drv_qtmr_enable(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration, rt_bool_t enable) |
| 335 | +{ |
| 336 | + TMR_Type *base; |
| 337 | + base = (TMR_Type *)device->parent.user_data; |
| 338 | + |
| 339 | + if (!enable) |
| 340 | + { |
| 341 | + QTMR_StopTimer(base, configuration->channel); |
| 342 | + base->CHANNEL[configuration->channel].SCTRL |= (TMR_SCTRL_FORCE_MASK | TMR_SCTRL_OEN_MASK); |
| 343 | + } |
| 344 | + else |
| 345 | + { |
| 346 | + QTMR_StartTimer(base, configuration->channel, kQTMR_PriSrcRiseEdge); |
| 347 | + } |
| 348 | + |
| 349 | + return RT_EOK; |
| 350 | +} |
| 351 | + |
| 352 | +static rt_err_t imxrt_drv_qtmr_get(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration) |
| 353 | +{ |
| 354 | + TMR_Type *base; |
| 355 | + rt_uint32_t high_count, low_count, clk_divider, clk_freq; |
| 356 | + |
| 357 | + base = (TMR_Type *)device->parent.user_data; |
| 358 | + |
| 359 | + low_count = base->CHANNEL[configuration->channel].COMP1; |
| 360 | + high_count = base->CHANNEL[configuration->channel].COMP2; |
| 361 | + clk_divider = 1 << (((base->CHANNEL[configuration->channel].CTRL & TMR_CTRL_PCS_MASK) >> TMR_CTRL_PCS_SHIFT) - 8); |
| 362 | + clk_freq = CLOCK_GetFreq(kCLOCK_IpgClk) / clk_divider; |
| 363 | + |
| 364 | + configuration->period = 1000000000 / clk_freq * (high_count + low_count); |
| 365 | + configuration->pulse = 1000000000 / clk_freq * high_count; |
| 366 | + |
| 367 | + return RT_EOK; |
| 368 | +} |
| 369 | + |
| 370 | +static rt_err_t imxrt_drv_qtmr_set(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration) |
| 371 | +{ |
| 372 | + RT_ASSERT(configuration->period > 0); |
| 373 | + RT_ASSERT(configuration->pulse <= configuration->period); |
| 374 | + |
| 375 | + TMR_Type *base = (TMR_Type *)device->parent.user_data; |
| 376 | + |
| 377 | + rt_size_t clk_freq = CLOCK_GetFreq(kCLOCK_IpgClk) / (1 << (((base->CHANNEL[configuration->channel].CTRL & TMR_CTRL_PCS_MASK) >> TMR_CTRL_PCS_SHIFT) - 8)); |
| 378 | + rt_size_t current_period_count = base->CHANNEL[configuration->channel].CMPLD1 + base->CHANNEL[configuration->channel].CMPLD2; |
| 379 | + rt_size_t period_count = clk_freq / (1000000000 / configuration->period); |
| 380 | + if (current_period_count == period_count) |
| 381 | + { |
| 382 | + rt_size_t high_count = period_count * configuration->pulse / configuration->period; |
| 383 | + rt_size_t low_count = period_count - high_count; |
| 384 | + base->CHANNEL[configuration->channel].CMPLD1 = (uint16_t)low_count; |
| 385 | + base->CHANNEL[configuration->channel].CMPLD2 = (uint16_t)high_count; |
| 386 | + } |
| 387 | + else |
| 388 | + { |
| 389 | + rt_bool_t timer_is_on = base->CHANNEL[configuration->channel].CTRL & TMR_CTRL_CM_MASK; |
| 390 | + rt_uint8_t duty = configuration->pulse * 100 / configuration->period; |
| 391 | + QTMR_StopTimer(base, configuration->channel); |
| 392 | + if (kStatus_Success != QTMR_SetupPwm(base, configuration->channel, 1000000000 / configuration->period, duty, DEFAULT_POLARITY, clk_freq)) |
| 393 | + { |
| 394 | + LOG_E(LOG_TAG" setup pwm failed \n"); |
| 395 | + return RT_ERROR; |
| 396 | + } |
| 397 | + if (timer_is_on) |
| 398 | + { |
| 399 | + QTMR_StartTimer(base, configuration->channel, kQTMR_PriSrcRiseEdge); |
| 400 | + } |
| 401 | + } |
| 402 | + |
| 403 | + return RT_EOK; |
| 404 | +} |
| 405 | + |
| 406 | +static rt_err_t imxrt_drv_qtmr_control(struct rt_device_pwm *device, int cmd, void *arg) |
| 407 | +{ |
| 408 | + struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg; |
| 409 | + |
| 410 | + switch (cmd) |
| 411 | + { |
| 412 | + case PWM_CMD_ENABLE: |
| 413 | + return imxrt_drv_qtmr_enable(device, configuration, RT_TRUE); |
| 414 | + case PWM_CMD_DISABLE: |
| 415 | + return imxrt_drv_qtmr_enable(device, configuration, RT_FALSE); |
| 416 | + case PWM_CMD_SET: |
| 417 | + return imxrt_drv_qtmr_set(device, configuration); |
| 418 | + case PWM_CMD_GET: |
| 419 | + return imxrt_drv_qtmr_get(device, configuration); |
| 420 | + default: |
| 421 | + return RT_EINVAL; |
| 422 | + } |
| 423 | +} |
| 424 | + |
| 425 | +static rt_err_t imxrt_drv_qtmr_init(TMR_Type *base, qtmr_channel_selection_t channel, uint16_t psc, uint32_t fre, uint8_t duty) |
| 426 | +{ |
| 427 | + qtmr_config_t qtmr_config; |
| 428 | + rt_uint32_t qtmr_clock_freq; |
| 429 | + QTMR_GetDefaultConfig(&qtmr_config); |
| 430 | + |
| 431 | + qtmr_config.primarySource = (qtmr_primary_count_source_t)(psc + 8); |
| 432 | + qtmr_clock_freq = CLOCK_GetFreq(kCLOCK_IpgClk) / (1 << psc); |
| 433 | + |
| 434 | + QTMR_Init(base, channel, &qtmr_config); |
| 435 | + |
| 436 | + if (kStatus_Success != QTMR_SetupPwm(base, channel, fre, duty, DEFAULT_POLARITY, qtmr_clock_freq)) |
| 437 | + { |
| 438 | + LOG_E(LOG_TAG" setup pwm failed \n"); |
| 439 | + return RT_ERROR; |
| 440 | + } |
| 441 | + |
| 442 | + return RT_EOK; |
| 443 | +} |
| 444 | + |
| 445 | +static rt_err_t imxrt_qtmr_init() |
| 446 | +{ |
| 447 | + TMR_Type *base_list[] = |
| 448 | + { |
| 449 | +#ifdef BSP_USING_QTMR1 |
| 450 | + TMR1, |
| 451 | +#endif |
| 452 | +#ifdef BSP_USING_QTMR2 |
| 453 | + TMR2, |
| 454 | +#endif |
| 455 | +#ifdef BSP_USING_QTMR3 |
| 456 | + TMR3, |
| 457 | +#endif |
| 458 | +#ifdef BSP_USING_QTMR4 |
| 459 | + TMR4, |
| 460 | +#endif |
| 461 | + }; |
| 462 | + |
| 463 | + rt_uint8_t channel_list[] = |
| 464 | + { |
| 465 | +#ifdef BSP_USING_QTMR1 |
| 466 | +#ifdef BSP_USING_QTMR1_CH0 |
| 467 | + 1 << 0 | |
| 468 | +#endif |
| 469 | +#ifdef BSP_USING_QTMR1_CH1 |
| 470 | + 1 << 1 | |
| 471 | +#endif |
| 472 | +#ifdef BSP_USING_QTMR1_CH2 |
| 473 | + 1 << 2 | |
| 474 | +#endif |
| 475 | +#ifdef BSP_USING_QTMR1_CH3 |
| 476 | + 1 << 3 | |
| 477 | +#endif |
| 478 | + 0, |
| 479 | +#endif |
| 480 | +#ifdef BSP_USING_QTMR2 |
| 481 | +#ifdef BSP_USING_QTMR2_CH0 |
| 482 | + 1 << 0 | |
| 483 | +#endif |
| 484 | +#ifdef BSP_USING_QTMR2_CH1 |
| 485 | + 1 << 1 | |
| 486 | +#endif |
| 487 | +#ifdef BSP_USING_QTMR2_CH2 |
| 488 | + 1 << 2 | |
| 489 | +#endif |
| 490 | +#ifdef BSP_USING_QTMR2_CH3 |
| 491 | + 1 << 3 | |
| 492 | +#endif |
| 493 | + 0, |
| 494 | +#endif |
| 495 | +#ifdef BSP_USING_QTMR3 |
| 496 | +#ifdef BSP_USING_QTMR3_CH0 |
| 497 | + 1 << 0 | |
| 498 | +#endif |
| 499 | +#ifdef BSP_USING_QTMR3_CH1 |
| 500 | + 1 << 1 | |
| 501 | +#endif |
| 502 | +#ifdef BSP_USING_QTMR3_CH2 |
| 503 | + 1 << 2 | |
| 504 | +#endif |
| 505 | +#ifdef BSP_USING_QTMR3_CH3 |
| 506 | + 1 << 3 | |
| 507 | +#endif |
| 508 | + 0, |
| 509 | +#endif |
| 510 | +#ifdef BSP_USING_QTMR4 |
| 511 | +#ifdef BSP_USING_QTMR4_CH0 |
| 512 | + 1 << 0 | |
| 513 | +#endif |
| 514 | +#ifdef BSP_USING_QTMR4_CH1 |
| 515 | + 1 << 1 | |
| 516 | +#endif |
| 517 | +#ifdef BSP_USING_QTMR4_CH2 |
| 518 | + 1 << 2 | |
| 519 | +#endif |
| 520 | +#ifdef BSP_USING_QTMR4_CH3 |
| 521 | + 1 << 3 | |
| 522 | +#endif |
| 523 | + 0, |
| 524 | +#endif |
| 525 | + }; |
| 526 | + |
| 527 | + for (rt_uint8_t i = 0; i < sizeof(base_list)/sizeof(TMR_Type *); ++i) |
| 528 | + { |
| 529 | + for (rt_uint8_t j = 0; j < 8; ++j) |
| 530 | + { |
| 531 | + if ((channel_list[i] >> j) & 1) |
| 532 | + { |
| 533 | + if (imxrt_drv_qtmr_init(base_list[i], j, DEFAULT_PRE, DEFAULT_FRE, DEFAULT_DUTY) != RT_EOK) |
| 534 | + { |
| 535 | + return -RT_ERROR; |
| 536 | + } |
| 537 | + } |
| 538 | + } |
| 539 | + } |
| 540 | + return RT_EOK; |
| 541 | +} |
| 542 | + |
| 543 | + |
| 544 | + |
320 | 545 | int rt_hw_pwm_init(void) |
321 | 546 | { |
322 | 547 | rt_err_t ret = RT_EOK; |
@@ -391,9 +616,52 @@ int rt_hw_pwm_init(void) |
391 | 616 | } |
392 | 617 | #endif /* BSP_USING_PWM4 */ |
393 | 618 |
|
| 619 | +#if defined(BSP_USING_QTMR1) || defined(BSP_USING_QTMR2) || defined(BSP_USING_QTMR3) || defined(BSP_USING_QTMR4) |
| 620 | + if (imxrt_qtmr_init() != RT_EOK) |
| 621 | + { |
| 622 | + LOG_E(LOG_TAG" init qtmr failed"); |
| 623 | + } |
| 624 | +#endif |
| 625 | + |
| 626 | +#ifdef BSP_USING_QTMR1 |
| 627 | + static struct rt_device_pwm qtmr1_device; |
| 628 | + ret = rt_device_pwm_register(&qtmr1_device, "pwm5", &imxrt_drv_qtmr_ops, TMR1); |
| 629 | + if (ret != RT_EOK) |
| 630 | + { |
| 631 | + LOG_E("%s register failed", "pwm5"); |
| 632 | + } |
| 633 | +#endif /* BSP_USING_QTMR1 */ |
| 634 | + |
| 635 | +#ifdef BSP_USING_QTMR2 |
| 636 | + static struct rt_device_pwm qtmr2_device; |
| 637 | + ret = rt_device_pwm_register(&qtmr2_device, "pwm6", &imxrt_drv_qtmr_ops, TMR2); |
| 638 | + if (ret != RT_EOK) |
| 639 | + { |
| 640 | + LOG_E("%s register failed", "pwm6"); |
| 641 | + } |
| 642 | +#endif /* BSP_USING_QTMR2 */ |
| 643 | + |
| 644 | +#ifdef BSP_USING_QTMR3 |
| 645 | + static struct rt_device_pwm qtmr3_device; |
| 646 | + ret = rt_device_pwm_register(&qtmr3_device, "pwm7", &imxrt_drv_qtmr_ops, TMR3); |
| 647 | + if (ret != RT_EOK) |
| 648 | + { |
| 649 | + LOG_E("%s register failed", "pwm7"); |
| 650 | + } |
| 651 | +#endif /* BSP_USING_QTMR3 */ |
| 652 | + |
| 653 | +#ifdef BSP_USING_QTMR4 |
| 654 | + static struct rt_device_pwm qtmr4_device; |
| 655 | + ret = rt_device_pwm_register(&qtmr4_device, "pwm8", &imxrt_drv_qtmr_ops, TMR4); |
| 656 | + if (ret != RT_EOK) |
| 657 | + { |
| 658 | + LOG_E("%s register failed", "pwm8"); |
| 659 | + } |
| 660 | +#endif /* BSP_USING_QTMR4 */ |
| 661 | + |
394 | 662 | return ret; |
395 | 663 | } |
396 | 664 |
|
397 | | -INIT_DEVICE_EXPORT(rt_hw_pwm_init); |
| 665 | +INIT_BOARD_EXPORT(rt_hw_pwm_init); |
398 | 666 |
|
399 | 667 | #endif /* BSP_USING_PWM */ |
0 commit comments