CCU8 PWM Generation

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

cross mob
User12951
Level 1
Level 1
I am developing my code on XMC4500 Relax Kit using Dave 4.4.2
I am trying to get an PWM output on P0.5 of frequency 57kHz at duty cycle of 50% using CCU80
I am unable to get any output on oscilloscope however when I run APNOTE_CCU8_USECASE1 the system operates seamlessly.


#include
#include
#include
#include
#include
#include


#define TICKS_PER_SECOND 1000
#define PWM_PIN_PRI P0_5
#define PWM_MODULE_PRI CCU80
#define PWM_SLICE_PRI CCU80_CC80
#define PWM_SLICE_PRI_NUM 0U

/**

* @brief main() - Application entry point
*
* Details of function

* This routine is the application entry point. It is invoked by the device startup code.
*/

void clockInit(void);
void gpioInit(void);
void pwm_init(void);
void pwm_calculate_compare_period(void);

static volatile uint16_t ticks = 0;
static const uint16_t pwm_total_period = 2104;
static volatile uint8_t duty_cycle = 50;
static volatile uint16_t pwm_compare_period = 0;

int main(void)
{

/* Placeholder for user application code. The while loop below can be replaced with user application code. */

clockInit();
pwm_init();

SysTick_Config(SystemCoreClock / TICKS_PER_SECOND);

while(1U)
{

}
}

//120MHz - External Crystal (12MHz), PLL, FCPU -> 120MHz, FCCU -> 120MHz, FSYS -> 120MHz, Fperipheral -> 120MHz
void clockInit(void)
{ const XMC_SCU_CLOCK_CONFIG_t clock_config = {
.enable_oschp = true,
.enable_osculp = false,
.calibration_mode = XMC_SCU_CLOCK_FOFI_CALIBRATION_MODE_AUTOMATIC,
.fstdby_clksrc = XMC_SCU_HIB_STDBYCLKSRC_OSI,
.fsys_clksrc = XMC_SCU_CLOCK_SYSCLKSRC_PLL,
.fccu_clkdiv = 1U,
.fcpu_clkdiv = 1U,
.fperipheral_clkdiv = 1U,
.fsys_clkdiv = 1U,
//Formula for P, N, K2 on Page->506 and Table for standard values on Page->507 of reference manual
.syspll_config.clksrc = XMC_SCU_CLOCK_SYSPLLCLKSRC_OSCHP,
.syspll_config.mode = XMC_SCU_CLOCK_SYSPLL_MODE_NORMAL,
.syspll_config.p_div = 2U,
.syspll_config.k_div = 4U,
.syspll_config.n_div = 80U
};

XMC_SCU_CLOCK_Init(&clock_config);

}

void gpioInit(void)
{
//Configure P0_5 for PWM Output
XMC_GPIO_CONFIG_t gpio_config_pwm = {
.mode = P0_5_AF_CCU80_OUT00,
.output_level = XMC_GPIO_OUTPUT_LEVEL_LOW,
.output_strength = XMC_GPIO_OUTPUT_STRENGTH_STRONG_SHARP_EDGE
};
XMC_GPIO_Init(PWM_PIN_PRI, &gpio_config_pwm);
}

