Deadtime does not appear to work in the PWMSP002 app

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Not applicable
I am probably doing something wrong here so any advice would be greatly appreciated as I cannot get the PWMSP002 deadtime working

I have 2 instances of the PWMSP002 App running, each uses direct output to pins P0.6 and P0.4. A single CCU8GLOBAL is used.

I have configured the PWMSP002 Apps so their rising edges are aligned with zero deadtime (in reality there is a 2.7uS offset between them which I can't explain).

Here are the PWM waveforms (Channel 1 = PWMSP002/1, Channel 2 = PWMSP002/0)...



Here are the rising edges...



I was expecting to be able to offset the rising edges from each other by changing the Deadtime values in PWMSP002/1 and PWMSP002/0, but the deadtimes have no effect.

Thank you in advance
Best regards
Aaron
0 Likes
10 Replies
User6412
Level 4
Level 4
Have you edge aligned mode? If not - you have to change it to the edge aligned. In case if you have it, I think, the problem is that you have to start all timers by using the CCUCON global start register. Otherwise they will start not synchronously. As I alredy noted in forum, there is a bug in PWMMP001 App around this sinchronization, may be PWMSP002 has exactly the same problem? Btw, the deadtime was also no really correct in PWMMP001, so I made this configuration manually. So, this code I use to configure CCU81_CC8y slice (it makes it possible to use the synchronous global start and correct deadtimes):

/**
* Configuration of CCU81_CC8y slice
*/
void Init_CCU81_CC8_Slice(CCU8_CC8_TypeDef* slice_reg) {
/*Set the symmetric PWM setting*/
WR_REG(slice_reg->CHC, CCU8_CC8_CHC_ASE_Msk, CCU8_CC8_CHC_ASE_Pos, CCU8PWMLIB_SYMMETRIC);
/*Configure output (channels 1..4)*/
WR_REG(slice_reg->CHC, CCU8_CC8_CHC_OCS1_Msk, CCU8_CC8_CHC_OCS1_Pos, 0); // direct output
WR_REG(slice_reg->CHC, CCU8_CC8_CHC_OCS2_Msk, CCU8_CC8_CHC_OCS2_Pos, 0); // inverted output
WR_REG(slice_reg->CHC, CCU8_CC8_CHC_OCS3_Msk, CCU8_CC8_CHC_OCS3_Pos, 1); // inverted output
WR_REG(slice_reg->CHC, CCU8_CC8_CHC_OCS4_Msk, CCU8_CC8_CHC_OCS4_Pos, 1); // direct output
/*
* Enable and configuration dead time
*/
SET_BIT(slice_reg->DTC, CCU8_CC8_DTC_DTE1_Pos);
SET_BIT(slice_reg->DTC, CCU8_CC8_DTC_DTE2_Pos);
SET_BIT(slice_reg->DTC, CCU8_CC8_DTC_DCEN1_Pos);
SET_BIT(slice_reg->DTC, CCU8_CC8_DTC_DCEN2_Pos);
SET_BIT(slice_reg->DTC, CCU8_CC8_DTC_DCEN3_Pos);
SET_BIT(slice_reg->DTC, CCU8_CC8_DTC_DCEN4_Pos);
// Dead Time 0.5 us
WR_REG(slice_reg->DC1R, CCU8_CC8_DC1R_DT1R_Msk, CCU8_CC8_DC1R_DT1R_Pos, 0x3c);
WR_REG(slice_reg->DC2R, CCU8_CC8_DC2R_DT2R_Msk, CCU8_CC8_DC2R_DT2R_Pos, 0x3c);
WR_REG(slice_reg->DC1R, CCU8_CC8_DC1R_DT1F_Msk, CCU8_CC8_DC1R_DT1F_Pos, 0x3c);
WR_REG(slice_reg->DC2R, CCU8_CC8_DC2R_DT2F_Msk, CCU8_CC8_DC2R_DT2F_Pos, 0x3c);
/*
* Configuring External Start
*/
// Select rising edge for Event 0 (used for synchronous start)
WR_REG(slice_reg->INS, CCU8_CC8_INS_EV0EM_Msk, CCU8_CC8_INS_EV0EM_Pos, 1);
// External Start Signal (Event 0) CCU81.IN0H <= SCU.GLCCST81 (Global Start)
WR_REG(slice_reg->INS, CCU8_CC8_INS_EV0IS_Msk, CCU8_CC8_INS_EV0IS_Pos, 7);
// External Start Function triggered by Event 0
WR_REG(slice_reg->CMC, CCU8_CC8_CMC_STRTS_Msk, CCU8_CC8_CMC_STRTS_Pos, 1);
/*
* Enable and configure Trap via ERU1
*/
WR_REG(slice_reg->INS, CCU8_CC8_INS_EV2IS_Msk, CCU8_CC8_INS_EV2IS_Pos, 8); // Event 2 signal selection: CCU81.INyI <= ERU1.PDOUT1
//CLR_BIT(slice_reg->INS, CCU8_CC8_INS_EV2LM_Pos); // Event 2 active on HIGH level
SET_BIT(slice_reg->INS, CCU8_CC8_INS_EV2LM_Pos); // Event 2 active on LOW level
WR_REG(slice_reg->INS, CCU8_CC8_INS_LPF2M_Msk, CCU8_CC8_INS_LPF2M_Pos, 0); // LPF is disabled
SET_BIT(slice_reg->CMC, CCU8_CC8_CMC_TS_Pos); // TRAP function connected to Event 2
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TCM_Pos); // Center aligned mode
SET_BIT(slice_reg->TC, CCU8_CC8_TC_STRM_Pos); // External Start signal clears the timer and sets run bit
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TRAPE0_Pos); // TRAP functionality affects the CCU8x.OUTy0 output
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TRAPE1_Pos); // TRAP functionality affects the CCU8x.OUTy1 output
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TRAPE2_Pos); // TRAP functionality affects the CCU8x.OUTy2 output
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TRAPE3_Pos); // TRAP functionality affects the CCU8x.OUTy3 output
//CLR_BIT(slice_reg->TC, CCU8_CC8_TC_TRPSE_Pos); // Exiting from TRAP state isn’t synchronized with the PWM signal
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TRPSE_Pos); // Exiting from TRAP state is synchronized with the PWM signal
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TRPSW_Pos); // The TRAP state can only be exited by a SW request.
//CLR_BIT(slice_reg->TC, CCU8_CC8_TC_TRPSW_Pos); // The slice exits the TRAP state automatically when the TRAP condition is not present (Trap state cleared by HW and SW)
WR_REG(slice_reg->TC, CCU8_CC8_TC_STOS_Msk, CCU8_CC8_TC_STOS_Pos, 2); // CC8yST1 AND CC8yST2 forward to CCU8x.STy
// Set Period Register
WR_REG(slice_reg->PRS, CCU8_CC8_PRS_PRS_Msk, CCU8_CC8_PRS_PRS_Pos, PWM_PERIOD);
}
0 Likes
Not applicable
Hi Dmitry.

