I was playing with PWM on the RP2040. I can do square waves, but pretty much everything else does not work. I have recorded the PWM output with a sound card at 44100 Hz in order to verify it visually. (PIN 0 and GND are directly connected to Line In of the sound card.)

The square wave output looks pretty good (the highlighted selection is exactly 100 samples): square wave

The sawtooth wave does not come out as such at all: sawtooth wave

What am I doing wrong?

The code:

#define SYS_CLOCK_KHZ 133000
#define AUDIO_PIN 0

void on_pwm_wrap() {
  const static bool sawtooth = true;
  const static int period = 100;
  static uint32_t i = 0;
  uint16_t level = sawtooth
    ? (i % period) * (65535/(period-1))       // sawtooth
    : (i % period) >= (period/2) ? 65535 : 0; // square
  pwm_set_gpio_level(AUDIO_PIN, level);

int main() {
  set_sys_clock_khz(SYS_CLOCK_KHZ, true);
  gpio_set_function(AUDIO_PIN, GPIO_FUNC_PWM);
  uint slice_num = pwm_gpio_to_slice_num(AUDIO_PIN);

  pwm_set_irq_enabled(slice_num, true);
  irq_set_exclusive_handler(PWM_IRQ_WRAP, on_pwm_wrap);
  irq_set_enabled(PWM_IRQ_WRAP, true);

  pwm_config config = pwm_get_default_config();
  // 3,015 * 1.00029 * 44,100 = 133,000,000
  pwm_config_set_clkdiv(&config, 1.00029f);
  pwm_config_set_wrap(&config, 3015);
  pwm_init(slice_num, &config, true);

  while (1)
  • Which saw tooth sig gen you are using, this one: Arbitrary Wave Generator With the Raspberry Pi Pico? instructables.com/…
    – tlfong01
    May 28 at 6:09
  • Why such a complicated way of setting level? What are you trying to do? It seems a long winded way of deciding if level should be 0 or 1.
    – joan
    May 28 at 8:33
  • @tlfong01 The hardware and software I'm using is described in my question. I'm not using anything else. The board the RP2040 sits on - although that should not matter, as I'm using the pico-sdk and RP2040 features only - is a Seeeduino XIAO. May 28 at 22:52
  • @joan I'm using these formulas for square and sawtooth waves so that I can change the frequency by simply changing the period variable. May 28 at 22:54
  • 1
    @Evgeniy Berezovsky: I guess you might have misunderstood the things that Pico GPIO pins can do. Either Rpi or Pico GPIO pins are digital pins which can do PWM which can dim LEDs, effectively like an analog pin, but they are still digital pins. In other words, any GPIO pins can switch between 0V and 3V3 at the frequency you like, but you cannot set them at an analogue value, eg say 0.5V or 1.8V.
    – tlfong01
    May 29 at 3:46

1 Answer 1


My mistake was that I believed I could choose arbitrary values from 0 to 65535 for the gpio level, judging from the signature:

static void pwm_set_gpio_level(uint gpio, uint16_t level)   

But the level needs to be <= wrap + 1, and wrap is 3015 in my case. By changing the 65535 to 3016:

    ? (i % period) * (3016/(period-1))       // sawtooth

I get the expected sawtooth: sawtooth


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.