CCU8 modulated outputs are not synchonized

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

cross mob
User10696
Level 4
Level 4
First solution authored
I am using 3 slices of the CCU8 timer to produce 6 PWMs (center aligned) for a BLDC motor. The 6 outputs are modulated from the output of the POSIF unit.

3357.attach

In the image chanels D0 to D6 are the 6 PWM outputs. When the hall sensors change (channel G1) the POSIF sends the next modulation pattern on the next synchronization signal from the CCU8.
What I do not understand is why does channel D3 change before channel D5? It seems like D3 is changing on the period match and channel D5 is changing on the one match. Both D3 and D5 are coming from the ST1 inverted output of 2 slices.

It does not matter where the motor is positioned, the falling edge (Low side FET off) is always before the next channel raising edge (Low side FET on).
The result is that no low side FET is on during this period, which causes strange spikes on the current measurement. I am not sure what it is doing to the motor, but properbly it it not running as smoothly as it should be.

Have I configured the CCU8 incorrectly? Or does the CCU8 always do this?
0 Likes
8 Replies
Mike1
Employee
Employee
5 sign-ins First question asked 10 replies posted
The gap you are seeing is not normal. There could be several reasons for it. Are the slices all setup identically? Are they started synchronously (e.g. via CCUCON.GSC8x)?
0 Likes
User10696
Level 4
Level 4
First solution authored
Thanks Mike for the reply. I didn't think that was normal.
The 3 slices are initialized with the same parameters. For the synchronization I am using this sequence in the initialization:
XMC_CCU8_SLICE_ConfigureEvent(ccu8Slice, XMC_CCU8_SLICE_EVENT_0, &startEventConfig);
XMC_CCU8_SLICE_StartConfig(ccu8Slice, XMC_CCU8_SLICE_EVENT_0, XMC_CCU8_SLICE_START_MODE_TIMER_START_CLEAR);
XMC_CCU8_SLICE_StartTimer(ccu8Slice);


startEventConfig is set to:
startEventConfig.mapped_input = static_cast(CCU81_IN0_SCU_GSC81); // Required input signal for the Event.
startEventConfig.edge = XMC_CCU8_SLICE_EVENT_EDGE_SENSITIVITY_RISING_EDGE; // Select the event edge of the input signal
startEventConfig.duration = XMC_CCU8_SLICE_EVENT_FILTER_DISABLED; // Low Pass filter duration


Then to start the PWMs I am using:
XMC_SCU_SetCcuTriggerHigh((1U << (8U + moduleNumber)));


As far as I know this is correct, but please tell me if I am doing anything wrong.
Do you need any more information?

Adrian
0 Likes
User10696
Level 4
Level 4
First solution authored
I really need some help with this, as I have no idea how to get it working correctly!
Is this forum the only place to get help from Infineon or do they have a support page? I have not been able to find it.
0 Likes
User10696
Level 4
Level 4
First solution authored
I am still waiting for a reply.
Where can I get support from Infineon? This forum does not give me the support I require.
0 Likes
Mike1
Employee
Employee
5 sign-ins First question asked 10 replies posted
Sorry for the delay. I see that you are doing synchronous rectification (Active Freewheeling). In this case when a phase is not PWMing the dead-time should be disabled, or you can get an unexpected dead-time insertion. But I don't think this is your issue. It could be because the PWM compare registers for the phases that are not PWMing are not setup before the commutation. Below are two functions that might be useful. SetHsPwm would be called at initialization and after a correct Hall Event to setup the PWM value values for the 3 phases for the next commutation. This ensures that when the next commutation occurs the transition will be smooth. UpdateHsPwm is used to adjust the duty cycle in your control loop. It looks to see what phase is PWMing and what phase will be PWMing on the next commutation and adjusts their duty cycles.

If this doesn't help, please let me know and we might have to setup a WebEx to look into it in more detail.

void SetHsPwm(uint8_t next_halls, uint16_t comp_val)
{

volatile uint16_t next_out;

next_out = OutPat[next_halls + Direction];

CCU80_CC80->CR2S = comp_val+1); // ADC trigger
CCU80_CC81->CR2S = comp_val+1); // ADC trigger

if( next_out & (HS_U) )
{
CCU80_CC80->CR1S = comp_val;
if(ActiveFreewheeling)
{
CCU80_CC80->DTC |= CCU8_CC8_DTC_DTE1_Msk; // Enable Dead Time on ch 1
}
}
if( (next_out & LS_U) && (!(next_out & HS_U)) )
{
CCU80_CC80->CR1S =0; // Set Low Side DC to 100%
CCU80_CC80->DTC &= ~CCU8_CC8_DTC_DTE1_Msk; // Disable Dead Time on ch 1
}
if( next_out & (HS_V) )
{
CCU80_CC81->CR1S = comp_val;
if(ActiveFreewheeling)
{
CCU80_CC81->DTC |= CCU8_CC8_DTC_DTE1_Msk; // Enable Dead Time on ch 1
}
}
if( (next_out & LS_V) && (!(next_out & HS_V)) )
{
CCU80_CC81->CR1S = 0; // Set Low Side DC to 100%
CCU80_CC81->DTC &= ~CCU8_CC8_DTC_DTE1_Msk; // Disable Dead Time on ch 1
}
if( next_out & (HS_W) )
{
CCU80_CC82->CR1S = comp_val;
if(ActiveFreewheeling)
{
CCU80_CC82->DTC |= CCU8_CC8_DTC_DTE1_Msk; // Enable Dead Time on ch 1
}
}
if( (next_out & LS_W) && (!(next_out & HS_W)) )
{
CCU80_CC82->CR1S = 0; // Set Low Side DC to 100%
CCU80_CC82->DTC &= ~CCU8_CC8_DTC_DTE1_Msk; // Disable Dead Time on ch 1
}