Thank you very much for your code. I have configured the PWMSP002 App for edge alignment but only in DAVE. If there is a problem in the PWMSP002 App then I will copy your coding approach for synchronous start, alignment and deadtime until a fix is available.

Thanks again
Aaron
0 Likes
elegantk
Employee
Employee
How to setup the deadtime for PWMSP002
1. Create a New DAVE CE project
2. Use only one instance of PWMSP002 from App Selection View
3. In the Simple PWM Configuration tab - Select "Start during initialization" for StartApp
4. In the Advanced PWM Configuration tab:
Enable Dead Time for both Outputs
1us for Rising Time
1us for Falling Time
5. Use the Manual Pin Assignment:
pin_directoutput Px.x
pin_invertedoutput Py.y
6. Generate, Compile and download the code

You should be able to observe the deadtime between Px.x and Py.y
0 Likes
Not applicable
Thanks elegantk but that deadtime has no effect. I have 2 instances of PWMSP002 sharing 1 instance of CCU8GLOBAL. The edges of the 2 output channels are aligned even if I change deadtime values.

Best regards
Aaron
0 Likes
elegantk
Employee
Employee
How the deadtime work:
- Instance #1 normal output and Instance #1 inverted output

Why deadtime does not work?
- Instance #1 normal output and Instance #2 normal output
As both of them are normal output, they will not have deadtime.

