|
8 | 8 |
|
9 | 9 | /* |
10 | 10 | We use the GPT timers, there are 2 channels (32 bit) + 6 channels (16 bit) |
11 | | - Each channel has 2 outputs (GTIOCAx and GTIOCBx) which can be complimentary |
| 11 | + Each channel has 2 outputs (GTIOCAx and GTIOCBx) which can be complimentary. |
12 | 12 |
|
13 | | - So each timer channel can handle one half-bridge, using either a single or |
14 | | - two complimentary PWM signals. |
| 13 | + So each timer channel can handle one half-bridge, using either a single (3-PWM) or |
| 14 | + two complimentary PWM signals (6-PWM). |
15 | 15 |
|
16 | 16 | For 1-PWM through 4-PWM, we need as many channels as PWM signals, and we can use |
17 | | - either output A or B of the timer (we can set the polarity). |
| 17 | + either output A or B of the timer (we can set the polarity) - but not both. |
18 | 18 |
|
19 | 19 | For 6-PWM we need 3 channels, and use both outputs A and B of each channel, then |
20 | 20 | we can do hardware dead-time. |
21 | 21 | Or we can use seperate channels for high and low side, with software dead-time. |
| 22 | + Each phase can be either hardware (1 channel) or software (2 channels) dead-time |
| 23 | + individually, they don't all have to be one or the other. |
22 | 24 |
|
23 | 25 | Selected channels can be started together, so we can keep the phases in sync for |
24 | 26 | low-side current sensing and software 6-PWM. |
25 | 27 |
|
26 | 28 | The event system should permit low side current sensing without needing interrupts, |
27 | 29 | but this will be handled by the current sense driver. |
| 30 | +
|
| 31 | + Supported: |
| 32 | + - arbitrary PWM frequencies between 1Hz (minimum we can set with our integer based API) |
| 33 | + and around 48kHz (more would be possible but the range will be low) |
| 34 | + - PWM range at 24kHz (default) is 1000 |
| 35 | + - PWM range at 48kHz is 500 |
| 36 | + - polarity setting is supported, in all modes |
| 37 | + - phase state setting is supported, in 3-PWM, 6-PWM hardware dead-time and 6-PWM software dead-time |
| 38 | +
|
| 39 | + TODOs: |
| 40 | + - change setDutyCycle to use register access for speed |
| 41 | + - add event system support for low-side current sensing |
| 42 | + - perhaps add support to reserve timers used also in |
| 43 | + Arduino Pwm.h code, for compatibility with analogWrite() |
| 44 | + - check if there is a better way for phase-state setting |
28 | 45 | */ |
29 | 46 |
|
30 | 47 |
|
@@ -469,47 +486,102 @@ void _writeDutyCycle4PWM(float dc_1a, float dc_1b, float dc_2a, float dc_2b, vo |
469 | 486 | } |
470 | 487 |
|
471 | 488 |
|
472 | | - // TODO phase-state |
| 489 | + |
| 490 | +void _setSinglePhaseState(RenesasTimerConfig* hi, RenesasTimerConfig* lo, PhaseState state) { |
| 491 | + gpt_gtior_setting_t gtior; |
| 492 | + gtior.gtior = hi->ctrl.p_reg->GTIOR; |
| 493 | + bool on = (state==PHASE_ON) || (state==PHASE_HI); |
| 494 | + |
| 495 | + if (hi->duty_pin == GPT_IO_PIN_GTIOCA_AND_GTIOCB) { |
| 496 | + bool ch = false; |
| 497 | + if (gtior.gtior_b.obe != on) { |
| 498 | + gtior.gtior_b.obe = on; |
| 499 | + ch = true; |
| 500 | + } // B is high side |
| 501 | + on = (state==PHASE_ON) || (state==PHASE_LO); |
| 502 | + if (gtior.gtior_b.oae != on) { |
| 503 | + gtior.gtior_b.oae = on; |
| 504 | + ch = true; |
| 505 | + } |
| 506 | + if (ch) |
| 507 | + hi->ctrl.p_reg->GTIOR = gtior.gtior; |
| 508 | + return; |
| 509 | + } |
| 510 | + |
| 511 | + if (hi->duty_pin == GPT_IO_PIN_GTIOCA) { |
| 512 | + if (gtior.gtior_b.oae != on) { |
| 513 | + gtior.gtior_b.oae = on; |
| 514 | + hi->ctrl.p_reg->GTIOR = gtior.gtior; |
| 515 | + } |
| 516 | + } |
| 517 | + else if (hi->duty_pin == GPT_IO_PIN_GTIOCB) { |
| 518 | + if (gtior.gtior_b.obe != on) { |
| 519 | + gtior.gtior_b.obe = on; |
| 520 | + hi->ctrl.p_reg->GTIOR = gtior.gtior; |
| 521 | + } |
| 522 | + } |
| 523 | + |
| 524 | + gtior.gtior = lo->ctrl.p_reg->GTIOR; |
| 525 | + on = (state==PHASE_ON) || (state==PHASE_LO); |
| 526 | + if (lo->duty_pin == GPT_IO_PIN_GTIOCA) { |
| 527 | + if (gtior.gtior_b.oae != on) { |
| 528 | + gtior.gtior_b.oae = on; |
| 529 | + lo->ctrl.p_reg->GTIOR = gtior.gtior; |
| 530 | + } |
| 531 | + } |
| 532 | + else if (lo->duty_pin == GPT_IO_PIN_GTIOCB) { |
| 533 | + if (gtior.gtior_b.obe != on) { |
| 534 | + gtior.gtior_b.obe = on; |
| 535 | + lo->ctrl.p_reg->GTIOR = gtior.gtior; |
| 536 | + } |
| 537 | + } |
| 538 | + |
| 539 | +} |
| 540 | + |
| 541 | + |
473 | 542 | void _writeDutyCycle6PWM(float dc_a, float dc_b, float dc_c, PhaseState *phase_state, void* params){ |
474 | 543 | RenesasTimerConfig* t = ((RenesasHardwareDriverParams*)params)->timer_config[0]; |
| 544 | + RenesasTimerConfig* t1 = ((RenesasHardwareDriverParams*)params)->timer_config[1]; |
475 | 545 | uint32_t dt = (uint32_t)(((RenesasHardwareDriverParams*)params)->dead_zone * (float)(t->timer_cfg.period_counts)); |
476 | 546 | uint32_t duty_cycle_counts = (uint32_t)(dc_a * (float)(t->timer_cfg.period_counts)); |
477 | 547 | bool hw_deadtime = ((RenesasHardwareDriverParams*)params)->channels[0] == ((RenesasHardwareDriverParams*)params)->channels[1]; |
478 | 548 | uint32_t dt_act = (duty_cycle_counts>0 && !hw_deadtime)?dt:0; |
| 549 | + _setSinglePhaseState(t, t1, phase_state[0]); |
479 | 550 | if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts - dt_act, t->duty_pin) != FSP_SUCCESS) { |
480 | 551 | // error |
481 | 552 | } |
482 | 553 | if (!hw_deadtime) { |
483 | | - t = ((RenesasHardwareDriverParams*)params)->timer_config[1]; |
484 | | - if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts + dt_act, t->duty_pin) != FSP_SUCCESS) { |
| 554 | + if (R_GPT_DutyCycleSet(&(t1->ctrl), duty_cycle_counts + dt_act, t1->duty_pin) != FSP_SUCCESS) { |
485 | 555 | // error |
486 | 556 | } |
487 | 557 | } |
488 | 558 |
|
489 | 559 | t = ((RenesasHardwareDriverParams*)params)->timer_config[2]; |
| 560 | + t1 = ((RenesasHardwareDriverParams*)params)->timer_config[3]; |
490 | 561 | duty_cycle_counts = (uint32_t)(dc_b * (float)(t->timer_cfg.period_counts)); |
491 | 562 | hw_deadtime = ((RenesasHardwareDriverParams*)params)->channels[2] == ((RenesasHardwareDriverParams*)params)->channels[3]; |
492 | 563 | dt_act = (duty_cycle_counts>0 && !hw_deadtime)?dt:0; |
| 564 | + _setSinglePhaseState(t, t1, phase_state[1]); |
493 | 565 | if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts - dt_act, t->duty_pin) != FSP_SUCCESS) { |
494 | 566 | // error |
495 | 567 | } |
496 | 568 | if (!hw_deadtime) { |
497 | | - t = ((RenesasHardwareDriverParams*)params)->timer_config[3]; |
498 | | - if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts + dt_act, t->duty_pin) != FSP_SUCCESS) { |
| 569 | + if (R_GPT_DutyCycleSet(&(t1->ctrl), duty_cycle_counts + dt_act, t1->duty_pin) != FSP_SUCCESS) { |
499 | 570 | // error |
500 | 571 | } |
501 | 572 | } |
502 | 573 |
|
503 | 574 | t = ((RenesasHardwareDriverParams*)params)->timer_config[4]; |
| 575 | + t1 = ((RenesasHardwareDriverParams*)params)->timer_config[5]; |
504 | 576 | duty_cycle_counts = (uint32_t)(dc_c * (float)(t->timer_cfg.period_counts)); |
505 | 577 | hw_deadtime = ((RenesasHardwareDriverParams*)params)->channels[4] == ((RenesasHardwareDriverParams*)params)->channels[5]; |
506 | 578 | dt_act = (duty_cycle_counts>0 && !hw_deadtime)?dt:0; |
| 579 | + _setSinglePhaseState(t, t1, phase_state[2]); |
507 | 580 | if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts, t->duty_pin) != FSP_SUCCESS) { |
508 | 581 | // error |
509 | 582 | } |
510 | 583 | if (!hw_deadtime) { |
511 | | - t = ((RenesasHardwareDriverParams*)params)->timer_config[5]; |
512 | | - if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts + dt_act, t->duty_pin) != FSP_SUCCESS) { |
| 584 | + if (R_GPT_DutyCycleSet(&(t1->ctrl), duty_cycle_counts + dt_act, t1->duty_pin) != FSP_SUCCESS) { |
513 | 585 | // error |
514 | 586 | } |
515 | 587 | } |
|
0 commit comments