7 years, 4 months ago.

PWM frequency unstable when reading data in COM port

hi everyone

first i'm french sorry for my english is bad ^^

i have a critical time application that require a stable PWM frequency but when i'm reading data from PC trough com port the frequency become very unstable i have no idea why where i'm wrong ? thanks for help

This is my code

#include "mbed.h"

Serial COM(USBTX, USBRX);
DigitalOut pc_activity(LED1);
PwmOut rpm_pulse(D5);
//PwmOut air_pwm(D2);

int serial_byte;

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

int main()
{
  COM.baud(115200);
  COM.format(8, SerialBase::None, 1);
  

    while(1) {
    
        
        if(COM.readable()){
            pc_activity = !pc_activity;
         
            serial_byte = COM.getc();
           
            if(serial_byte != 0xFF){
               return;
               }
               
               serial_byte = COM.getc();
               
               if(serial_byte != 0x02){
               return;
               }
               
            int speed_kph            = COM.getc(); 
            int speed_decimal        = COM.getc(); 
            int lsb_rpm              = COM.getc();
            int msb_rpm              = COM.getc(); 
            int air_pressure         = COM.getc();
            int fuel                 = COM.getc(); 
            int oil_pressure         = COM.getc(); 
            int water_temperature    = COM.getc(); 
            int batterie_voltage     = COM.getc();
            int engine_gear          = COM.getc(); 
            int retarder_steps       = COM.getc(); 
            int oil_temperature      = COM.getc();
            int OCTET_0              = COM.getc(); 
            int OCTET_1              = COM.getc(); 
            int OCTET_2              = COM.getc();
            
            int rpm = msb_rpm;
            rpm = rpm <<8;
            rpm = rpm + lsb_rpm;

//------------------------------------------------------------------------------------------------------------------------------- 

            if (rpm > 200){
                rpm = map(rpm, 200, 3000, 20, 1000); 
                float period = 1.0f/rpm;
                rpm_pulse.period(period);
                rpm_pulse.write(0.50f);  
            }  
           
            air_pressure = map(air_pressure, 0, 140, 0, 100);   
            float air_press = air_pressure /100.0f;

            oil_pressure = map(oil_pressure, 0, 86, 0, 100);   
            float oil_press = oil_pressure /100.0f;
           
           
            
            air_pwm.period(0.0025f);
            air_pwm.write(oil_press);

        }
    }
}

Please add <<code>> and <</code>> at separate lines to make it readable. Also can you clarify what you mean by unstable? And which device is this?

posted by Erik - 21 Dec 2016

sorry the code is readable now i use a nucleo f446RE i maybe found the solution it seems to be when i write all the time the same frequency for exemple

here i say rpm = 500 during 1 min with this code the frequency is unstable around 125 - 180 Hz

if (rpm > 200){
                rpm = map(rpm, 200, 3000, 20, 1000); 
                float period = 1.0f/rpm;
                rpm_pulse.period(period);
                rpm_pulse.write(0.50f);  
            }

but with this code the problem seems to be solved

if ((rpm > 200) && (rpm != prev_rpm)){
                prev_rpm = rpm;
                long  map = (rpm - 200) * (1000 - 20) / (3000 - 200) + 20;
                float period = 1.0f/map;
                rpm_pulse.period(period);
                rpm_pulse.write(0.50f); 
                 
            }

i never saw that ^^

posted by olivier flayols 21 Dec 2016

1 Answer

7 years, 4 months ago.

In addition what you found, have a look at FastPWM: https://developer.mbed.org/users/Sissors/code/FastPWM/ (too lazy to check if your device is supported, but otherwise it is fairly easy to add, might even be that the F401 code supports it). It generally handles changing settings of PWM better than the standard mbed code with less/no glitches.

Accepted Answer

Hi,

Thanks ! it's working much better :) but is it normal that i have to /2 the period to obtain the same frequency i had with mbed PWM library ?

  if ((rpm > 200) && (rpm != prev_rpm)){
                prev_rpm = rpm;
                rpm = map(rpm, 200, 3000, 20, 1000);  
                float period = (1.000000f/rpm)/2;
                rpm_pulse.period_us(double(period)*1000000);
                rpm_pulse.write(0.50f); 
                 
            } 
posted by olivier flayols 22 Dec 2016

You are the second one who has noticed it, sadly also on a device I don't have. I will during the holidays see if I can reproduce it on my F401. Apparently it happens on some PWM units, but not on all PWM units. So I guess some have a different prescaler/input clock than others, and I will need to figure that out and get a fix for it in.

Which pin do you use?

posted by Erik - 22 Dec 2016

Hi, it happen on pin D9 and D14

posted by olivier flayols 23 Dec 2016

Pfff I did figure out that on some STM boards some timers have a divide by two from the main clock. On some of these boards that should can be disabled (and might be already in the mbed code), on others it cannot be disabled. So then we have timers running at different frequencies. Compensating for the div2 is easy enough, but I wonder if there is a nice way to do it instead of having to add another list if if then else.

posted by Erik - 31 Dec 2016

Problem should be fixed, let me know if that is not the case for you after updating (right mouse button on the lib, update). By default mbed lib sets the PWM at 50Hz. Now FastPWM reads the prescaler/timer values and uses that to calculate if an additional prescaler is active. If yes it compensates its future calculations.

posted by Erik - 01 Jan 2017

Hi, Thanks, i will test soon :)

posted by olivier flayols 02 Jan 2017