Dear community,
we've implemented a small companion application for driving/managing a bunch of switching relays applying safety checks regarding weld contact and valid switch combination. This application is ported to an LPC844. If activated each relay coil is asserted with a 50% PWM signal at 17kHz (after asserting 100% for 200ms).
To improve EMC performance we're trying to add some kind of spread spectrum to this PWM signal to reduce the 17kHz harmonics' peaks in EM spectrum. As this is not supported by the HW I tried to achieve this by periodically modifying the PWM period with a small offset within the SCTimer peripheral but get results that I was not expecting and which I have no explanation for it.
How it is set up
Each relay's coil is connected to a dedicated output pin (via MOSFET stage). Initially all these pins are muxed to the GPIO peripheral driving them low. Additionally the SCTimer peripheral is initialized (OUT0, OUT1, OUT2) configuring a PWM frequency of 17kHz via SCTIMER_SetupPwm() call:
static Relay_sctPwmData_t Relay_asctPwmChannels[] = { ... }
static uint8_t u8PWMDutyCycle = 50U;
static uint32_t u32PwmFreq = 17000U;
// ...
for (uint32_t u32PwmCh=0; u32PwmCh < 3; u32PwmCh++)
{
Relay_sctPwmData_t *psctPwmSignal = &Relay_asctPwmChannels[u32PwmCh];
sctimer_pwm_signal_param_t sctimerPwmParams;
// kSCTIMER_Out_0,kSCTIMER_Out_1 or kSCTIMER_Out_2
sctimerPwmParams.output = psctPwmSignal->eSCTimerOut;
sctimerPwmParams.level = kSCTIMER_HighTrue;
sctimerPwmParams.dutyCyclePercent = u8PWMDutyCycle;
uint32_t u32Freqency = CLOCK_GetFreq(kSCT_Clk_From_SysPll);
// Create PWM signal, the returned event number corresponds to the PWM
// period event (pulse period would be event+1)
status_t status = SCTIMER_SetupPwm(SCT0, &sctimerPwmParams,
SCTIMER_EdgeAlignedPwm,
u32PwmFreq, u32Freqency,
&psctPwmSignal->u32EventNumberOutput);
// Store the calculated timer period value for spread spectrum functionality
psctPwmSignal->u32TimerPeriod = SCT0->MATCHREL[psctPwmSignal->u32EventNumberOutput];
// ...
}
If activating a relay its GPIO is set high and after a timeout the pin is swapped to the according SCTimer output resulting in a 50% PWM signal.
Spread spectrum modification
To achieve the "spread spectrum" I periodically add a slightly increasing offset to the previously stored "u32TimerPeriod" value and store it in the SCTimer output's corresponding MATCHREL register (and at a maximum steadily decreasing the offset again). This happens at a 1ms interval and is applied as follows:
uint32_t u32TimerPeriodNew = psctPwmSignal->u32TimerPeriod + i32Offset
uint32_t u32TimerPulsePeriodNew;
// For 100% dutycyle, make pulse period greater than period so the event will never occur
if (u8PWMDutyCycle >= 100U)
u32TimerPulsePeriodNew = u32TimerPeriodNew + 2U;
else
u32TimerPulsePeriodNew = (uint32_t) (((uint64_t) u32TimerPeriodNew * u8PWMDutyCycle) / 100U);
// Update timer PWM period
SCT0->MATCHREL[psctPwmSignal->u32EventNumberOutput] = u32TimerPeriodNew;
// Update timer PWM pulse period (which is derived from PWM period with applied duty cycle)
SCT0->MATCHREL[psctPwmSignal->u32EventNumberOutput+1] = u32TimerPulsePeriodNew;
What is observed
This basically results in a wobbling PWM frequency BUT also shows arbitrary distributed signal dropouts of one or more periods. Following image shows the traces of two signals generated from SCT_OUT0 (blue) and SCT_OUT1 (yellow)

UM11029 chapter 21 states that an SCTimer event's MATCH register is reloaded with the value of its corresponding MATCHREL each new counter cycle. From this rare information I'm not able to create any hypothesis what could lead to that behavior. What I'm curious about is that this rather special use case matches pretty much the common LED "fading" application which I would expect to work flawlessly (with the difference that here I also modify the overall PWM period and not just the PWM pulse period value).
I'd rather appreciate of anyone is able to contribute any hints how to address this issue.
Kind regards
André