Arm Mbed OS support forum

STM32F103, PWM very coarse

I am having trouble with the PWM. While it works, the resolution is very coarse. With 64kHz, the duty cycle (measured with a scope) stays the same for set values 0.51 … 0.56 (it seems to take 6.4% steps). with 32 kHz this is 3.2%. Indicating there is a fixed 1µs hiding somewhere.

I did try fast_PWM, however this killed the CAN bus.

Any suggestions ?

Code is fairly simple:

PwmOut PWM_Power(PA_9);
float switching_frequency = 50e3;

Using Visual Studio Code with PlatformIO.
platform = ststm32
board = bluepill_f103c8
framework = mbed

PS: really liking the experience with mbed so far!

I did some digging and found this in the pwmout_api.c:

/* By default use, 1us as SW pre-scaler */
obj->prescaler = 1;
// TIMxCLK = PCLKx when the APB prescaler = 1 else TIMxCLK = 2 * PCLKx
if (APBxCLKDivider == RCC_HCLK_DIV1) {
    TimHandle.Init.Prescaler = (((PclkFreq) / 1000000)) - 1; // 1 us tick
} else {
    TimHandle.Init.Prescaler = (((PclkFreq * 2) / 1000000)) - 1; // 1 us tick
TimHandle.Init.Period = (us - 1);

later on it is only checked if this is slow enough, never if this is fast enough.

Why was a 1µs tick chosen? If I read this correctly, we are limiting our PWM resolution to 1 MHz.

Search for the fastpwm library. You can set pulse width down to the clock tick with it.

As I mentioned, I did try fastpwm. But then the CAN Bus stops working.

Sorry I missed that. The standard mbed pwmout is very limiting and I ran into the same problem using the stm32f303 a couple years ago. I’ve never used the CAN bus. I did have some problems with I2C and fastPWM. Later I changed the PWM pin and it mysteriously worked. Perhaps they were on the same timer before switching pins?

The main timer in mbed is set to 1uS. Someone can probably answer better than me, but when you start messing with prescalers there can be unintended consequences. I think the 1uS timer settings has something to do with free-RTOS compatibility.