Since you are using two instances, you might wish to take a look at the four available output to have a better understanding:
- Instance #1 normal output
- Instance #1 inverted output
- Instance #2 normal output
- Instance #2 inverted output
0 Likes
Not applicable
Hi Aaron,

You could refer to UM (xmc4500_rm_v1+2_2012_12_ Chapter 23) for more details.

Best regards,
Zain
0 Likes
Not applicable
Hi Dmitry,


I am just trying to implement the OCS section of your code. I am unsure how you are calling your 'Init_CCU81_CC8_Slice()' function and in particular the 'slice_reg' parameter you are passing to it. Could you show me how you are calling the function please ?


Thank you very much
Aaron
0 Likes
User6412
Level 4
Level 4
This is the whole code:


/**
* Configuration of CCU81_CC8y slice
*/
void Init_CCU81_CC8_Slice(CCU8_CC8_TypeDef* slice_reg) {
/*Set the symmetric PWM setting*/
WR_REG(slice_reg->CHC, CCU8_CC8_CHC_ASE_Msk, CCU8_CC8_CHC_ASE_Pos, CCU8PWMLIB_SYMMETRIC);
/*Configure output (channels 1..4)*/
WR_REG(slice_reg->CHC, CCU8_CC8_CHC_OCS1_Msk, CCU8_CC8_CHC_OCS1_Pos, 0); // direct output
WR_REG(slice_reg->CHC, CCU8_CC8_CHC_OCS2_Msk, CCU8_CC8_CHC_OCS2_Pos, 0); // inverted output
WR_REG(slice_reg->CHC, CCU8_CC8_CHC_OCS3_Msk, CCU8_CC8_CHC_OCS3_Pos, 1); // inverted output
WR_REG(slice_reg->CHC, CCU8_CC8_CHC_OCS4_Msk, CCU8_CC8_CHC_OCS4_Pos, 1); // direct output
/*
* Enable and configuration dead time
*/
SET_BIT(slice_reg->DTC, CCU8_CC8_DTC_DTE1_Pos);
SET_BIT(slice_reg->DTC, CCU8_CC8_DTC_DTE2_Pos);
SET_BIT(slice_reg->DTC, CCU8_CC8_DTC_DCEN1_Pos);
SET_BIT(slice_reg->DTC, CCU8_CC8_DTC_DCEN2_Pos);
SET_BIT(slice_reg->DTC, CCU8_CC8_DTC_DCEN3_Pos);
SET_BIT(slice_reg->DTC, CCU8_CC8_DTC_DCEN4_Pos);
// Dead Time 0.5 us
WR_REG(slice_reg->DC1R, CCU8_CC8_DC1R_DT1R_Msk, CCU8_CC8_DC1R_DT1R_Pos, 0x3c);
WR_REG(slice_reg->DC2R, CCU8_CC8_DC2R_DT2R_Msk, CCU8_CC8_DC2R_DT2R_Pos, 0x3c);
WR_REG(slice_reg->DC1R, CCU8_CC8_DC1R_DT1F_Msk, CCU8_CC8_DC1R_DT1F_Pos, 0x3c);
WR_REG(slice_reg->DC2R, CCU8_CC8_DC2R_DT2F_Msk, CCU8_CC8_DC2R_DT2F_Pos, 0x3c);
/*
* Configuring External Start
*/
// Select rising edge for Event 0 (used for synchronous start)
WR_REG(slice_reg->INS, CCU8_CC8_INS_EV0EM_Msk, CCU8_CC8_INS_EV0EM_Pos, 1);
// External Start Signal (Event 0) CCU81.IN0H <= SCU.GLCCST81 (Global Start)
WR_REG(slice_reg->INS, CCU8_CC8_INS_EV0IS_Msk, CCU8_CC8_INS_EV0IS_Pos, 7);
// External Start Function triggered by Event 0
WR_REG(slice_reg->CMC, CCU8_CC8_CMC_STRTS_Msk, CCU8_CC8_CMC_STRTS_Pos, 1);
/*
* Enable and configure Trap via ERU1
*/
WR_REG(slice_reg->INS, CCU8_CC8_INS_EV2IS_Msk, CCU8_CC8_INS_EV2IS_Pos, 8); // Event 2 signal selection: CCU81.INyI <= ERU1.PDOUT1
//CLR_BIT(slice_reg->INS, CCU8_CC8_INS_EV2LM_Pos); // Event 2 active on HIGH level
SET_BIT(slice_reg->INS, CCU8_CC8_INS_EV2LM_Pos); // Event 2 active on LOW level
WR_REG(slice_reg->INS, CCU8_CC8_INS_LPF2M_Msk, CCU8_CC8_INS_LPF2M_Pos, 0); // LPF is disabled
SET_BIT(slice_reg->CMC, CCU8_CC8_CMC_TS_Pos); // TRAP function connected to Event 2
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TCM_Pos); // Center aligned mode
SET_BIT(slice_reg->TC, CCU8_CC8_TC_STRM_Pos); // External Start signal clears the timer and sets run bit
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TRAPE0_Pos); // TRAP functionality affects the CCU8x.OUTy0 output
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TRAPE1_Pos); // TRAP functionality affects the CCU8x.OUTy1 output
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TRAPE2_Pos); // TRAP functionality affects the CCU8x.OUTy2 output
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TRAPE3_Pos); // TRAP functionality affects the CCU8x.OUTy3 output
//CLR_BIT(slice_reg->TC, CCU8_CC8_TC_TRPSE_Pos); // Exiting from TRAP state isn’t synchronized with the PWM signal
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TRPSE_Pos); // Exiting from TRAP state is synchronized with the PWM signal
SET_BIT(slice_reg->TC, CCU8_CC8_TC_TRPSW_Pos); // The TRAP state can only be exited by a SW request.
//CLR_BIT(slice_reg->TC, CCU8_CC8_TC_TRPSW_Pos); // The slice exits the TRAP state automatically when the TRAP condition is not present (Trap state cleared by HW and SW)
WR_REG(slice_reg->TC, CCU8_CC8_TC_STOS_Msk, CCU8_CC8_TC_STOS_Pos, 2); // CC8yST1 AND CC8yST2 forward to CCU8x.STy
// Set Period Register
WR_REG(slice_reg->PRS, CCU8_CC8_PRS_PRS_Msk, CCU8_CC8_PRS_PRS_Pos, PWM_PERIOD);
}

