Library that allows for higher resolution and speed than standard mbed PWM library using same syntax (drop-in replacement).

Dependents:   PwmOscillator FastStepDriver TLC5940 CameraTest ... more

Issue: Sync Issue (Closed: Fixed)

I am using the FastPWM to produce a 50kHz PWM output on the KL25Z. I routinely change at regular intervals the duty cycle on the PWM output. I am using the pulsewidth() function as I do not want the period to change.

As the library suggests I set the period at the beginning of the code and I use double type variables throughout to maintain accuracy.

Each time the pulsewidth function is called the next PWM pulse is not in sync with the period of the previous (i.e it as if a new pulse train is initialized with the same period as before). Before and after the period is as expected.

Ideally the value of the pulsewidth should be changed and then only activated at the end of the previous pulse period. Apologies is this is my mistake through an incorrect use of this library

7 comments:

17 Mar 2014

/media/uploads/ProjectLemur/pwm_generation_issue.bmp

Above is an oscilloscope screenshot to illustrate the issue

17 Mar 2014

Hey,

On the LPC1768 a special sync register is written, which prevents this kind of behavior. On the KL25Z the code is:

void FastPWM::pulsewidth_ticks( uint32_t ticks ) {
    *(_pwm.CnV) = ticks;
    *_pwm.CNT = 0;  //Not yet sure why this is needed!
}

So when writing the new pulsewidth, it afterwards resets the count register. And as the code says, when I wrote it I didn't know why that was required :). It is a bit ago for me, but I just checked the datasheet, and according to that it should be automatically synced so this is not required, and it should behave like you want it to behave.

I will have a look at it and report back.

17 Mar 2014

Currently I am at:

http://www.explainxkcd.com/wiki/images/0/01/inexplicable.png

For you it might be handiest to go to the FastPWM_KLXX.cpp file, and delete line 3 in my previous post, then it should work.

The issue there is that without that line it will not work properly if within the same PWM period the pulsewidth or the period already has been changed. The CNT = 0 fixes that. Why it doesn't work? Not a clue, can't find it in the manual, and also not in errata sheet, but I guess it is something with the syncronisation logic.

Now there are two solutions: Waiting a full period, which would be very slow, or resetting the counter, which gives your issues. Solution three: Only reset the counter when it is required for it to accept the new value. (Could also wait, but still slow, and then I rather accept a glitch sometimes). Now the issue why I think my KL25 is haunted: I can detect when it happens. But if I use an if statement to only reset it if required, it doesn't work. Any if statement that isn't optimized away does not make the damn thing work properly. If I use an if statement to return, unless it needs to reset the counter, it still does not work.

17 Mar 2014

Thanks so much for the in depth reply. Fortunately I am only changing the PWM pulsewidth at a frequency of 1kHz, so deleting line 3 in your code should work for me as waiting for a period will have no effect. I will be able to test this tomorrow and report back. Thanks again for the in depth reply and the library itself, its proved really useful.

17 Mar 2014

Update: I managed to fix it in a quite weird way (not checking once if the new pulsewidth is loaded correctly, but twice). But then I had some issues with the period setting. Took me alot more time than it should have, since it happened to be a poorly implemented feature of my lib, where changing the period keeps the duty cycle the same, but the duty cycle isn't updated when the pulsewidth is changed.

There are multiple options to solve that, but in the end I just decided to change behavior of period changes: keep the pulsewidth equal instead of duty-cycle. There is something to say for both options, but I personally prefer this anyway. Programs which require the old behavior will have to keep using the old version.

The really weird part: all that stuff with the timer not properly updating is also gone. I have to admit I don't understand what it is doing exactly, but now it appears to work correctly simply with the CNT = 0 lines removed.

So it would be nice you can test it tomorrow properly :) (I have only tested it by flashing an LED and visually checking for glitches, I published the new version, so you can simply update the library). Maybe in a next version I will make it so changing the period keeps duty-cycle the same, if duty-cycle was the last thing changed, and pulsewidth, if pulse-width was the last thing changed. But that will be further in the future.

18 Mar 2014

Tested: The update seems to work fine with my set-up. So still generating a 50kHz PWM output and changing its variables at a 1kHz rate. As before the period is initialized at the start of the code and then in the 1kHz function the duty ratio oscillates between 0.3 and 0.7. The pulsewidth function is then use to execute the desired duty ratio using pulsewidth(PWM_period*duty) where duty is a decimal between 0 and 1. You can see in the scope capture below that the PWM period is 20us and so the frequency 50kHz and the duty ratio is changed seamlessly from 0.3 to 0.7. Let me know if you want some more testing on some of the other functions and see if they perform as expected.

/media/uploads/ProjectLemur/issue_resolved.bmp

18 Mar 2014

Thanks. And nop, I don't think I need anything else to be tested currently, this is the only thing changed, so other stuff shouldn't be affected :).

Going to figure out if I can set this as solved :)

Btw: If you have another time something like this, it is best to also send a PM. Simply because currently I don't get a mail when someone makes an issue, so if I miss it in the activity log, I will never notice it. It is on the mbeds team todo list now, so in the future I should get a mail.