Dec 17, 2018
06:46 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dec 17, 2018
06:46 AM
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.
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?
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?
8 Replies
Dec 17, 2018
07:24 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dec 17, 2018
07:24 AM
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)?
Dec 17, 2018
11:54 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dec 17, 2018
11:54 PM
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:
startEventConfig is set to:
Then to start the PWMs I am using:
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
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);
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
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
Dec 19, 2018
10:52 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dec 19, 2018
10:52 PM
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.
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.
Jan 24, 2019
03:23 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 24, 2019
03:23 AM
I am still waiting for a reply.
Where can I get support from Infineon? This forum does not give me the support I require.
Where can I get support from Infineon? This forum does not give me the support I require.
Feb 07, 2019
06:00 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Feb 07, 2019
06:00 AM
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;
}
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;
}
Feb 07, 2019
06:03 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Feb 07, 2019
06:03 AM
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;
}
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;
}
Feb 12, 2019
06:10 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Feb 12, 2019
06:10 AM
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.
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.
Feb 12, 2019
06:33 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Feb 12, 2019
06:33 AM
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?