You are here

Question about changing the PWM compare value | Cypress Semiconductor

Question about changing the PWM compare value

Summary: 6 Replies, Latest post by FredJM on 08 Nov 2012 03:06 PM PST
Verified Answers: 0
Last post
Log in to post new comments.
Doug McClean's picture
38 posts

When I call

void PWM_WriteCompare1(uint8/16 compare)

or one of the similar functions, does that new compare value have immediate effect? Or does it become effective the next time the counter rolls over?

If it's the former, how can I acheive the latter in a glitch-free way?

I am trying to control 8 hobby servos by demultiplexing the output of a single PWM generator. Every time the counter rolls over (every 2.5 ms), I redirect the multiplexer to the next output and load a new compare value. I am concerned that as my system becomes more complicated (it has a bunch of other things to do apart from babysitting these servos), it might take long enough to service the overflow interrupt to create really short pulses sent to channels that are supposed to be disabled entirely.

I have three ideas for dealing with this:

  1. Don't worry about it (PROS: Simple, CONS: Hard for me to assess with the equipment I have whether this is problematic or not. It might well work with the sample servos I have to test with and then cause glitchy problem later.)
  2. Add a control register with one bit for the enabled status of each channel, AND the control register with the outputs of the demultiplexer (PROS: Guarantees no glitches like this. CONS: Uses up a control register, might be completely unneccessary.)
  3. Change the software to perform these updates in the Interrupt On Compare 1 ISR instead of in the Interrupt On Terminal Count ISR. (PROS: Perfect if it works. CONS: Really bad if the update to the compare value has immediate effect, because if the upcoming channel is to receive a pulse longer than the one that was sent to this channel, this channel will end up glitched.)

The component datasheet appears to be silent on this question.

Other suggestions are welcome too.

dasg's picture
Cypress Employee
730 posts

Hi Doug McClean,


From the API Definition of PWM_1_WriteCompare1(compare), we can see that the compare value is updated immediately when the API is called.

It doesn't wait for the PWM counter to roll over.


void PWM_1_WriteCompare1(uint8 compare)
        CY_SET_REG16(PWM_1_COMPARE1_LSB_PTR, (uint16)compare);
        CY_SET_REG8(PWM_1_COMPARE1_LSB_PTR, compare);

One possible solution according to me would be to use a DMA channel which is triggered by the PWM's Terminal Count. The DMA transfers the Compare value stored in a memory location into the Compare Register of the PWM. It will consume less time than using an ISR to update the same.



Doug McClean's picture
38 posts

Hmm, the DMA idea is a good one, but if i undestand properly it will only shorten the glitch.

I am sending one pulse every 2.5ms, but luckily for me each channel will either get a pulse between 500us and 2250us or no pulse at all. Now that I think about it overnight, I think I can see a clean solution. (Which I will write here in case it can help anyone else)

In the compare ISR:

  • let n be the index of the next channel
  • update the control register for the demux to select channel n
  • iff the next channel should receive no pulse at all, set the compare register to equal the period of the PWM generator (since it is in "Greater" compare mode, this will result in no pulse at all)

In the overflow ISR:

  • set the compare register equal to the pulse length required for the current channel (perhaps conditionally on whether it was already done, although it doesn't matter if you do it always)

I think this always works, assuming the following timing. The compare ISR must be serviced within (2500us pwm period - 2250us longest possible pulse) = 250us; this is necessary to ensure that we don't emit a pulse at all if channel n requires one and channel n + 1 mod 8 does not require one. The overflow ISR (or DMA) must be serviced within 500us, because otherwise if channel n has a longer pulse and channel n + 1 mod 8 has the shortest pulse, channel n + 1 will receive too long of a pulse.

I could make it even safer by having the hardware interrupt or hardware tc line latched into a flip flop, such that it is set from when the TC occurs until the FW (through another bit of the same control register used for the demux) clears it. This would be used to drive the kill input. The ISR can disable the PWM (clearing bit 7 of the control register stops the PWM clock, if I understand properly), do what it needs to do, possibly PWM_WriteCounter(0) if it discovers that it has arrived "late", and move on with life. Then the worst that can happen is a delay in starting to generate the next pulse, which doesn't hurt my application.



All of that would fix it, but I just discovered the run mode setting. One-shot multi-trigger with the trigger coming from an auto-clearing bit in a control register that the TC ISR sets, and I get the same outcome as above but with none of the nonsense! Light dawns.

dasg's picture
Cypress Employee
730 posts



One-shot Multi trigger mode is similar to a mono-stable multivibrator. This may eliminate many issues in your case.

Doug McClean's picture
38 posts

What is meant by this sentence in the datasheet?

"The PWM outputs are double buffered to avoid glitches due to duty cycle
changes while running."

Doug McClean's picture
38 posts

Hmmm, actually there might be a documentation bug here.

The TRM (in section, subsection "On The Fly Duty Cycle Update", page 308 of revision E) says:

Support for multiple comparisons depends on the bit
CMP_BUFF in Configuration register CFG0. The following
describes the process:
■ When the CMP_BUFF is set to ‘1’; the updated comparator
value takes effect only after completion of the currently
running period. After the terminal count, the new
compare value is taken for further comparison. When
this mode is used, the PWM block detects only one compare
during a period.
■ When the CMP_BUFF is set to ‘0’; the updated comparator
value takes effect immediately even before the completion
of the current running period. This may result in
another toggling of the pin even before the completion of
current period, thus supporting multiple comparisons.

Of course, it's talking about the fixed function block. As nearly as I can tell by reading the generated C for my 16-bit fixed-function counter, this bit is set to 0? (It's certainly possible I misread it.)

It seems to me that the data sheet for the PWM component, quoted in my previous post, states that this bit is enabled. (You could argue it should be configurable.)

That still leaves open the question of whether the UDB implementation also supports this feature, and if so whether it is enabled by the component or not. Since the component datasheet seems to say that double-buffering is supported (without qualifying as to implementation) it seems that it should be?

There's more going on here than I first thought, it seems.

See also section 1.3.186, "TMR[0..3].CFG0 Configuration Register CFG0", page 297 of revision A in the PSoC 5 registers TRM.

FredJM's picture
19 posts

I have been bugged by the same kind of problem - about 7 years ago I did a project using PSoC 1, which I am now porting to PSoC 3 - I had solved the problem on the PSoC 1 but could not remember how I did.. After examining the original code I found that I fixed the problem with external glue logic which can be easily fitted in the PSoC 3..

On the original I used a SR latch, Compare output set the latch, TC reset it .. The output from the latch was glitch free - if a new compare value is written after the latch is set (after the compare output goes high) then whatever state the compare output goes to before TC is ignored.

I have not yet tested this with PSoC3 - I feel sure it will work in my application at least - and cannot see any reason it wont work as shown in attached .pdf.



Log in to post new comments.