2
votes

I'm trying to get PWM functioning on two pins of my STM32030R8T6, it's on a Nucleo development board and I'm using Keil. For learning, I've mostly been following the material on this website, but with adaptations as that site uses a different MCU. There really isn't much to setting up the PWM so I'm not quite sure what I've done wrong, I know the timer is working because the on-board LED blinks 1.5 times per second, but when I monitor the Ch1 and Ch2 output pins with my scope I get nothing. I'm pretty sure the pins are correctly set in Alternate Function Push-Pull because they're set the same as the MCO pin which is functioning and showing 24 MHz (Though my cheap scope has some problems determining that...). I've attached all of my relevant and even remotely possibly relevant code. And for your convenience:

UM0360 Reference Manual (STM32F030...)

I'd post links to the Nucleo User Manual and Device Datasheet as well but I can't post more than two links, since this is my first question and my reputation is less than ten.

Any help on what I might be doing wrong is appreciated, I'm sure it's something stupid.

#include "stm32f0xx.h"

void Initializations(void);

int main(void)
{
    Initializations();

    while(1)
    {
        /*  Toggle onboard LED whenever timer overflows */
        if((TIM3->SR & TIM_SR_UIF))
        {
            TIM3->SR &= ~TIM_SR_UIF;
            GPIOA->ODR ^= GPIO_ODR_5;
        }           
    }
}

void Initializations(void)
{ 
    /*  CLK CONFIG  */
    RCC->CFGR |= RCC_CFGR_HPRE_DIV2  |
                 RCC_CFGR_PPRE_DIV16 |
                 RCC_CFGR_MCO_SYSCLK |
                 RCC_CFGR_PLLMUL6; 

    /*  Activate PLL, wait  */
    RCC->CR |= RCC_CR_PLLON;
    while(!(RCC->CR & RCC_CR_PLLRDY));
    RCC->CFGR |= RCC_CFGR_SW_PLL;

    /*  Enable IO CLKs  */
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
    RCC->AHBENR |= RCC_AHBENR_GPIOCEN;

    /*  Enable peripheral CLKs  */
    RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;

    /*  PIN INITIALIZATIONS */
    GPIOA->MODER |= GPIO_MODER_MODER5_0 |       // Onboard LED (General output)
                    GPIO_MODER_MODER2_1 |       // USART2 TX (Alternate function)
                    GPIO_MODER_MODER3_1 |       // USART2 RX (Alternate function)
                    GPIO_MODER_MODER6_1 |       // TIM3 CH1 (Alternate function)
                    GPIO_MODER_MODER7_1 |       // TIM3 CH2 (Alternate function)
                    GPIO_MODER_MODER8_1 |       // MCO (Alternate function)
                    GPIO_MODER_MODER9_1 |       // USART1 TX (Alternate function)
                    GPIO_MODER_MODER10_1;       // USART1 RX (Alternate function)

    /*  TIMER INITS */
    TIM3->PSC = 7;
    TIM3->ARR = 59999;

    /*  CCM1    */
    TIM3->CCMR1 |= TIM_CCMR1_OC1M_0 | 
                   TIM_CCMR1_OC1M_1;

    TIM3->CCR1 |= 4499;
    TIM3->CCER |= TIM_CCER_CC1E;                // Enable Ch1

    /*  CCM2    */
    TIM3->CCMR1 |= TIM_CCMR1_OC2M_0 | 
                   TIM_CCMR1_OC2M_1;

    TIM3->CCR2 |= 29999;
    TIM3->CCER |= TIM_CCER_CC2E;                // Enable Ch2

    TIM3->CR1 |= TIM_CR1_CEN;                   // Enable TIM3

    /*  USART INITS */
    RCC->CFGR3 |= RCC_CFGR3_USART1SW_0;         // Clock USART1 from SYSCLK
}
1
Are you trying to avoid using interrupts?bunkerdive
Also, do you have an equivalent of RCC->APB2ENR |= RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN; for enabling your respective port, and alternate function block?bunkerdive
Yes, it's in the AHBENR register on this MCU, and even though the bit is still IOPxEN, it's the compiler takes GPIOxEN instead. They're both the same number.Unit_One

1 Answers

2
votes

In addition to setting the pin to use an alternate function, you must also set which alternate function to use.

This is described in section 8.3.2 (pdf page 128) of the document you linked.

These are the AFRL (for pins 0-7) and AFRH (for pins 8-15) registers on the port.

For example, based on your code, and if TIM3 uses alternate function 2 and is on pins 6 and 7, (and assuming the alternate code was currently 0) you'd do

GPIOA->AFRL |= (2 << (6 * 4)) | (2 << (7 * 4));

If it isn't 0 or you want to be sure, mask off the bits first (each pin gets 4 bits).

(Note, your header may name registers differently than mine, and your alternate functions may also be different; I usually work with STM32F407 or STM32F334. To find the table of alternate functions to see which one you need, you'll have to look that up in the datasheet for the particular chip you are using, as opposed to the family reference manual which you linked above)

The more general form is

mode << (pin * 4)

for AFRL and

mode << ((pin - 8) * 4)

for AFRH.