XMC4500 CCU4 32Bit PWM

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

cross mob
User14626
Level 1
Level 1
I am trying to generate a PWM with a 32Bit resolution and 50% duty-cycle on P3.7 using CCU41_CC42 and CCU41_CC43. I wrote the following code to initialize the hardware:
const XMC_GPIO_CONFIG_t  PWM_pin_config	=
{
XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT3, //Mode
XMC_GPIO_OUTPUT_LEVEL_LOW, //level
XMC_GPIO_OUTPUT_STRENGTH_MEDIUM //strength
};
XMC_GPIO_Init(P3_7, &PWM_pin_config);

XMC_CCU4_SLICE_COMPARE_CONFIG_t SLICE_config;
SLICE_config.timer_mode = (uint32_t) XMC_CCU4_SLICE_TIMER_COUNT_MODE_EA;
SLICE_config.monoshot = (uint32_t) false;
SLICE_config.shadow_xfer_clear = (uint32_t) 0;
SLICE_config.dither_timer_period = (uint32_t) 0;
SLICE_config.dither_duty_cycle = (uint32_t) 0;
SLICE_config.prescaler_mode = (uint32_t) XMC_CCU4_SLICE_PRESCALER_MODE_NORMAL;
SLICE_config.mcm_enable = (uint32_t) 0;
SLICE_config.prescaler_initval = (uint32_t) XMC_CCU4_SLICE_PRESCALER_1;
SLICE_config.float_limit = (uint32_t) 0;
SLICE_config.dither_limit = (uint32_t) 0;
SLICE_config.passive_level = (uint32_t) XMC_CCU4_SLICE_OUTPUT_PASSIVE_LEVEL_LOW;
SLICE_config.timer_concatenation = (uint32_t) 0;

XMC_CCU4_Init(CCU41, XMC_CCU4_SLICE_MCMS_ACTION_TRANSFER_PR_CR);
XMC_CCU4_StartPrescaler(CCU41);
XMC_CCU4_SetModuleClock(CCU41, XMC_CCU4_CLOCK_SCU);

XMC_CCU4_SLICE_CompareInit(CCU41_CC42, &SLICE_config);
SLICE_config.timer_concatenation = 1;
XMC_CCU4_SLICE_CompareInit(CCU41_CC43, &SLICE_config);

XMC_CCU4_SLICE_StartTimer(CCU41_CC42);
XMC_CCU4_SLICE_StartTimer(CCU41_CC43);


The following function is used to set the period and duty-cycle (fixed to 50%):
void setPeriod(std::uint32_t period)
{
const uint32_t compare = period/2; //50% PWM

XMC_CCU4_SLICE_SetTimerPeriodMatch(CCU41_CC42, static_cast(period & 0xFFFF));
XMC_CCU4_SLICE_SetTimerPeriodMatch(CCU41_CC43, static_cast(period >> 16));
XMC_CCU4_SLICE_SetTimerCompareMatch(CCU41_CC42, static_cast(compare & 0xFFFF));
XMC_CCU4_SLICE_SetTimerCompareMatch(CCU41_CC43, static_cast(compare >> 16));

XMC_CCU4_EnableShadowTransfer(CCU41, XMC_CCU4_SHADOW_TRANSFER_SLICE_2);
XMC_CCU4_EnableShadowTransfer(CCU41, XMC_CCU4_SHADOW_TRANSFER_SLICE_3);
}

This all works fine with a period up to 0xFFFF. Everything above that (more than 16Bit set) deactivates the PWM output. Using the debugger I can see that the timer itself is running and the registers are set correctly. What am I doing wrong?
0 Likes
1 Reply
DRubeša
Employee
Employee
First solution authored First like received
Hi Julian,
the thing is that with the timer concatenation you will get 32 bit precision, but the implementation of it is different than what you implemented with splitting the value into lower and upper 16 bits. I would suggest to you to check "CCU4_CONFIG_SLICE_EXAMPLE_XMC47" example. There you will find a working example with attached .pdf that will help you with the understanding of CCU4 concatenation implementation. Additionally, you can find a Python script with an example how to calculate value of compare and period match registers for the both slices.

More or less the calculation of these values can be described with following pseudocode:

time_interval = 1. / frequency
count = time_interval / tick_resolution

msb = 0;
while True:
count = count / 2
msb = msb + 1
if (count < 65535):
break

higher_period_value = (1 << msb) - 1 <== upper slice period match register value
lower_period_value = int(count) <== lower slice period match register value

temp_period = ((higher_period_value + 1) * (lower_period_value + 1)) + 1
compare_value = ((100 - duty_cycle) * (temp_period)) / 100

lower_compare_value = int(compare_value % lower_period_value) <== lower slice compare match register value
higher_compare_value= int(compare_value / lower_period_value) <== upper slice compare match register value



and for additional explanation please refer to Reference manual and previously mentioned example.

Best regards,
Deni
0 Likes