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.
1 Answer 1
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.
-
\$\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– andre.hre2021年07月08日 23:59:07 +00:00Commented 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– Tagli2021年07月09日 04:38:07 +00:00Commented Jul 9, 2021 at 4:38
|
instead of+
for using multiple flags at the same time. \$\endgroup\$