cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F0: Getting PWM Output to Work

upgrdman
Associate II
Posted on October 08, 2012 at 05:20

I can get PWM output to work with my F4 MCUs, but I can't get it to work with the F0. My code is below, any ideas? As you can see, I'm not using the STM libraries, I am only using their stm32f0xx.h header for register definitions.

#include ''stm32f0xx.h''

#include ''core_cm0.h''

void TIM1_BRK_UP_TRG_COM_IRQHandler();                      // ISR prototype

int main() {

    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;                      // Enable GPIOA clock

    GPIOA->MODER |= GPIO_MODER_MODER8_1;                    // Pin A8 mode = Alt Function

    GPIOA->AFR[1] |= 0b0010;                                // Pin A8 alt function = AF2 (TIM1)

    GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8;               // Pin A8 speed = 50MHz

    RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;                     // Enable clock

    TIM1->PSC = 23;                                         // Prescaler = 23 (1 tick per half microsecond)

    TIM1->ARR = 19999;                                      // Auto-reload = PWM frequency in half microseconds = 10ms period

    TIM1->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;     // OC1M = 110 for PWM Mode 1 output on ch1

    TIM1->CCMR1 |= TIM_CCMR1_OC1PE;                         // Output 1 preload enable

    TIM1->CR1 |= TIM_CR1_ARPE;                              // Auto-reload preload enable

    TIM1->CCER |= TIM_CCER_CC1E;                            // Enable output for ch1

    TIM1->CCR1 = 1800;                                      // CCR1 = Duty cycle in half microseconds = high for 900us

    TIM1->EGR |= TIM_EGR_UG;                                // Force update

    TIM1->SR &= ~TIM_SR_UIF;                                // Clear the update flag

    TIM1->DIER |= TIM_DIER_UIE;                             // Enable interrupt on update event

    NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);               // Enable IRQ

    TIM1->CR1 |= TIM_CR1_CEN;                               // Enable counter

    while(1) {

    }

}

void TIM1_BRK_UP_TRG_COM_IRQHandler() {

    if(TIM1->SR & TIM_SR_UIF != 0) {                        // If update flag is set

        // do stuff here if needed

    }

    TIM1->SR &= ~TIM_SR_UIF;                                // Interrupt has been handled

}
2 REPLIES 2
frankmeyer9
Associate II
Posted on October 08, 2012 at 10:55

I can recommend a working example from the StdPeripheralLibrary.

There is a ''TIM_PWM_Output'' called project, that does exactly this for 4 channels at once.

It is based on the Periph.DriverLib however. You can strip it down and extract the relevant code if you like.

upgrdman
Associate II
Posted on October 11, 2012 at 06:43

After about an hour of printing out register values with GDB and comparing my values with the known-good values used in the STM PWM example, I found my error.

Too simple: when using the advanced timer you must set the MOE main output enable bit. Turns out I wasn't using an advanced timer on my F4's, and made a poor assumption when setting up PWM on my F0 🙂

-Farrell