void pwm_init(void)
{
XMC_CCU8_SLICE_COMPARE_CONFIG_t pwm_slice_config = {
.asymmetric_pwm = 0U,
.dither_duty_cycle = 0U,
.dither_limit = 0U,
.dither_timer_period = 0U,
.float_limit = 0U,
.invert_out0 = 0U,
.invert_out1 = 1U,
.invert_out2 = 0U,
.invert_out3 = 1U,
.mcm_ch1_enable = (uint32_t) false,
.mcm_ch2_enable = (uint32_t) false,
.monoshot = (uint32_t) false,
.passive_level_out0 = XMC_CCU8_SLICE_OUTPUT_PASSIVE_LEVEL_LOW,
.passive_level_out1 = XMC_CCU8_SLICE_OUTPUT_PASSIVE_LEVEL_LOW,
.passive_level_out2 = XMC_CCU8_SLICE_OUTPUT_PASSIVE_LEVEL_LOW,
.passive_level_out3 = XMC_CCU8_SLICE_OUTPUT_PASSIVE_LEVEL_LOW,
.prescaler_initval = 0U,
.prescaler_mode = XMC_CCU8_SLICE_PRESCALER_MODE_NORMAL,
.shadow_xfer_clear = 0U,
.slice_status = XMC_CCU8_SLICE_STATUS_CHANNEL_1,
.timer_concatenation = false,
.timer_mode = XMC_CCU8_SLICE_TIMER_COUNT_MODE_EA
};

XMC_CCU8_Init(PWM_MODULE_PRI, XMC_CCU8_SLICE_MCMS_ACTION_TRANSFER_PR_CR);

XMC_CCU8_StartPrescaler(PWM_MODULE_PRI);

XMC_CCU8_SetModuleClock(PWM_MODULE_PRI, XMC_CCU8_CLOCK_SCU);

XMC_CCU8_SLICE_CompareInit(PWM_SLICE_PRI, &pwm_slice_config);

XMC_CCU8_SLICE_SetTimerPeriodMatch(PWM_SLICE_PRI, pwm_total_period);

pwm_calculate_compare_period();

XMC_CCU8_SLICE_SetTimerCompareMatch(PWM_SLICE_PRI, XMC_CCU8_SLICE_COMPARE_CHANNEL_1, pwm_compare_period);

XMC_CCU8_EnableShadowTransfer(PWM_MODULE_PRI, XMC_CCU8_SHADOW_TRANSFER_SLICE_0);

XMC_CCU8_SLICE_EnableEvent(PWM_SLICE_PRI, XMC_CCU8_SLICE_IRQ_ID_PERIOD_MATCH);

XMC_CCU8_SLICE_SetInterruptNode(PWM_SLICE_PRI, XMC_CCU8_SLICE_IRQ_ID_PERIOD_MATCH, XMC_CCU8_SLICE_SR_ID_0);

NVIC_SetPriority(CCU80_0_IRQn, 63U);

NVIC_EnableIRQ(CCU80_0_IRQn);

gpioInit();

XMC_CCU8_EnableClock(PWM_MODULE_PRI, PWM_SLICE_PRI_NUM);

XMC_CCU8_SLICE_StartTimer(PWM_SLICE_PRI);


}

inline void pwm_calculate_compare_period(void)
{
pwm_compare_period = (uint16_t) ((1-((float)duty_cycle / 100)) * (pwm_total_period+1));
}

void SysTick_Handler(void)
{
if(++ticks >= 5000)
{

}
}

void CCU80_0_IRQHandler(void)
{
XMC_CCU8_SLICE_ClearEvent(PWM_SLICE_PRI, XMC_CCU8_SLICE_IRQ_ID_PERIOD_MATCH);
XMC_CCU8_SLICE_SetTimerCompareMatchChannel1(PWM_SLICE_PRI, pwm_compare_period);
XMC_CCU8_EnableShadowTransfer(PWM_MODULE_PRI, XMC_CCU8_SHADOW_TRANSFER_SLICE_0);
}
0 Likes
2 Replies
DRubeša
Employee
Employee
First solution authored First like received
Hi,

there is an issue in the following line:

.mode = P0_5_AF_CCU80_OUT00,


it´s seems that is replaced by the wrong macro...I will check with the colleagues is this a bug on our side or usage of a wrong type on your side 😛

But for now, just change the previously line of code to this:

.mode = XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT3,


and everything will work like a charm.

P.S. I check this issue with macro one more time and from XMCLib point of view it´s fine; there is a "XMC_GPIO_IsModeValid" function to check if the mode is valid and option "XMC_GPIO_MODE_OUTPUT_ALT3" (the value that corresponds to P0_5_AF_CCU80_OUT00) is not an valid input. So either you take a look what is the alternate function used for your use case or you can do something like this:

.mode = P0_5_AF_CCU80_OUT00 | XMC_GPIO_MODE_OUTPUT_PUSH_PULL,


Now the compiler will do its job and combine the wanted pin with the appropriate alternate function and wanted mode (in this case push-pull output).

Best regards,
Deni
0 Likes
User12951
Level 1
Level 1
Thanks the advice, my issue has been resolved.
0 Likes