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.

asked Jul 7, 2021 at 18:12
\$\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\$ 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\$ 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\$ 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.

answered Jul 8, 2021 at 16:00
\$\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\$ 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\$ Commented Jul 9, 2021 at 4:38

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.