#include "./renesas.h" #if defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_UNOR4_MINIMA) #pragma message("") #pragma message("SimpleFOC: compiling for Arduino/Renesas (UNO R4)") #pragma message("") #include "communication/SimpleFOCDebug.h" #include "FspTimer.h" #define GPT_OPEN (0x00475054ULL) /* We use the GPT timers, there are 2 channels (32 bit) + 6 channels (16 bit) Each channel has 2 outputs (GTIOCAx and GTIOCBx) which can be complimentary. So each timer channel can handle one half-bridge, using either a single (3-PWM) or two complimentary PWM signals (6-PWM). For 1-PWM through 4-PWM, we need as many channels as PWM signals, and we can use either output A or B of the timer (we can set the polarity) - but not both. For 6-PWM we need 3 channels, and use both outputs A and B of each channel, then we can do hardware dead-time. Or we can use seperate channels for high and low side, with software dead-time. Each phase can be either hardware (1 channel) or software (2 channels) dead-time individually, they don't all have to be one or the other. Selected channels can be started together, so we can keep the phases in sync for low-side current sensing and software 6-PWM. The event system should permit low side current sensing without needing interrupts, but this will be handled by the current sense driver. Supported: - arbitrary PWM frequencies between 1Hz (minimum we can set with our integer based API) and around 48kHz (more would be possible but the range will be low) - PWM range at 24kHz (default) is 1000 - PWM range at 48kHz is 500 - polarity setting is supported, in all modes - phase state setting is supported, in 3-PWM, 6-PWM hardware dead-time and 6-PWM software dead-time TODOs: - change setDutyCycle to use register access for speed - add event system support for low-side current sensing - perhaps add support to reserve timers used also in Arduino Pwm.h code, for compatibility with analogWrite() - check if there is a better way for phase-state setting */ // track which channels are used bool channel_used[GPT_HOWMANY] = { false }; struct RenesasTimerConfig { timer_cfg_t timer_cfg; gpt_instance_ctrl_t ctrl; gpt_extended_cfg_t ext_cfg; gpt_extended_pwm_cfg_t pwm_cfg; gpt_io_pin_t duty_pin; }; struct ClockDivAndRange { timer_source_div_t clk_div; uint32_t range; }; ClockDivAndRange getClockDivAndRange(uint32_t pwm_frequency, uint8_t timer_channel) { ClockDivAndRange result; uint32_t max_count = (timer_channel < GTP32_HOWMANY)? 4294967295 : 65535; uint32_t freq_hz = R_FSP_SystemClockHzGet(FSP_PRIV_CLOCK_PCLKD); float range = (float) freq_hz / ((float) pwm_frequency * 2.0f); if(range / 1.0 < max_count) { result.range = (uint32_t) (range / 1.0); result.clk_div = TIMER_SOURCE_DIV_1; } else if (range / 2.0 < max_count) { result.range = (uint32_t) (range / 2.0); result.clk_div = TIMER_SOURCE_DIV_2; } else if(range / 4.0 < max_count) { result.range = (uint32_t) (range / 4.0); result.clk_div = TIMER_SOURCE_DIV_4; } else if(range / 8.0 < max_count) { result.range = (uint32_t) (range / 8.0 ); result.clk_div = TIMER_SOURCE_DIV_8; } else if(range / 16.0 < max_count) { result.range = (uint32_t) (range / 16.0 ); result.clk_div = TIMER_SOURCE_DIV_16; } else if (range / 32.0 < max_count) { result.range = (uint32_t) (range / 32.0 ); result.clk_div = TIMER_SOURCE_DIV_32; } else if(range / 64.0 < max_count) { result.range = (uint32_t) (range / 64.0 ); result.clk_div = TIMER_SOURCE_DIV_64; } else if(range / 128.0 < max_count) { result.range = (uint32_t) (range / 128.0 ); result.clk_div = TIMER_SOURCE_DIV_128; } else if(range / 256.0 < max_count) { result.range = (uint32_t) (range / 256.0 ); result.clk_div = TIMER_SOURCE_DIV_256; } else if(range / 512.0 < max_count) { result.range = (uint32_t) (range / 512.0 ); result.clk_div = TIMER_SOURCE_DIV_512; } else if(range / 1024.0 < max_count) { result.range = (uint32_t) (range / 1024.0 ); result.clk_div = TIMER_SOURCE_DIV_1024; } else { SimpleFOCDebug::println("DRV: PWM frequency too low"); } return result; }; bool configureTimerPin(RenesasHardwareDriverParams* params, uint8_t index, bool active_high, bool complementary = false, bool complementary_active_high = true) { uint8_t pin = params->pins[index]; uint8_t pin_C; std::array pinCfgs = getPinCfgs(pin, PIN_CFG_REQ_PWM); std::array pinCfgs_C; if(pinCfgs[0] == 0) { SIMPLEFOC_DEBUG("DRV: no PWM on pin ", pin); return false; } if (IS_PIN_AGT_PWM(pinCfgs[0])) { SIMPLEFOC_DEBUG("DRV: AGT timer not supported"); return false; } // get the timer channel uint8_t timer_channel = GET_CHANNEL(pinCfgs[0]); // check its not used if (channel_used[timer_channel]) { SIMPLEFOC_DEBUG("DRV: channel in use"); return false; } if (complementary) { pin_C = params->pins[index+1]; pinCfgs_C = getPinCfgs(pin_C, PIN_CFG_REQ_PWM); if(pinCfgs_C[0] == 0) { SIMPLEFOC_DEBUG("DRV: no PWM on pin ", pin_C); return false; } if (IS_PIN_AGT_PWM(pinCfgs_C[0]) || GET_CHANNEL(pinCfgs_C[0])!=timer_channel) { SIMPLEFOC_DEBUG("DRV: comp. channel different"); return false; } } TimerPWMChannel_t pwm_output = IS_PWM_ON_A(pinCfgs[0]) ? CHANNEL_A : CHANNEL_B; if (complementary) { TimerPWMChannel_t pwm_output_C = IS_PWM_ON_A(pinCfgs_C[0]) ? CHANNEL_A : CHANNEL_B; if (pwm_output_C != CHANNEL_A || pwm_output != CHANNEL_B) { SIMPLEFOC_DEBUG("DRV: output A/B mismatch"); return false; } } // configure GPIO pin fsp_err_t err = R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[pin].pin, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | IOPORT_PERIPHERAL_GPT1)); if ((err == FSP_SUCCESS) && complementary) err = R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[pin_C].pin, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | IOPORT_PERIPHERAL_GPT1)); if (err != FSP_SUCCESS) { SIMPLEFOC_DEBUG("DRV: pin config failed"); return false; } // configure timer channel - frequency / top value ClockDivAndRange timings = getClockDivAndRange(params->pwm_frequency, timer_channel); #if defined(SIMPLEFOC_RENESAS_DEBUG) SimpleFOCDebug::println("---PWM Config---"); SimpleFOCDebug::println("DRV: pwm pin: ", pin); if (complementary) SimpleFOCDebug::println("DRV: compl. pin: ", pin_C); SimpleFOCDebug::println("DRV: pwm channel: ", timer_channel); SimpleFOCDebug::print("DRV: pwm A/B: "); SimpleFOCDebug::println(complementary?"A+B":((pwm_output==CHANNEL_A)?"A":"B")); SimpleFOCDebug::println("DRV: pwm freq: ", (int)params->pwm_frequency); SimpleFOCDebug::println("DRV: pwm range: ", (int)timings.range); SimpleFOCDebug::println("DRV: pwm clkdiv: ", timings.clk_div); #endif RenesasTimerConfig* t = new RenesasTimerConfig(); // configure timer channel - count mode t->timer_cfg.channel = timer_channel; t->timer_cfg.mode = TIMER_MODE_TRIANGLE_WAVE_SYMMETRIC_PWM; t->timer_cfg.source_div = timings.clk_div; t->timer_cfg.period_counts = timings.range; t->timer_cfg.duty_cycle_counts = 0; t->timer_cfg.p_callback = nullptr; t->timer_cfg.p_context = nullptr; t->timer_cfg.p_extend = &(t->ext_cfg); t->timer_cfg.cycle_end_ipl = BSP_IRQ_DISABLED; t->timer_cfg.cycle_end_irq = FSP_INVALID_VECTOR; t->ext_cfg.p_pwm_cfg = &(t->pwm_cfg); t->pwm_cfg.trough_ipl = BSP_IRQ_DISABLED; t->pwm_cfg.trough_irq = FSP_INVALID_VECTOR; t->pwm_cfg.poeg_link = GPT_POEG_LINK_POEG0; t->pwm_cfg.output_disable = GPT_OUTPUT_DISABLE_NONE; t->pwm_cfg.adc_trigger = GPT_ADC_TRIGGER_NONE; t->pwm_cfg.dead_time_count_up = 0; t->pwm_cfg.dead_time_count_down = 0; t->pwm_cfg.adc_a_compare_match = 0; t->pwm_cfg.adc_b_compare_match = 0; t->pwm_cfg.interrupt_skip_source = GPT_INTERRUPT_SKIP_SOURCE_NONE; t->pwm_cfg.interrupt_skip_count = GPT_INTERRUPT_SKIP_COUNT_0; t->pwm_cfg.interrupt_skip_adc = GPT_INTERRUPT_SKIP_ADC_NONE; t->pwm_cfg.gtioca_disable_setting = GPT_GTIOC_DISABLE_PROHIBITED; t->pwm_cfg.gtiocb_disable_setting = GPT_GTIOC_DISABLE_PROHIBITED; // configure dead-time if both outputs are used if (complementary) { uint32_t dt = params->dead_zone * timings.range; t->pwm_cfg.dead_time_count_up = dt; t->pwm_cfg.dead_time_count_down = dt; } // configure timer channel - outputs and polarity t->ext_cfg.gtior_setting.gtior = 0L; if (!complementary) { if(pwm_output == CHANNEL_A) { t->duty_pin = GPT_IO_PIN_GTIOCA; t->ext_cfg.gtioca.output_enabled = true; t->ext_cfg.gtiocb.output_enabled = false; t->ext_cfg.gtior_setting.gtior_b.gtioa = 0x03 | (active_high ? 0x00 : 0x10); t->ext_cfg.gtior_setting.gtior_b.oadflt = active_high ? 0x00 : 0x01; // t->ext_cfg.gtior_setting.gtior_b.oahld = 0x0; // t->ext_cfg.gtior_setting.gtior_b.oadf = 0x0; // t->ext_cfg.gtior_setting.gtior_b.nfaen = 0x0; } else { t->duty_pin = GPT_IO_PIN_GTIOCB; t->ext_cfg.gtiocb.output_enabled = true; t->ext_cfg.gtioca.output_enabled = false; t->ext_cfg.gtior_setting.gtior_b.gtiob = 0x03 | (active_high ? 0x00 : 0x10); t->ext_cfg.gtior_setting.gtior_b.obdflt = active_high ? 0x00 : 0x01; } } else { t->duty_pin = GPT_IO_PIN_GTIOCA_AND_GTIOCB; t->ext_cfg.gtioca.output_enabled = true; t->ext_cfg.gtiocb.output_enabled = true; t->ext_cfg.gtior_setting.gtior_b.gtioa = 0x03 | (!complementary_active_high ? 0x00 : 0x10); t->ext_cfg.gtior_setting.gtior_b.oadflt = !complementary_active_high ? 0x00 : 0x01; t->ext_cfg.gtior_setting.gtior_b.gtiob = 0x03 | (active_high ? 0x00 : 0x10); t->ext_cfg.gtior_setting.gtior_b.obdflt = active_high ? 0x00 : 0x01; } // lets stop the timer in case its running if (GPT_OPEN == t->ctrl.open) { if (R_GPT_Stop(&(t->ctrl)) != FSP_SUCCESS) { SIMPLEFOC_DEBUG("DRV: timer stop failed"); return false; } } memset(&(t->ctrl), 0, sizeof(gpt_instance_ctrl_t)); err = R_GPT_Open(&(t->ctrl),&(t->timer_cfg)); if ((err != FSP_ERR_ALREADY_OPEN) && (err != FSP_SUCCESS)) { SIMPLEFOC_DEBUG("DRV: open failed"); return false; } #if defined(SIMPLEFOC_RESENSAS_DEBUG) if (err == FSP_ERR_ALREADY_OPEN) { SimpleFOCDebug::println("DRV: timer already open"); } #endif err = R_GPT_PeriodSet(&(t->ctrl), t->timer_cfg.period_counts); if (err != FSP_SUCCESS) { SIMPLEFOC_DEBUG("DRV: period set failed"); return false; } err = R_GPT_OutputEnable(&(t->ctrl), t->duty_pin); if (err != FSP_SUCCESS) { SIMPLEFOC_DEBUG("DRV: pin enable failed"); return false; } channel_used[timer_channel] = true; params->timer_config[index] = t; params->channels[index] = timer_channel; if (complementary) { params->timer_config[index+1] = t; params->channels[index+1] = timer_channel; } return true; } // start the timer channels for the motor, synchronously bool startTimerChannels(RenesasHardwareDriverParams* params, int num_channels) { uint32_t mask = 0; for (int i = 0; i < num_channels; i++) { // RenesasTimerConfig* t = params->timer_config[i]; // if (R_GPT_Start(&(t->ctrl)) != FSP_SUCCESS) { // SIMPLEFOC_DEBUG("DRV: timer start failed"); // return false; // } mask |= (1 << params->channels[i]); #if defined(SIMPLEFOC_RENESAS_DEBUG) SimpleFOCDebug::println("DRV: starting timer: ", params->channels[i]); #endif } params->timer_config[0]->ctrl.p_reg->GTSTR |= mask; #if defined(SIMPLEFOC_RENESAS_DEBUG) SimpleFOCDebug::println("DRV: timers started"); #endif return true; } // check if the given pins are on the same timer channel bool isHardware6Pwm(const int pin1, const int pin2) { std::array pinCfgs1 = getPinCfgs(pin1, PIN_CFG_REQ_PWM); std::array pinCfgs2 = getPinCfgs(pin2, PIN_CFG_REQ_PWM); if(pinCfgs1[0] == 0 || pinCfgs2[0] == 0) return false; if (IS_PIN_AGT_PWM(pinCfgs1[0]) || IS_PIN_AGT_PWM(pinCfgs2[0])) return false; uint8_t timer_channel1 = GET_CHANNEL(pinCfgs1[0]); uint8_t timer_channel2 = GET_CHANNEL(pinCfgs2[0]); return timer_channel1==timer_channel2; } void* _configure1PWM(long pwm_frequency, const int pinA) { RenesasHardwareDriverParams* params = new RenesasHardwareDriverParams; params->pins[0] = pinA; params->pwm_frequency = (pwm_frequency==NOT_SET)?RENESAS_DEFAULT_PWM_FREQUENCY:pwm_frequency; bool success = true; success = configureTimerPin(params, 0, SIMPLEFOC_PWM_ACTIVE_HIGH); if (success) success = startTimerChannels(params, 1); if (!success) return SIMPLEFOC_DRIVER_INIT_FAILED; return params; } void* _configure2PWM(long pwm_frequency,const int pinA, const int pinB) { RenesasHardwareDriverParams* params = new RenesasHardwareDriverParams; params->pins[0] = pinA; params->pins[1] = pinB; params->pwm_frequency = (pwm_frequency==NOT_SET)?RENESAS_DEFAULT_PWM_FREQUENCY:pwm_frequency; bool success = true; success = configureTimerPin(params, 0, SIMPLEFOC_PWM_ACTIVE_HIGH); success &= configureTimerPin(params, 1, SIMPLEFOC_PWM_ACTIVE_HIGH); if (!success) success &= startTimerChannels(params, 2); if (!success) return SIMPLEFOC_DRIVER_INIT_FAILED; return params; } void* _configure3PWM(long pwm_frequency,const int pinA, const int pinB, const int pinC) { RenesasHardwareDriverParams* params = new RenesasHardwareDriverParams; params->pins[0] = pinA; params->pins[1] = pinB; params->pins[2] = pinC; params->pwm_frequency = (pwm_frequency==NOT_SET)?RENESAS_DEFAULT_PWM_FREQUENCY:pwm_frequency; bool success = true; success = configureTimerPin(params, 0, SIMPLEFOC_PWM_ACTIVE_HIGH); success &= configureTimerPin(params, 1, SIMPLEFOC_PWM_ACTIVE_HIGH); success &= configureTimerPin(params, 2, SIMPLEFOC_PWM_ACTIVE_HIGH); if (success) success = startTimerChannels(params, 3); if (!success) return SIMPLEFOC_DRIVER_INIT_FAILED; return params; } void* _configure4PWM(long pwm_frequency, const int pin1A, const int pin1B, const int pin2A, const int pin2B) { RenesasHardwareDriverParams* params = new RenesasHardwareDriverParams; params->pins[0] = pin1A; params->pins[1] = pin1B; params->pins[2] = pin2A; params->pins[3] = pin2B; params->pwm_frequency = (pwm_frequency==NOT_SET)?RENESAS_DEFAULT_PWM_FREQUENCY:pwm_frequency; bool success = true; success = configureTimerPin(params, 0, SIMPLEFOC_PWM_ACTIVE_HIGH); success &= configureTimerPin(params, 1, SIMPLEFOC_PWM_ACTIVE_HIGH); success &= configureTimerPin(params, 2, SIMPLEFOC_PWM_ACTIVE_HIGH); success &= configureTimerPin(params, 3, SIMPLEFOC_PWM_ACTIVE_HIGH); if (success) success = startTimerChannels(params, 4); if (!success) return SIMPLEFOC_DRIVER_INIT_FAILED; return params; } void* _configure6PWM(long pwm_frequency, float dead_zone, const int pinA_h, const int pinA_l, const int pinB_h, const int pinB_l, const int pinC_h, const int pinC_l){ RenesasHardwareDriverParams* params = new RenesasHardwareDriverParams; params->pins[0] = pinA_h; params->pins[1] = pinA_l; params->pins[2] = pinB_h; params->pins[3] = pinB_l; params->pins[4] = pinC_h; params->pins[5] = pinC_l; params->pwm_frequency = (pwm_frequency==NOT_SET)?RENESAS_DEFAULT_PWM_FREQUENCY:pwm_frequency; params->dead_zone = (dead_zone==NOT_SET)?RENESAS_DEFAULT_DEAD_ZONE:dead_zone; bool success = true; if (isHardware6Pwm(pinA_h, pinA_l)) success &= configureTimerPin(params, 0, SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH, true, SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH); else { success &= configureTimerPin(params, 0, SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH); success &= configureTimerPin(params, 1, !SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH); // reverse polarity on low side gives desired active high/low behaviour } if (isHardware6Pwm(pinB_h, pinB_l)) success &= configureTimerPin(params, 2, SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH, true, SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH); else { success &= configureTimerPin(params, 2, SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH); success &= configureTimerPin(params, 3, !SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH); } if (isHardware6Pwm(pinC_h, pinC_l)) success &= configureTimerPin(params, 4, SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH, true, SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH); else { success &= configureTimerPin(params, 4, SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH); success &= configureTimerPin(params, 5, !SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH); } if (success) success = startTimerChannels(params, 6); if (!success) return SIMPLEFOC_DRIVER_INIT_FAILED; return params; } void _writeDutyCycle1PWM(float dc_a, void* params){ RenesasTimerConfig* t = ((RenesasHardwareDriverParams*)params)->timer_config[0]; uint32_t duty_cycle_counts = (uint32_t)(dc_a * (float)(t->timer_cfg.period_counts)); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts, t->duty_pin) != FSP_SUCCESS) { // error } } void _writeDutyCycle2PWM(float dc_a, float dc_b, void* params){ RenesasTimerConfig* t = ((RenesasHardwareDriverParams*)params)->timer_config[0]; uint32_t duty_cycle_counts = (uint32_t)(dc_a * (float)(t->timer_cfg.period_counts)); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts, t->duty_pin) != FSP_SUCCESS) { // error } t = ((RenesasHardwareDriverParams*)params)->timer_config[1]; duty_cycle_counts = (uint32_t)(dc_b * (float)(t->timer_cfg.period_counts)); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts, t->duty_pin) != FSP_SUCCESS) { // error } } void _writeDutyCycle3PWM(float dc_a, float dc_b, float dc_c, void* params){ RenesasTimerConfig* t = ((RenesasHardwareDriverParams*)params)->timer_config[0]; uint32_t duty_cycle_counts = (uint32_t)(dc_a * (float)(t->timer_cfg.period_counts)); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts, t->duty_pin) != FSP_SUCCESS) { // error } t = ((RenesasHardwareDriverParams*)params)->timer_config[1]; duty_cycle_counts = (uint32_t)(dc_b * (float)(t->timer_cfg.period_counts)); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts, t->duty_pin) != FSP_SUCCESS) { // error } t = ((RenesasHardwareDriverParams*)params)->timer_config[2]; duty_cycle_counts = (uint32_t)(dc_c * (float)(t->timer_cfg.period_counts)); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts, t->duty_pin) != FSP_SUCCESS) { // error } } void _writeDutyCycle4PWM(float dc_1a, float dc_1b, float dc_2a, float dc_2b, void* params){ RenesasTimerConfig* t = ((RenesasHardwareDriverParams*)params)->timer_config[0]; uint32_t duty_cycle_counts = (uint32_t)(dc_1a * (float)(t->timer_cfg.period_counts)); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts, t->duty_pin) != FSP_SUCCESS) { // error } t = ((RenesasHardwareDriverParams*)params)->timer_config[1]; duty_cycle_counts = (uint32_t)(dc_1b * (float)(t->timer_cfg.period_counts)); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts, t->duty_pin) != FSP_SUCCESS) { // error } t = ((RenesasHardwareDriverParams*)params)->timer_config[2]; duty_cycle_counts = (uint32_t)(dc_2a * (float)(t->timer_cfg.period_counts)); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts, t->duty_pin) != FSP_SUCCESS) { // error } t = ((RenesasHardwareDriverParams*)params)->timer_config[3]; duty_cycle_counts = (uint32_t)(dc_2b * (float)(t->timer_cfg.period_counts)); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts, t->duty_pin) != FSP_SUCCESS) { // error } } void _setSinglePhaseState(RenesasTimerConfig* hi, RenesasTimerConfig* lo, PhaseState state) { gpt_gtior_setting_t gtior; gtior.gtior = hi->ctrl.p_reg->GTIOR; bool on = (state==PHASE_ON) || (state==PHASE_HI); if (hi->duty_pin == GPT_IO_PIN_GTIOCA_AND_GTIOCB) { bool ch = false; if (gtior.gtior_b.obe != on) { gtior.gtior_b.obe = on; ch = true; } // B is high side on = (state==PHASE_ON) || (state==PHASE_LO); if (gtior.gtior_b.oae != on) { gtior.gtior_b.oae = on; ch = true; } if (ch) hi->ctrl.p_reg->GTIOR = gtior.gtior; return; } if (hi->duty_pin == GPT_IO_PIN_GTIOCA) { if (gtior.gtior_b.oae != on) { gtior.gtior_b.oae = on; hi->ctrl.p_reg->GTIOR = gtior.gtior; } } else if (hi->duty_pin == GPT_IO_PIN_GTIOCB) { if (gtior.gtior_b.obe != on) { gtior.gtior_b.obe = on; hi->ctrl.p_reg->GTIOR = gtior.gtior; } } gtior.gtior = lo->ctrl.p_reg->GTIOR; on = (state==PHASE_ON) || (state==PHASE_LO); if (lo->duty_pin == GPT_IO_PIN_GTIOCA) { if (gtior.gtior_b.oae != on) { gtior.gtior_b.oae = on; lo->ctrl.p_reg->GTIOR = gtior.gtior; } } else if (lo->duty_pin == GPT_IO_PIN_GTIOCB) { if (gtior.gtior_b.obe != on) { gtior.gtior_b.obe = on; lo->ctrl.p_reg->GTIOR = gtior.gtior; } } } void _writeDutyCycle6PWM(float dc_a, float dc_b, float dc_c, PhaseState *phase_state, void* params){ RenesasTimerConfig* t = ((RenesasHardwareDriverParams*)params)->timer_config[0]; RenesasTimerConfig* t1 = ((RenesasHardwareDriverParams*)params)->timer_config[1]; uint32_t dt = (uint32_t)(((RenesasHardwareDriverParams*)params)->dead_zone * (float)(t->timer_cfg.period_counts)); uint32_t duty_cycle_counts = (uint32_t)(dc_a * (float)(t->timer_cfg.period_counts)); bool hw_deadtime = ((RenesasHardwareDriverParams*)params)->channels[0] == ((RenesasHardwareDriverParams*)params)->channels[1]; uint32_t dt_act = (duty_cycle_counts>0 && !hw_deadtime)?dt:0; _setSinglePhaseState(t, t1, phase_state[0]); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts - dt_act, t->duty_pin) != FSP_SUCCESS) { // error } if (!hw_deadtime) { if (R_GPT_DutyCycleSet(&(t1->ctrl), duty_cycle_counts + dt_act, t1->duty_pin) != FSP_SUCCESS) { // error } } t = ((RenesasHardwareDriverParams*)params)->timer_config[2]; t1 = ((RenesasHardwareDriverParams*)params)->timer_config[3]; duty_cycle_counts = (uint32_t)(dc_b * (float)(t->timer_cfg.period_counts)); hw_deadtime = ((RenesasHardwareDriverParams*)params)->channels[2] == ((RenesasHardwareDriverParams*)params)->channels[3]; dt_act = (duty_cycle_counts>0 && !hw_deadtime)?dt:0; _setSinglePhaseState(t, t1, phase_state[1]); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts - dt_act, t->duty_pin) != FSP_SUCCESS) { // error } if (!hw_deadtime) { if (R_GPT_DutyCycleSet(&(t1->ctrl), duty_cycle_counts + dt_act, t1->duty_pin) != FSP_SUCCESS) { // error } } t = ((RenesasHardwareDriverParams*)params)->timer_config[4]; t1 = ((RenesasHardwareDriverParams*)params)->timer_config[5]; duty_cycle_counts = (uint32_t)(dc_c * (float)(t->timer_cfg.period_counts)); hw_deadtime = ((RenesasHardwareDriverParams*)params)->channels[4] == ((RenesasHardwareDriverParams*)params)->channels[5]; dt_act = (duty_cycle_counts>0 && !hw_deadtime)?dt:0; _setSinglePhaseState(t, t1, phase_state[2]); if (R_GPT_DutyCycleSet(&(t->ctrl), duty_cycle_counts, t->duty_pin) != FSP_SUCCESS) { // error } if (!hw_deadtime) { if (R_GPT_DutyCycleSet(&(t1->ctrl), duty_cycle_counts + dt_act, t1->duty_pin) != FSP_SUCCESS) { // error } } } #endif