// Enable Shadow Transfer of compare/period/passive values (slice 0-2)
CCU80->GCSS |= CCU8_GCSS_S0SE_Msk + CCU8_GCSS_S1SE_Msk + CCU8_GCSS_S2SE_Msk;

}

void UpdateHsPwm(u16 comp_val)
{

__disable_irq(); //disable all interrupts
CCU80_CC80->CR2S = comp_val+1; // ADC Trigger
CCU80_CC81->CR2S = comp_val+1; // ADC Trigger

if (CCU80_CC80->CR1S != 0)
{
CCU80_CC80->CR1S = comp_val;
}
if (CCU80_CC81->CR1S != 0)
{
CCU80_CC81->CR1S = comp_val;
}
if (CCU80_CC82->CR1S != 0)
{
CCU80_CC82->CR1S = comp_val;
}
__enable_irq(); //enable all interrupts
// Enable Shadow Transfer of compare/period/passive values (slice 0-2)
CCU80->GCSS |= CCU8_GCSS_S0SE_Msk + CCU8_GCSS_S1SE_Msk + CCU8_GCSS_S2SE_Msk;
}
0 Likes
Mike1
Employee
Employee
5 sign-ins First question asked 10 replies posted
Please forgive the typo's. I already found a couple:

void SetHsPwm(uint8_t next_halls, uint16_t comp_val)
{

volatile uint16_t next_out;

next_out = OutPat[next_halls + Direction];

CCU80_CC80->CR2S = comp_val+1; // ADC trigger
CCU80_CC81->CR2S = comp_val+1; // ADC trigger

if( next_out & (HS_U) )
{
CCU80_CC80->CR1S = comp_val;
if(ActiveFreewheeling)
{
CCU80_CC80->DTC |= CCU8_CC8_DTC_DTE1_Msk; // Enable Dead Time on ch 1
}
}
if( (next_out & LS_U) && (!(next_out & HS_U)) )
{
CCU80_CC80->CR1S =0; // Set Low Side DC to 100%
CCU80_CC80->DTC &= ~CCU8_CC8_DTC_DTE1_Msk; // Disable Dead Time on ch 1
}
if( next_out & (HS_V) )
{
CCU80_CC81->CR1S = comp_val;
if(ActiveFreewheeling)
{
CCU80_CC81->DTC |= CCU8_CC8_DTC_DTE1_Msk; // Enable Dead Time on ch 1
}
}
if( (next_out & LS_V) && (!(next_out & HS_V)) )
{
CCU80_CC81->CR1S = 0; // Set Low Side DC to 100%
CCU80_CC81->DTC &= ~CCU8_CC8_DTC_DTE1_Msk; // Disable Dead Time on ch 1
}
if( next_out & (HS_W) )
{
CCU80_CC82->CR1S = comp_val;
if(ActiveFreewheeling)
{
CCU80_CC82->DTC |= CCU8_CC8_DTC_DTE1_Msk; // Enable Dead Time on ch 1
}
}
if( (next_out & LS_W) && (!(next_out & HS_W)) )
{
CCU80_CC82->CR1S = 0; // Set Low Side DC to 100%
CCU80_CC82->DTC &= ~CCU8_CC8_DTC_DTE1_Msk; // Disable Dead Time on ch 1
}

// Enable Shadow Transfer of compare/period/passive values (slice 0-2)
CCU80->GCSS |= CCU8_GCSS_S0SE_Msk + CCU8_GCSS_S1SE_Msk + CCU8_GCSS_S2SE_Msk;

}

void UpdateHsPwm(u16 comp_val)
{

__disable_irq(); //disable all interrupts
CCU80_CC80->CR2S = comp_val+1; // ADC Trigger
CCU80_CC81->CR2S = comp_val+1; // ADC Trigger

if (CCU80_CC80->CR1S != 0)
{
CCU80_CC80->CR1S = comp_val;
}
if (CCU80_CC81->CR1S != 0)
{
CCU80_CC81->CR1S = comp_val;
}
if (CCU80_CC82->CR1S != 0)
{
CCU80_CC82->CR1S = comp_val;
}
__enable_irq(); //enable all interrupts
// Enable Shadow Transfer of compare/period/passive values (slice 0-2)
CCU80->GCSS |= CCU8_GCSS_S0SE_Msk + CCU8_GCSS_S1SE_Msk + CCU8_GCSS_S2SE_Msk;
}
0 Likes
User10696
Level 4
Level 4
First solution authored
Hi Mike
Thanks for the reply. I have only just seen that you have replied. It seems the notification via email is not working correctly, as I did not receive any notifications.

I understand what you are saying and as far as I know my code is doing what you recommend. The dead time is only active on the slice that is PWMing the other two are disabled.
At each Hall sensor event I set the PWM compare register for the next sector even though it is disabled via the modulation inputs. At first I was not doing this and I was getting half PWM pulses at the beginning of each sector.

What I am seeing is the slices that are not PWMing are being masked at different times. How is the synchroinization realized? I am using the sync input of the POSIF to change the modulation signals,
but it seems they are not being appiled at the same moment in the CCU8, depending if it is low-to-high or high-to-low. The output changes are synchronous to the Period match and One match.

My system is fairly complex as the motor controller is written in C++ using a UML model based code generator. But maybe with a Webex session you could check the CCU8 register settings to see if there is anything incorrect.
0 Likes
User10696
Level 4
Level 4
First solution authored
I have seen the Multi channel pattern synchronization (Figure 23-51) in the reference manual. This example only shows an example in edge-aligned mode, I am using centered-aligned mode. Is there any documentation showing center-aligned mode?
0 Likes