'Blackpill STM32F411CEU6 - PWM with libopencm3 not working

I'm trying to get PWM working with timer 3, I've followed the reference manual and believe i have everything correct but i get nothing on the output.

My code is below, I must be missing something

rcc_periph_clock_enable(RCC_GPIOB);
  gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
                  GPIO0 | GPIO4 | GPIO5);
  gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
                          GPIO0 | GPIO4 | GPIO5);
  gpio_set_af(GPIOB, GPIO_AF2, GPIO0 | GPIO4 | GPIO5);

  rcc_periph_clock_enable(RCC_TIM3);
  timer_set_mode(TIM3, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
  timer_set_prescaler(TIM3, 50000000 / 125000 - 1);

  timer_enable_preload(TIM3);
  timer_enable_oc_preload(TIM3, TIM_OC1);

  timer_set_period(TIM3, 0xffff);

  timer_enable_oc_output(TIM3, TIM_OC1);
  timer_set_oc_mode(TIM3, TIM_OC1, TIM_OCM_PWM2);
  // timer_set_oc_mode(TIM3, TIM_OC2, TIM_OCM_PWM2);
  // timer_set_oc_mode(TIM3, TIM_OC3, TIM_OCM_PWM2);

  timer_set_oc_value(TIM3, TIM_OC1, 0x7fff);
  timer_enable_update_event(TIM3);
  timer_generate_event(TIM3, TIM_EGR_UG);
  timer_enable_counter(TIM3);


Solution 1:[1]

A few things to bear in mind:

  • gpio_mode_setup() should use GPIO_MODE_AF, not GPIO_MODE_OUTPUT
  • some timers take only 16-bit counters, some are 32-bit. Double-check that your timer is suitable
  • different pins allow for various combinations of timer, channel, and alternate function number. Check the datasheet to ensure you're using the right values

Here's an example that outputs a frequency of 400Hz, 25% duty cycle to PA0 using TIM5 on an stm32f411re:

#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/timer.h>
#include <libopencm3/cm3/nvic.h>

// PA0 TIM5_CH1. AF2


const uint32_t timer_peri = TIM5; // timer peripheral
const enum tim_oc_id oc_id = TIM_OC1; // output compare channel designator

int main(void)
{

    // setup PA0 for PWM
    rcc_periph_clock_enable(RCC_GPIOA);
    rcc_periph_clock_enable(RCC_TIM5); // enable TIM clock
    gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO0); // pin PA11 Alt Function
    gpio_set_af(GPIOA, GPIO_AF2, GPIO0);

    int freq = 400;
    timer_set_prescaler(timer_peri, 16-1); // s/b 1MHz
    int period = 1000000/freq; // assumes prescaled set to 1MHz
    timer_enable_preload(timer_peri); // causes counter to be loaded from its ARR only at next update event
    timer_set_period(timer_peri, period); // set the timer period in the (ARR) auto-reload register
    timer_set_oc_value(timer_peri, oc_id, period * 1/4); // set duty cycle to 25%
    timer_set_counter(timer_peri, 0); // TIM_CNT
    
    timer_enable_oc_preload(timer_peri, oc_id);
    timer_set_oc_mode(timer_peri, oc_id, TIM_OCM_PWM1); // output active when counter is lt compare register
    timer_enable_oc_output(timer_peri, oc_id); // enable timer output compare
    timer_continuous_mode(timer_peri); // enable the timer to run continuously
    timer_generate_event(timer_peri, TIM_EGR_UG); // required!
    timer_enable_counter(timer_peri);
    //timer_enable_irq(timer_peri, TIM_DIER_COMIE);  //enable commutation interrupt
    //nvic_enable_irq(NVIC_TIM1_CC_IRQ);

    while (1);
}

Adapt it to your needs.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 blippy