Hello!
I'm using the PWM on my FRDM-MCXN947 to create two complimentary 500kHz waveforms.
They're using submodule 1 (PWM1), have an input clock of 150MHz, and a deadtime of 6 ticks (40ns). Everything looks good so far!
I also want to implement duty cycle dithering.
But, I've noticed when I turn on the registers to enable dithering, my deadtime reduces to 0.
There are no functions to enable dithering, so I access the register directly:
https://www.nxp.com/docs/en/application-note/AN14196.pdf
PWM1->SM[0].FRCTRL |= PWM_FRCTRL_FRAC1_EN(1);
PWM1->SM[0].FRCTRL |= PWM_FRCTRL_FRAC23_EN(1);
PWM1->SM[0].FRCTRL |= PWM_FRCTRL_FRAC45_EN(1);
Specifically, enabling FRAC1 and FRAC45 does not reduce the deadtime, but FRAC23 does.
I'd like to be able to have both deadtime and dithering.
Can you tell me why this happens, and if this works on this or other submodules, boards, etc.?
Thank you for your time,
JC
If anyone else is running into this issue, I've worked around it for now by:
- Make 2 duplicate independent waveforms, instead of complimentary
- Make the one channel HIGH on active and the other LOW on active
- Simulate a deadtime by making the duty cycle of one channel (deadtime ticks * 2) longer (I'm not sure if this is enough to work for edge-aligned waveforms, I use center-aligned)
- After enabling FRCTRL somewhere, set FRACVAL3 (dither for channel A) and FRACVAL5 (dither for channel B) in PWM_UpdatePwmDutycycleHighAccuracy
// During the integer division to calculate pwmHighPulse,
// any remainder was simply discarded and cut off during rounding down.
// lost_precision is the remainder that was cut off.
const double lost_precision = ((pulseCnt * dutyCycle) - (pwmHighPulse * 65535U)) / pulseCnt;
// Section 3.2.6 Fractional delay logic
// FRACVAL3 is, every pulseCnt pulses, how many pulses we want on for an extra clock tick
// NOTE: Yes, this also loses precision, but less than if we did nothing.
// We can only dither the nearest 1/pulseCnt precision, unless we use adjust
// FRACVAL3 every pulseCnt strategically.
// lost_precision / (((1 / pulseCnt) / pulseCnt)(65535)) =
// lost_precision * pulseCnt * pulseCnt / 65525
base->SM[subModule].FRACVAL3 = PWM_FRACVAL3_FRACVAL3((pulseCnt * pulseCnt * lost_precision) / 65535U);
base->SM[subModule].FRACVAL5 = PWM_FRACVAL5_FRACVAL5((pulseCnt * pulseCnt * lost_precision) / 65535U);
Thought I'd share, although not using a workaround would be ideal, thanks!