Wrong (duplicated) PWM pulse
I'm a software developer and love electronics, specifically making metal detectors. I'm trying to develop a new Pulse Induction metal detector and I'm using this development board (STM32F407VET6).
Although I'm a software developer, I work with high level programming languages like Javascript and Python, so programming in plain C (register manipulation) is not easy for me, but I want to learn, so, I'm building the code with the help of AI (ChatGpt).
The code below is supposed to generate 2 pulses with PWM inside a 1ms pulse period. One pulse is 100us (or the metal detector TX pulse) generated to PE13 and another is 500us (for the metal detector power supply charge pump) generated to PA8.
I tested the pulse generation with an oscilloscope 100uS/Div and the first pulse is correct (100us) but it appears one time at the start and another at the end of the and it should appear only one time at the start of the period. I tried everything with the IA but I can't solve this problem and don't understand why it happens.
So, can someone look at my code and give an idea of the problem source?
#include "stm32f4xx.h"
// Function Prototypes
void SystemClock_Config(void);
void GPIO_Init(void);
void TIM1_PWM_Init(void);
int main(void) {
// Configure system clock
SystemClock_Config();
// Initialize GPIO (PE13 as TIM1_CH3 Alternate Function)
GPIO_Init();
// Initialize TIM1 for PWM on PE13
TIM1_PWM_Init();
while (1) {
// PWM runs automatically in hardware
}
}
void SystemClock_Config(void) {
// Enable HSE (High-Speed External Clock)
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY)); // Wait for HSE to be ready
// Configure PLL: PLL_M = 8, PLL_N = 336, PLL_P = 2, PLL_Q = 7
RCC->PLLCFGR = (8 << RCC_PLLCFGR_PLLM_Pos) | // PLLM = 8
(336 << RCC_PLLCFGR_PLLN_Pos) | // PLLN = 336
(0 << RCC_PLLCFGR_PLLP_Pos) | // PLLP = 2 (00)
(7 << RCC_PLLCFGR_PLLQ_Pos) | // PLLQ = 7
RCC_PLLCFGR_PLLSRC_HSE; // Use HSE as PLL source
// Enable PLL
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY)); // Wait for PLL to lock
// Set Flash Latency and Enable Prefetch Buffer
FLASH->ACR |= FLASH_ACR_LATENCY_5WS | FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN;
// Set system clock to PLL
RCC->CFGR |= RCC_CFGR_SW_PLL;
while (!(RCC->CFGR & RCC_CFGR_SWS_PLL)); // Wait for PLL to be used as SYSCLK
// Set AHB = 168 MHz, APB1 = 42 MHz, APB2 = 84 MHz
RCC->CFGR |= RCC_CFGR_HPRE_DIV1; // AHB Prescaler = 1
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; // APB1 Prescaler = 4 (42 MHz)
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; // APB2 Prescaler = 2 (84 MHz)
}
void GPIO_Init(void) {
// Habilitar clock dos GPIOs A e E
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOEEN;
// Configurar PE13 como função alternativa (TIM1_CH3)
GPIOE->MODER &= ~(3 << (13 * 2));
GPIOE->MODER |= (2 << (13 * 2));
GPIOE->OSPEEDR |= (3 << (13 * 2)); // Alta velocidade
GPIOE->AFR[1] &= ~(0xF << ((13 - 8) * 4));
GPIOE->AFR[1] |= (1 << ((13 - 8) * 4)); // AF1 - TIM1_CH3
// Configurar PA8 como função alternativa (TIM1_CH1)
GPIOA->MODER &= ~(3 << (8 * 2));
GPIOA->MODER |= (2 << (8 * 2));
GPIOA->OSPEEDR |= (3 << (8 * 2)); // Alta velocidade
GPIOA->AFR[1] &= ~(0xF << ((8 - 8) * 4));
GPIOA->AFR[1] |= (1 << ((8 - 8) * 4)); // AF1 - TIM1_CH1
}
// testar abaixo (foi removido o charge pump pra teste tambem)
void TIM1_PWM_Init(void) {
// Enable TIM1 clock
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
// Set TIM1 Prescaler for 1 MHz Timer Clock (168 MHz / 168 = 1 MHz)
TIM1->PSC = (84 * 2) - 1;
// Set TIM1 Period for 1 kHz PRF (1 ms period)
TIM1->ARR = 999;
// Set Duty Cycle to 100 µs Pulse Width (10% of 1 ms)
TIM1->CCR3 = 100;
// Configure PWM Mode 1 (edge-aligned)
TIM1->CCMR2 &= ~TIM_CCMR2_OC3M;
TIM1->CCMR2 |= (6 << TIM_CCMR2_OC3M_Pos); // PWM mode 1
TIM1->CCMR2 |= TIM_CCMR2_OC3PE; // Enable preload
// Set output polarity (active high)
TIM1->CCER &= ~TIM_CCER_CC3P;
TIM1->CCER |= TIM_CCER_CC3E; // Enable output
// Force edge-aligned mode
TIM1->CR1 &= ~TIM_CR1_CMS; // Up-counting mode
TIM1->CR1 |= TIM_CR1_ARPE; // Auto-reload preload enable
// Main output enable
TIM1->BDTR |= TIM_BDTR_MOE;
// Generate update event to load all settings
TIM1->EGR |= TIM_EGR_UG;
// Start timer
TIM1->CR1 |= TIM_CR1_CEN;
}Please don't mind the code comments.
Thanks!

