2024-11-15 05:04 PM - edited 2024-11-15 05:08 PM
I'm working with an STM32H743 and trying to generate a PWM signal (Center Aligned) on PE9 using Timer1 (TIM1). Although the PWM output is functioning, the frequency is not what I expect. I’m trying to generate a 1 kHz signal, but instead, I’m getting around 833 Hz, and I’ve confirmed that the period is incorrect.This is for driving a stepper motor.
- My Code
#include <Arduino.h>
HardwareSerial SerialDebug(PA3, PA2);
const uint8_t PIN_STEP = PE9;
const uint8_t PIN_DIR = PE10;
const uint8_t PIN_ENA = PE7;
void setupTimer1()
{
// Enable clocks
__HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
// Get actual timer clock frequency
uint32_t pclk2 = HAL_RCC_GetPCLK2Freq();
uint32_t pclk1 = HAL_RCC_GetPCLK1Freq();
uint32_t timclk = HAL_RCC_GetHCLKFreq();
uint32_t sysclk = HAL_RCC_GetSysClockFreq();
SerialDebug.printf("\nClock Configuration:\n");
SerialDebug.printf("PCLK2: %lu Hz\n", pclk2);
SerialDebug.printf("PCLK1: %lu Hz\n", pclk1);
SerialDebug.printf("HCLK: %lu Hz\n", timclk);
SerialDebug.printf("SYSCLK: %lu Hz\n", sysclk);
SerialDebug.printf("SystemCoreClock: %lu Hz\n", SystemCoreClock);
// Configure PE9 for Timer1 CH1 (PWM output)
GPIO_InitTypeDef GPIO_Config = {0};
GPIO_Config.Pin = GPIO_PIN_9;
GPIO_Config.Mode = GPIO_MODE_AF_PP;
GPIO_Config.Pull = GPIO_NOPULL;
GPIO_Config.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_Config.Alternate = GPIO_AF1_TIM1;
HAL_GPIO_Init(GPIOE, &GPIO_Config);
// Reset timer
TIM1->CR1 = 0;
TIM1->CR2 = 0;
TIM1->SMCR = 0;
TIM1->DIER = 0;
TIM1->CCMR1 = 0;
TIM1->CCER = 0;
TIM1->BDTR = 0;
// Timer configuration for HCLK = 200 MHz
TIM1->PSC = 199; // Divide by 200 (200 MHz / 200 = 1 MHz)
TIM1->ARR = 999; // ARR = 999 for 1 kHz (1000 cycles)
TIM1->CCR1 = 500; // 50% duty cycle (ARR / 2)
// Configure PWM mode 1 (OC1, PWM mode 1)
TIM1->CCMR1 = (0b110 << 4) | TIM_CCMR1_OC1PE;
TIM1->CCER = TIM_CCER_CC1E; // Enable capture/compare channel 1
TIM1->BDTR = TIM_BDTR_MOE; // Main output enable
TIM1->CR1 = TIM_CR1_ARPE | TIM_CR1_CEN; // Enable auto-reload preload and the timer
// For debug - read back the actual values
SerialDebug.printf("\nTimer Configuration:\n");
SerialDebug.printf("PSC: %lu\n", TIM1->PSC);
SerialDebug.printf("ARR: %lu\n", TIM1->ARR);
SerialDebug.printf("CCR1: %lu\n", TIM1->CCR1);
SerialDebug.printf("CR1: 0x%08lX\n", TIM1->CR1);
SerialDebug.printf("CCMR1: 0x%08lX\n", TIM1->CCMR1);
// Start timer
TIM1->CR1 |= TIM_CR1_CEN;
}
void setup()
{
SerialDebug.begin(115200);
delay(100);
SerialDebug.println("\nClock Verification Test");
// Configure control pins
pinMode(PIN_DIR, OUTPUT);
pinMode(PIN_ENA, OUTPUT);
digitalWrite(PIN_ENA, HIGH); // Disabled
digitalWrite(PIN_DIR, LOW); // Forward
setupTimer1();
}
void loop()
{
if (SerialDebug.available())
{
char cmd = SerialDebug.read();
if (cmd == 'e')
{
SerialDebug.println("Enabling motor");
digitalWrite(PIN_ENA, LOW);
}
else if (cmd == 'd')
{
SerialDebug.println("Disabling motor");
digitalWrite(PIN_ENA, HIGH);
}
}
}
Clock Verification Test
Clock Configuration:
PCLK2: 100000000 Hz
PCLK1: 100000000 Hz
HCLK: 200000000 Hz
SYSCLK: 400000000 Hz
SystemCoreClock: 400000000 Hz
Timer Configuration:
PSC: 199
ARR: 999
CCR1: 500
CR1: 0x00000080
CCMR1: 0x00000068
Any help or insight would be much appreciated. Thanks in advance!
2024-11-16 03:00 AM
Your system clock is most likely not 400MHz, but 333.200MHz, most likely as consequence of a different primary clock source frequency than you've set (e.g. you assume 12MHz primary clock but it's in fact 10MHz).
HAL_RCC_GetHCLKFreq() etc. functions don't actually *measure* the HCLK/APB etc. frequencies; rather, they rely on a system variable (SystemCoreClock) being set properly in HAL_RCC_ClockConfig() by calling HAL_RCC_GetSysClockFreq(), which in turn uses one of HSI_VALUE/CSI_VALUE/HSE_VALUE set in stm32h7xx_hal_conf.h depeding on what primary clock source you've set.
JW
2024-11-21 07:48 AM
Hello @sktech
Did you measure the clock frequency? If the measured value is different from the theoretical value, it could be the reason for this issue.
To measure the clock frequency, you can use an oscilloscope to monitor the output on the MCO pin.