I am using the PSMC module in a PIC16F1782 to create a single-output PWM signal at 100 Hz. I am having problems with the duty cycle glitching on a periodic basis.
The code main loop runs every 1.024 ms and the duty-cycle registers are updated on every pass of the loop. The datasheet is quite specific in saying:
The PSMCxLD bit of the PSMCxCON register is provided to synchronize changes to the event Count registers. Changes are withheld from taking action until the first period event Reset after the PSMCxLD bit is set. For example, to change the PWM frequency, while maintaining the same effective duty cycle, the Period and Duty Cycle registers need to be changed. The changes to all four registers take effect simultaneously on the period event Reset after the PSMCxLD bit is set.
In my case, the duty-cycle register may or may not be changed on each pass through the loop but the LD bit is set on every pass through the loop regardless if any changes were needed or not.
I suspect this is where my problems occur but I need to understand why this might be happening. In particular, the datasheet appears to say that I can change any of the registers associated with the duty-cycle or period or phase at any time without affecting the current operating parameters. Only after setting the LD bit do any changes made to those registers take effect.
Can anyone confirm this is indeed the case? If this is NOT the case, can someone provide guidance on how and when to update the registers and/or the LD bit?
In particular, there is a several microsecond time period where the duty-cycle registers are being manipulated. That is: initial values are loaded into the duty-cycle HI and LO registers, then those values are manipulated. This might be a total time of 30us or so. Only after the register values are stable is the LD bit asserted.
Obviously, the PWM output is active during this time.
The glitches are regular (not periodic) but random. That might imply beating between the main loop period and PWM period - but then I would not expect the glitches to be random.
Any guidance appreciated.
Other information: no interrupts.
[Edit] One section of the relevant code is as follows:
SetPWM_Auto incf SPEED,W ;add offset (can't have zero duty-cycle skpnz movlw 0xFF ;don't allow speed to wrap to 0x00 SETBSR PSMC1DCH movwf RBS(PSMC1DCL) ;save speed in lo byte MULX132 RBS(PSMC1DCH), RBS(PSMC1DCL) ;w *132 -> dcH:dcL bsf BBS(_PSMC1LD) ;load steering and time buffers rampg0 goto SetPWMdone
The multiply macro:
MULX132 MACRO ACC1, ACC0 ;W * 132 -> ACC1:ACC0 ; enters with multiplicand in W ; exits with result in ACC1:ACC0 ; Written by Mike Rigby-Jones clrf ACC1 ; Clear MSB movwf ACC0 ; save W in ACC0 ; clrc ; use these instead of "lslf" for ; rlf ACC0,F ; non-enhanced PICs lslf ACC0,F ;C <- b7..b0 <- 0 rlf ACC1,F rlf ACC0,F rlf ACC1,F rlf ACC0,F rlf ACC1,F ; ACC1:ACC0 = 8 * input addwf ACC1,F ; C + ACC1:ACC0 = 264 * input rrf ACC1,F ; divide by 2 rrf ACC0,F ; ACC1:ACC0 = 132 * input 11 cy endm
My guess is that the registers within the PSMC are NOT properly double-buffered and that the duty-cycle is changing because the value in the DC register has intermediate values while the math is being done. About to try fixing that.