2024-07-14 05:14 PM
I use CubeMX to generate the set up code for clocks and peripherals in the STM32H7A3 I'm currently using for my current work. I'd like to calculate the timer and low-power timer call back periods programmatically without having to type in magic numbers I set in CubeMX. I've been able to figure out how to mostly do that for timer1 but have a few questions.
Q1) If there is a HAL or LL function that gives the clock frequency going into each timer module? If so, can someone point me at it because I sure haven't been able to find one. If there is a function like that, please ignore the next 2 questions. If there really isn't one, the next 2 questions are about how to roll my own. And if there really isn't a function like that, shouldn't there be?
Q2) Here's a snip of the CubeMX clock configuration tab for the timers on the APB1 and APB2 timers. In order to calculate the clock frequency being fed to those timers, I need the values for SYSCLK, CDCPRE Prescaler, HPRE Prescaler, CDPPRE1, CDPPRE2. I can get those directly off registers or by using HAL or LL calls. The problem is the little X1 multiplier ahead of the "To APB1 Timer Clocks" and "To APB2 Timer Clocks" on the right side of the figure below . That multiplier can be X1, X2, X4 or other values depending on the APB1 and APB2 peripheral clock values. It appears that CubeMX sets that multiplier value based on some internal algorithm and I can't find a way to read that value from my program. Is it possible to get that multiplier value programmatically?
Q3) Below is a snip of the clock configuration for the low power timers: I can get which clock is being used with the
LL_RCC_GetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE)
function. But I haven't figured out how to get the value of the LSI clock frequency except as a #define in stm32h7xx_hal_conf.h. Is that really the only way?
Here's the code I use to setup the timers if anyone is interested.
void TimerMgr::initTimers()
{
const float sysClockFreq = HAL_RCC_GetSysClockFreq();
const uint32_t sysPrescalerRegisterValue = LL_RCC_GetSysPrescaler();
const uint32_t hprePrescalerRegisterValue = LL_RCC_GetAHBPrescaler();
const uint32_t cdppre1PrescalerRegisterValue = LL_RCC_GetAPB1Prescaler();
//See RM0455 Section 8.4.6 for the mapping between sys Prescaler register values and actual divider values
const uint16_t cdcpreDivisors[] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 8, 16, 64, 128, 256, 512 };
//See RM0455 Section 8.7.6 for the mapping between hpre Presclaer register values and actual divider values
const uint16_t hpreDivisors[] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 8, 16, 64, 128, 256, 512 };
//See RM0455 Section 8.7.7 for the mapping between cdppre1 Prescaler register values and actual divider values
const uint8_t cdppre1Divisors[] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 8, 16 };
//See RM0455 Section 46.7.4for the mapping between lowpower timer prescaler register values and actual divider values
const uint8_t lptimerDivisors[] = { 1, 2, 4, 8, 16, 32, 64, 128, };
uint32_t prescalerLptim1 = LL_LPTIM_GetPrescaler(LPTIM1);
uint32_t lpTimer1ClockSource = LL_RCC_GetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE);
if (lpTimer1ClockSource == LL_RCC_LPTIM1_CLKSOURCE_LSI)
lpTimer1ClockFreq = LSI_VALUE;
else if (lpTimer1ClockSource == LL_RCC_LPTIM1_CLKSOURCE_LSE)
lpTimer1ClockFreq = LSE_VALUE;
else
lpTimer1ClockFreq = 32767;
lpTimer1ClockFreq = lpTimer1ClockFreq / lptimerDivisors[prescalerLptim1];
timer1MaxPeriod = UINT16_MAX / lpTimer1ClockFreq;
//By inspection of CubeMX clock configuration tab
timer1ClockFreq = sysClockFreq / (cdcpreDivisors[sysPrescalerRegisterValue] *
hpreDivisors[hprePrescalerRegisterValue] *
cdppre1Divisors[cdppre1PrescalerRegisterValue]);
uint32_t prescalerTim1 = LL_TIM_GetPrescaler(TIM1);
//RM0455 Figure 314
timer1ClockFreq = timer1ClockFreq / (prescalerTim1 + 1);
//Note: This depends on exactly which timer is being used. Can be UINT16 or UINT32
timer1MaxPeriod = UINT16_MAX / timer1ClockFreq;
}
Thanks in advance
2024-07-15 11:06 AM
Why is the constant defined for LSI in the HAL insufficient?
There are functions to get the APB1 (PCLK1) and APB2 (PCLK2) frequencies.
HAL_RCC_GetPCLK1Freq() and HAL_RCC_GetPCLK2Freq().
2024-07-15 12:37 PM
@Rob.Riggs There's nothing wrong with the #define, it just seemed a little odd given that I can get all the other stuff from registers. And thanks for pointing me at those 2 functions.
My biggest issue seems to be with the X1 boxes that I mentioned in my OP. The actual value doesn't seem to be anywhere I can get access to it.
2024-07-15 01:07 PM
Hello @magene ,
To calculate the timer and low-power timer callback periods programmatically in the STM32H7A3, you can use HAL or LL functions to get the clock frequency for each timer module.
Using HAL Functions
The HAL (Hardware Abstraction Layer) library provides functions to retrieve the clock frequency for different peripherals, including timers. Here’s how you can use them:
1. Get the timer clock frequency:
uint32_t timerClockFrequency = HAL_RCC_GetPCLK1Freq(); // For timers on APB1
// or
uint32_t timerClockFrequency = HAL_RCC_GetPCLK2Freq(); // For timers on APB2
2. Adjust for Timer Prescaler: If the timer is on APB1 and the APB1 prescaler is not 1, the timer clock frequency is doubled:
if (__HAL_RCC_GET_PCLK1_PRESCALER() != RCC_HCLK_DIV1) {
timerClockFrequency *= 2;
}
Similarly, for APB2:
if (__HAL_RCC_GET_PCLK2_PRESCALER() != RCC_HCLK_DIV1) {
timerClockFrequency *= 2;
}
BRs,
Sarra