/**
* This function makes initializations of the CCU81 Unit
*/
void Init_CCU81(void) {
// Assert reset
SCU_RESET->PRSET0 |= SCU_RESET_PRSET0_CCU81RS_Msk;
// De-assert reset
SCU_RESET->PRCLR0 |= SCU_RESET_PRCLR0_CCU81RS_Msk;
// Set the Run Bit of the prescaler
CCU81->GIDLC |= CCU8_GIDLC_SPRB_Msk;
// Initialize Slices 1..3
Init_CCU81_CC8_Slice(CCU81_CC81);
Init_CCU81_CC8_Slice(CCU81_CC82);
Init_CCU81_CC8_Slice(CCU81_CC83);
// Request SW shadow transfer for period, compare and Passive level values
CCU81->GCSS |= CCU8_GCSS_S1SE_Msk | CCU8_GCSS_S2SE_Msk | CCU8_GCSS_S3SE_Msk;
// Special initialization of Slice 0
Init_CCU81_CC80();
// IDLE mode clear
CCU81->GIDLC |= CCU8_GIDLC_CS0I_Msk | CCU8_GIDLC_CS1I_Msk | CCU8_GIDLC_CS2I_Msk | CCU8_GIDLC_CS3I_Msk;
}


And this is how to initiate the global start:


SCU_GENERAL->CCUCON |= SCU_GENERAL_CCUCON_GSC81_Msk;
0 Likes
Not applicable
Thank you again Dmitry. Now I understand. Very helpful.

Best regards
Aaron
0 Likes
Not applicable
Just a quick update. I've created the deadtime in my own code as follows...

1) Leading edge : by starting the 1st PWMSP002 app then waiting (in my case for 10uS) before starting the 2nd PWMSP002 app.
2) Trailing edge : by ensuring the pulse width of the 1st PWMSP002 is 2 x 10uS greater than the pulse width of the 2nd PWMSP002

Works well.
0 Likes