2
\$\begingroup\$

I've been practicing bare-metal programming with a custom board that I bought from a friend.

My idea is to control a LED brightness, connected to the pin PA4, over pwm. After flashing the device (STM32F042F4), the LED doesn't change its brightness, it remains turned off.

I used the following configurations:

  • General purpose timer 14 in PWM mode 1 and clocked by HSI source (8MHz);
  • PA4 selected as alternate function 4 (TIM14 Channel 1) and clocked by HSI source (8MHz) as well;

The code is shown below. I used the example provided in the reference manual as a guide.

#include "stm32f042x6.h"


void ConfigurePA4asAF2()
{
    // enabling clock of GPIOA
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN_Msk;

    GPIOA->MODER |= GPIO_MODER_MODER4_1; // alternate function
    GPIOA->OTYPER &= ~GPIO_OTYPER_OT_4; // push-pull
    GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEEDR4_1; // low speed
    GPIOA->PUPDR |= GPIO_PUPDR_PUPDR4_1; // pull-down

    GPIOA->AFR[0] |= GPIO_AFRL_AFSEL4; //Alternate function 4, TIM14_CH1
}

void ConfigureTIM14()
{

    //Enabling TIM14 clock
    RCC->APB1ENR |= RCC_APB1ENR_TIM14EN;

    TIM14->PSC = 7; // Pre scaler (PSC + 1), PSC final value = 8, CC module clock = 1MHz 
    TIM14->ARR = 1000-1; // auto reload value, period of PWM
    TIM14->CCR1 = 500-1; // capture compare register, DutyCycle = 50%
    TIM14->CCMR1 |= TIM_CCMR1_OC1M_2 + TIM_CCMR1_OC1M_1 + TIM_CCMR1_OC1PE; // (PWM mode 1)
    TIM14->CCER |= TIM_CCER_CC1E; //capture compare enable

    TIM14->BDTR |= TIM_BDTR_MOE;

    TIM14->EGR |= TIM_EGR_UG;
    TIM14->CR1 |= TIM_CR1_CEN; //Enabling timer
}


int main(void)
{
    ConfigurePA4asAF2();
    ConfigureTIM14();

    while(1);

    return 0;
}

In the example provided by the documentation (A.9.8 Edge-aligned PWM configuration example), the bit TIM_BDTR_MOE is set on register BDTR, and the description of this line says: "(6) Enable output (MOE = 1)".

However, Timer 14 doesn't have the register BDTR, does it mean that it's impossible to output pwm signal over PA4?

PS: My board doesn't support debugging feature.

\$\endgroup\$
8
  • \$\begingroup\$ MOE is for timers with motor control capabilities (TIM1 I suppose). because of safety, for these timers, the output is not enabled by default (the motor is "brake"d) and has to be enabled by MOE bit. however that wouldn't apply to simpler timers like TIM14. \$\endgroup\$ Commented Jul 7, 2021 at 18:46
  • \$\begingroup\$ @TirdadSadriNejad, so is the timer 14 unable to naturally output pwm signal over its channel? or is just a safe feature of advanced timers? \$\endgroup\$
    – andre.hre
    Commented Jul 7, 2021 at 18:58
  • \$\begingroup\$ no no. I mean you don't need to set this bit for this timer. setting appropriate bits in CCER register would suffice and it will output on that pin. (I haven't checked the code you provided yet) \$\endgroup\$ Commented Jul 7, 2021 at 19:45
  • \$\begingroup\$ Start with HAL project as that is just as bare metal as your code, and see how it writes to registers first, then do the same without HAL. Have you debugged this in any way, like is it a problem of timer not running or just not causing the PWM to be output? \$\endgroup\$
    – Justme
    Commented Jul 7, 2021 at 19:54
  • \$\begingroup\$ Start a debugging session and check if the TIM registers have correct/intended values and the timer is running. Also, prefer | instead of + for using multiple flags at the same time. \$\endgroup\$
    – Tagli
    Commented Jul 8, 2021 at 11:22

1 Answer 1

1
\$\begingroup\$

It seems there are some errors in your bit field access codes. Try these code snippets:

For configuring GPIO:

RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
__DSB();
GPIOA->AFR[0] |= (4u << GPIO_AFRL_AFSEL4_Pos); // 4u means AF4
GPIOA->MODER |= (0b10u << GPIO_MODER_MODE4_Pos); // 0b10u means AF

For configuring TIM14:

RCC->APB1ENR |= RCC_APB1ENR_TIM14EN;
__DSB();
TIM14->PSC = 7;
TIM14->ARR = 1000 - 1;
TIM14->CCR1 = 500 - 1;
TIM14->CCMR1 |= (0b110u << TIM_CCMR1_OC1M_Pos) // 0b110u means PWM mode 1
             | TIM_CCMR1_OC1PE;
TIM14->CCER |= TIM_CCER_CC1E;
TIM14->EGR |= TIM_EGR_UG;
TIM14->CR1 |= TIM_CR1_CEN;

I haven't tested these code snippets. I guess your TIM code was OK, but the main problem was the wrong GPIO AF configuration.

\$\endgroup\$
2
  • \$\begingroup\$ Wow, surgical precision. Thanks a lot for your help. I searched for the function __DSB(), however, I didn't understand very well its application. Could you help me understand it? \$\endgroup\$
    – andre.hre
    Commented Jul 8, 2021 at 23:59
  • \$\begingroup\$ Actually, it's related with F4 series, where the errata sheet suggest adding some delay after enabling the peripheral clock and before accessing its registers. It's probably not needed for F0 series, but I made it a habit to add it anyways, to reduce the risk of problems if I copy & paste code from my F0 projects to my F4 projects. \$\endgroup\$
    – Tagli
    Commented Jul 9, 2021 at 4:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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