PWM Period is not good on mbed with raspberry pico

Hi,
when using PWM with mbed on raspberry pico, the period only works fine from 10us to 2ms. If i use the SDK it works fine from 800ns to 133.7ms with 1% precision.

Here is the code

#include <mbed.h>

using namespace mbed;

PwmOut led(p27); // Sortie GPIO 27

void setup() {
  led.period_ms(1000); // Doesn't work, period is not good
  for(int i=0;i<3;i++) { // Blink 3 times
    led = 1;
    delay(200);
    led = 0;
    delay(200);
  }
}
// Duty cycle from 0 to 100% during 1s
void loop() {
  static int rapport=0;
  led=0.001*rapport;
  rapport = (rapport + 1)%1001;
  delay(1);
}

I use platformIO on VSCode for my project.
Sincerely
Olivier

Hello,

Targets in MbedOS are usually ported and maintained by (ST, NXP, Arduino…) their makers/creators or people/companies who want to have it in MbedOS officially and not Mbed team. So if there is a hardware specific issue it is up to that target’s maintainer.
With Raspberry Pi Pico it is little bit different. It is not Mbed enabled board and was never officially supported in ARM Mbed only in MbedCE. Here you can see a Pull request what was never finished. It was done only in a fork of Mbed OS in Arduino github repo - arduino/mbed-os: Arm Mbed OS is a platform operating system designed for the internet of things (github.com)

So how you can see you are on wrong forum.

Btw you can try to check the PWM implementation and make a PR for fix (if you tried it witk SDK maybe you will find something wrong).

I also somewhere read about much more better is a solution by Earle Philhower. So maybe try to check if is possible to use it in PlatformIO.

BR, Jan

Could you share the code that you used with the Pico SDK that works as expected?

Looking at the mbed driver code, I do see some weirdness.

First of all, the code doesn’t properly handle periods smaller than about 10us, because doing that would require using a smaller count_top constant (the value at which the PWM counter resets), which it isn’t smart enough to do. Additionally, with count_top fixed to 1000, and a max clock divider of 256, the longest possible duty cycle is 1/(133MHz / 256 / 1000) = ~2ms.

It also has resolution problems – it doesn’t use the fractional part of the clock divider pwm_config_set_clkdiv_int_frac(), so the frequency resolution is lower than it could be. Additionally, with count_top locked to 1000, the duty cycle resolution is locked to 1/1000, when it could be 1/65536 (using the full 16 bit counter).

I think this code should be updated so that it dynamically determines count_top based on the frequency. It should use count_top = 65536 in most cases, but if the calculated clock divider would be less than 1, it should decrease count_top as needed so that the lower period can be accommodated. That should restore the full frequency range.

2 Likes

Here is the code

#include <Arduino.h>

void setup() {
  gpio_set_function(0, GPIO_FUNC_PWM); // GPIO 0 used
  int slice=pwm_gpio_to_slice_num(0);
  pwm_set_clkdiv(slice,125); // Divide by 125 (float from 1 to 256 max)
  // TOP Value between 0 and 65535 so here frequency is 1Mhz period of 10ns
  pwm_set_wrap(slice,19999); // TOP value 19999 so 20000 countsx10ns=20ms   
  pwm_set_chan_level(slice,PWM_CHAN_A,9999); // 19999/2=50% duty cycle
  pwm_set_enabled(slice,true); // Enable PWM
}

Frequency is 125Mhz not 133Mhz on Pico. It can go up to 133Mhz (or even more but no guarantee it will work longtime).

ok I’m going to look into this. First PR: Enable RPi Pico's optimized ROM floating point routines by multiplemonomials · Pull Request #202 · mbed-ce/mbed-os · GitHub

Also yea ur right, it’s 125 MHz in code, I must have copied the wrong value to the Mbed CE wiki page.

@Olivier_Corrio Would you be able to test this patch for me? I think it should work but have not tested it yet.

Update: I tested it myself, and it is now working after some math fixes! The linked PR should work to fix your issue.

1 Like

It doesn’t seem to work with mbed version provided with platformIO

Some facts.

  • The fix from above was done in Mbed fork called MbedCE . This fork was created because original Mbed stopped their work. Unfortunately this fork is not used by Arduino or PlatformIO.
  • PlatformIO uses original Mbed, but this one does not contain RP Pico support
  • PlatformIO probably uses also Arduino-Mbed-Core which contains RP Pico and was done by Arduino for Arduino

How you can see there is no way how you can get this fix into PlatformIO for now. You have to ask a PlatformIO support probably.

BR, Jan

I just saw your PlatformIO issue - PWM period doesn’t work with mbed proveded with platformIO · Issue #7796 · platformio/platformio-home (github.com)
But to be honest it seems like you will not get any answer soon -according to states of 2000+ issues and most of them (from last months) are without any answer for months.

BR, Jan

Yes thanks. To be honest, it is not for my own purpose, but for a courses i give, and it is a bit a pity to say that it is buggy and to use the pico_sdk to do it.

If i knew where the code is, i would have done it by myself to have this old code updated.

Here’s the diff, if you’d like to apply it to another repo: Increase RPi Pico PWM range and resolution to the max supported by HW by multiplemonomials · Pull Request #203 · mbed-ce/mbed-os · GitHub