4 years, 10 months ago.

Issue with STM32F769 PWM output when updated according to condition

I am using STM32F769 Disc board with Mbed online compiler. My task is to change the PWM frequency and duty ratio according to input. i created a simple algorithm according to my need, the program is working well but whenever the controller updates the PWM frequency, there is strange behavior(overlapped maybe, difficult to explain verbally for me), the frequency is changed instantly and the output is incorrect at that moment, for other controllers like aurdino, this never happens, the controller update value after the time period of PWM is over. But not in this case What can be wrong?

i thought to add a small delay before value is updated but that will not work, as every time a different delay would be needed. i have attached the code and screenshots.

  1. include "mbed.h"

AnalogIn analog_value(A0);

PwmOut pulse(D11);

int main() {

double meas_v=0; double out_freq,out_duty,s_time; while(1) {

meas_v = analog_value.read()* 3300; if(meas_v<1) { out_freq=50000; out_duty=40; }

else if(meas_v>=1000) { out_freq=100000; out_duty=80; } else { out_freq=50000+(meas_v*50); out_duty=40+(meas_v*0.04); }

pulse.period( 1.0 / out_freq); pulse=out_duty/100; s_time=0.0001; wait(s_time);

}

} The output should be updated after the current period is completed

1 Answer

4 years, 10 months ago.

In an earlier version of mbed-os 5 for STM32L476 device I observed that the PWM libraries were updating the duty cycle in a way that would introduce glitches when you change the duty cycle. When you loaded a new duty it would go through the whole pwm initialization again instead of just updating the duty CCR register.

It has been a couple years since I looked at this, but if it is misbehaving right when you change duty I would bet it is the same issue. The hardware has glitch-free capability it is just not being used that way.

You could try using the FastPWM library instead and see if that helps - its a different implementation but does the same thing. I believe this is it:

https://os.mbed.com/users/Sissors/code/FastPWM/

To update the duty on the fly all you have to do is write to the Timer CCR register. If you import the mbed source you can add a function to just load CCR.

   TimHandle.Instance->CCR1 = duty_as_integer;

I don't know about updating the Frequency on the Fly. That would seem to require reinitializing the Timer.

Edit

I confirmed the standard PwmOut is glitching sometimes for me when I change duty on higher frequency signals (image is 200kHz). However, given that you want to change Frequency too that is probably the bigger issue you're facing.

/media/uploads/Gobstopper/pwmglitch.png

I believe this can be solved by making a new class that inherits from PwmOut and then updating CCR register when duty changes. This works for me and I have not been able to find any glitches using this new class and write_smooth() method.

class PwmSmooth : public PwmOut {
public:
    /* Create a Glitch Free PWM that updates Timer CCR when duty changes
     *  @param pin PwmOut pin to connect to
     */
    PwmSmooth(PinName pin) :
        PwmOut(pin) {}
    

    /** Set the output duty-cycle, specified as a percentage (float) without Glitch
     *  @param value A floating-point value representing the output duty-cycle,
     *    specified as a percentage. The value should lie between
     *    0.0f (representing on 0%) and 1.0f (representing on 100%).
     *    Values outside this range will be saturated to 0.0f or 1.0f.
     */
    void write_smooth(float value) {
        core_util_critical_section_enter();
        lock_deep_sleep();
        pwmout_write_smooth (&_pwm, value);
        core_util_critical_section_exit();
    }

protected:
    /** Add pwm function, normally found in pwmout_api.c
     *  @param value A floating-point value representing the output duty-cycle,
     */
    void pwmout_write_smooth(pwmout_t *obj, float value) {

        // Get Timer Handle
        TIM_HandleTypeDef TimHandle;
        TimHandle.Instance = (TIM_TypeDef *)(obj->pwm);
    
        // Limit
        if (value < 0.0f) {
            value = 0.0f;
        } else if (value > 1.0f) {
            value = 1.0f;
        }
    
        // Convert to integer duty
        uint32_t pulse = (uint32_t)((float)obj->period * value + 0.5);
    
        TimHandle.Instance->CCR1 = pulse;
    }
};

Accepted Answer

Thank you.. The FastPWM solved my issue..

posted by Ali K 31 May 2019