Can anyone help me figure out how to configure the PWM deadtime. I have not had any luck. Phase B waveform always comes out incorrect. I must be doing something wrong. Below is a scope shot of the PWM as expexted without deadtime.
Top trace is timer 3 overflow ISR. Yellow and Red traces are T3 CHA and CHB respectively. Blue and Green traces are T2 CHA and CHB respectively. I need to configure deadtime between CHA and CHB for each timer. I am having issues getting the deadtime to work correctly.
Any help would be appreciated.
void hardware::initInverterPwm( void)
const uint32_t period = ( 120000000 / 60) / 2 ;
const uint32_t alpha = uint32_t( float( period) * 0.10) ;
gpt_instance_ctrl_t *gptCtrl ;
R_GPTA0_Type *gptRegs ;
g_timer2.p_api->open( g_timer2.p_ctrl, g_timer2.p_cfg) ;
g_timer3.p_api->open( g_timer3.p_ctrl, g_timer3.p_cfg) ;
// config timer 3
gptCtrl = ( gpt_instance_ctrl_t *)g_timer3.p_ctrl ;
gptRegs = ( R_GPTA0_Type *)gptCtrl->p_reg ;
for ( uint8_t i = 0; i < 2; i++)
gptRegs->GTWP = 0x0000A500 ; // enable access to timer registers
gptRegs->GTCR_b.MD = 1 ; // sawtooth pwm mode - oneshot
gptRegs->GTCR_b.TPCS = 0 ; // pclkd / 1
gptRegs->GTPR = period - 1 ; // period register
gptRegs->GTCNT = i * 2 * alpha ; // init counter value - T3 = 0 and T2 = 2*alpha
gptRegs->GTIOR_b.GTIOA = 3 ;
gptRegs->GTIOR_b.GTIOB = 19 ;
// configure this for deadtime - this is the problem
gptRegs->GTDTCR_b.TDE = 0 ; // Use GTDVU and GTDVD to set the compare match value for negative-phase waveform with dead time automatically in GTCCRB
gptRegs->GTDTCR_b.TDBUE = 0 ; // GTDVU Buffer Operation Enable
gptRegs->GTDTCR_b.TDBDE = 0 ; // GTDVD Buffer Operation Enable
gptRegs->GTDTCR_b.TDFER = 0 ; // Automatically set the value written to GTDVU to GTDVD
gptRegs->GTDBU = 120 ; // sets deadtime buffer to 1us
gptRegs->GTDBD = 120 ; // sets deadtime buffer to 1us
gptRegs->GTCCRC = alpha ; // GTCCRC to GTCCRA at the cycle end
gptRegs->GTCCRE = alpha ; // GTCCRE to GTCCRB at the cycle end
gptRegs->GTCCRD = alpha ; // GTCCRD to temporary register A at the cycle end
gptRegs->GTCCRF = alpha ; // GTCCRF to temporary register B at the cycle end
// Temporary register A to GTCCRA at a GTCCRA compare match
// Temporary register B to GTCCRB at a GTCCRB compare match.
gptRegs->GTSSR_b.CSTRT = 1 ; // enable software start
// config timer 2
gptCtrl = ( gpt_instance_ctrl_t *)g_timer2.p_ctrl ;
gptRegs = ( R_GPTA0_Type *)gptCtrl->p_reg ;
gptRegs->GTSTR = ( 1 << 3) + ( 1 << 2) ; // start timer 2 and 3 at the same time
I'll be honest I've never got PWM one shot mode working. It seems to be a very complicated PWM mode master!
Please have a look on the media gallery where I've uploaded "Triangle-wave PWM mode 1.zip"
It was written & tested for a S7G2-SK, but it will be easily ported to the S5D9 as the GPT is the same across S7 & S5 families.
The project demonstrates Triangle-wave PWM mode 1.
When running, the PWM duty values are calculated / updated in either the GPT overflow interrupt, or in the while(1) processing loop. This can be selected by the #define in the source file.
The example generates continuously variable PWM suitable for a sine-wave output (can be seen when filtered)
Carrier frequency is 20kHz
The cdoe only generates PWM on a single channel (GPT0), but the code can be duplicated for additional channels as required by yourself.
I hope this helps
In reply to Richard:
I tested automatic dead-time setup using saw-wave one-shot mode and managed to get it to work. One "gotcha" is that you cannot use the bit-field to set GTDTCR.TDE bit to 1 - the compiler will emit 16-bit write instruction which will leave this register unmodified. Performing GTDTCR = 1UL; addresses this issue. Here's the code snippet to configure timer with all of the required settings:
R_GPTA0_Type * t2 = (R_GPTA0_Type *) ((gpt_instance_ctrl_t *) tmr2.p_ctrl)->p_reg; t2->GTWP = GPT_GTWP_KEY; t2->GTCR_b.MD = 0b001; // Set saw-wave one-shot mode t2->GTUDDTYC_b.UD = 0b1; // Count up t2->GTCR_b.TPCS = 0b000; // Set clock source to PCLKD/1 t2->GTPR_b.GTPR = (uint32_t) (period - 1); // Set maximum count value t2->GTIOR_b.GTIOA = 0b00011; // 4 Initial output low // 3:2 Retain output at cycle end // 1:0 Toggle output at Compare Match A t2->GTIOR_b.GTIOB = 0b10011; // 4 Initial output high // 3:2 Retain output at cycle end // 1:0 Toggle output at Compare Match B t2->GTIOR_b.OAE = 0b1; // Enable pin GTIOCA t2->GTIOR_b.OBE = 0b1; // Enable pin GTIOCB#if APP_TIMER_FORCE_SYMMETRY uint32_t rise = offset + (APP_TIMER_DT_CYCLES / 2); uint32_t fall = offset + ((period - APP_TIMER_DT_CYCLES) / 2); t2->GTCCRC_b.GTCCRC = rise; // Set buffer for GTCCRA t2->GTCCRD_b.GTCCRD = fall; // Set buffer for GTCCRA#else t2->GTCCRC_b.GTCCRC = offset; // Set buffer for GTCCRA t2->GTCCRD_b.GTCCRD = offset + (period / 2); // Set buffer for GTCCRA#endif t2->GTBER_b.CCRSWT = 0b1; // Force buffer transfers now t2->GTDTCR = 1UL; // Enable automatic dead-time adjustment in GTCCRB t2->GTDVU_b.GTDVU = APP_TIMER_DT_CYCLES; // Dead time first half t2->GTDVD_b.GTDVD = APP_TIMER_DT_CYCLES; // Dead time second half t2->GTSSR_b.CSTRT = 0b1; // Enable sofware start by GTSTR t2->GTPSR_b.CSTOP = 0b1; // Enable sofware stop by GTSTP t2->GTCSR_b.CCLR = 0b1; // Enable sofware stop by GTCLR t2->GTSTR |= ((1 << 2); // start the timer
When APP_TIMER_FORCE_SYMMETRY is set to non-zero value, GTCCRA value is compensated to maintain equal duty cycle between outputs A and B