Page 1 of 1

Changing PWM duty cycle on BluePill produces wrong output

Posted: Sat Aug 01, 2020 9:30 am
by Leviro
Hi everyone!
I am working with STM32F103C8T6-BluePill to control the speed of a motor through PID (feedback from rotary encoder connected to the same STM32 board).

The problem is, the PID generates output so often (about 50~200 outputs/sec) and the PWM needs to be set to this value. But calls to analogWrite and setPWM with such small intervals seems to break it and causes it to produce wrong output.

To reproduce the problem,
Simply call setPWM with any duty cycle in setup and measure the output using a voltmeter.
Update the sketch and move setPWM to loop with small delay and measure the output again.
The values won't be the same.

Re: Changing PWM duty cycle on BluePill produces wrong output

Posted: Sat Aug 01, 2020 10:11 am
by stevestrong
viewtopic.php?f=2&t=301
Which core do you use?

Re: Changing PWM duty cycle on BluePill produces wrong output

Posted: Mon Aug 03, 2020 9:55 pm
by Leviro
This problem appears in the official core. But Roger Clark's core works fine and doesn't have this issue. However, the I2C is unstable in Roger Clark's core so I have to use the official core.

Re: Changing PWM duty cycle on BluePill produces wrong output

Posted: Tue Aug 04, 2020 3:57 am
by fpiSTM
Hi @Leviro , could you share the code you used, please?

Re: Changing PWM duty cycle on BluePill produces wrong output

Posted: Tue Aug 04, 2020 9:14 am
by ABOSTM
Hi @Leviro,
Difficult to know what appends to PWM with a voltmeter, If you can observe signal with oscilloscope that would be better.
That said, setPWM() is made for simplicity to start a PWM, but it is not designed to update a running PWM because it performs a full initialisation of the timer, and I suspect you have transition step which disrupt your PWM.
setPWM() could be kept for the 1st time PWM is start.
But as far as PWM updates is concerned, I suggest you to use setCaptureCompare() and setOverflow() to respectively update dutycylce and period.
It will be more efficient (just update the necessary register witout a full initialisation) and I hope it will solve your issue

Re: Changing PWM duty cycle on BluePill produces wrong output

Posted: Tue Aug 04, 2020 11:14 am
by ozcar
I tried it, repeatedly setting the frequency and duty cycle to the same value. If I happen to call setPWM() when the pulse is high, then it goes low for around 35 microseconds. It does not appear to disturb or reset the overall pulse though?? The time of this low glitch seems to be independent of the frequency or duty cycle, so if the frequency is low the glitches will not affect the average by very much, but for higher frequencies it could have a large effect.

I tried putting the call to setPWM() into the PeriodCallback function, and the low glitch is still there (but only once, around 6 microsecounds from the start of the pulse).

Re: Changing PWM duty cycle on BluePill produces wrong output

Posted: Tue Aug 04, 2020 6:13 pm
by Leviro
ABOSTM wrote: Tue Aug 04, 2020 9:14 am If you can observe signal with oscilloscope that would be better.
I don't have access to an oscilloscope right now thanks to COVID19. I will try using setCaptureCompare to change the duty cycle and see if it works.
Also, when I set my AVOmeter to measure "DC Voltage" and input a PWM signal, it seems to read the average correctly (or very approximately). That's what I meant by saying "measure using a voltmeter", sorry for the confusion.

Re: Changing PWM duty cycle on BluePill produces wrong output

Posted: Tue Aug 04, 2020 6:28 pm
by Leviro
fpiSTM wrote: Tue Aug 04, 2020 3:57 am Hi @Leviro , could you share the code you used, please?
I started with the example in the GitHub wiki, made the timer variable global, and used it to call setPWM in the loop:

Code: Select all

#define pin  PA3

TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pin), PinMap_PWM);
uint32_t channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pin), PinMap_PWM));
HardwareTimer *MyTim = new HardwareTimer(Instance);

void setup()
{
  
}


void loop()
{
  MyTim->setPWM(channel, pin, 5, 100);
  // delay(50);
}

Re: Changing PWM duty cycle on BluePill produces wrong output

Posted: Tue Aug 04, 2020 7:27 pm
by fredbox
Try this:

Move MyTim->setPWM() to setup.

Inside loop, call
MyTim->setCaptureCompare(channel, dutycycle, PERCENT_COMPARE_FORMAT)

I would keep dutycycle in the range of 1 to 99, avoiding 0 and 100.

Re: Changing PWM duty cycle on BluePill produces wrong output

Posted: Tue Aug 04, 2020 10:19 pm
by ozcar
Leviro wrote: Tue Aug 04, 2020 6:28 pm I started with the example in the GitHub wiki, made the timer variable global, and used it to call setPWM in the loop:
They say that great minds think alike – that is exactly what I tried.

My equipment does not run to an AVOmeter, but I do have an old analog meter. With 5HZ, and 10% as in the example, I measure close to the expected 0.33V when not calling setPWM() in the loop (at that frequency, the pointer does shudder a little).

If I put the same setPWM() call into the loop, with no added delay, then the voltage as measure on the meter drops down to around 0.08V. The DSO shows there are so many of the 35 microsecond lows in the pulse, that this is not surprising. If, however, I add a 5ms delay into the loop (you said you could update up to 200 times per second), then the DSO show only four 35 microsecond lows per 20ms pulse, which is not enough to make a noticeable difference on the analog meter – the pointer is still hovering around 0.33V.

So, I don’t totally understand why you saw the problem originally, but changing to use setCaptureCompare() does make the problem go away.