|
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