2024-10-15 04:52 AM - edited 2024-10-15 04:52 AM
Hi folks,
I recently started my STM32 journey using a STM32WLE5JCxx (the LoRa-E5). After fighting with the SubGHz for a while, I managed to write a decent application, but I'm not completely familiar with all of the essentials yet.
Currently, I am using the `HAL_Delay()` function, but after some testing found that it is highly inaccurate. My code snippet:
int i = 0;
while(1) {
printf("%d\n", i++);
HAL_Delay(100000);
}
The output I get (with the actual difference in milliseconds calculated afterwards):
13:26:41.925 > 0
13:28:22.323 > 1 (+398)
13:30:02.318 > 2 (-5)
13:31:42.309 > 3 (-9)
13:33:22.290 > 4 (-19)
13:35:02.236 > 5 (-54)
13:36:42.118 > 6 (-118)
13:38:21.961 > 7 (-157)
13:40:01.796 > 8 (-165)
13:41:41.623 > 9 (-173)
13:43:21.431 > 10 (-192)
This means that on every 100 seconds, the clock drifts anywhere from -200ms to +400ms. A fixed value drift might've been OK, but this is quite unworkable.
I did read that `HAL_Delay()` might not be the most accurate clock source, but I am unsure how to implement a 'simple' delay-function. If someone could help me with a snippet or point to a place where I can find explanation on how to make an accurate delay myself, that would be very much appreciated.
Cheers!
Solved! Go to Solution.
2024-10-15 09:07 AM
I think your clock source has offset. If you can use the TCXO that would likely be a lot tighter/consistent
I'd free run the counter, not continually reset it.
At that point the time line becomes more consistent and more impervious to other stuff going on, like UART output.
I'd delta the time measurement, and advance the start / check-point reference
int i = 0;
uint32_t delay = 100000;
uint32_t start = TIM2->CNT;
while(1) {
printf("%d\n", i++);
while((TIM2->CNT - start) < delay);
start += delay;
}
.
2024-10-15 04:59 AM
For completeness sake, here's a message of the Clock configuration (the bottom half outside the picture is all greyed out and as per default).
2024-10-15 05:35 AM - edited 2024-10-15 08:56 AM
Perhaps use TIM2, clocking at 1 MHz to get 1 us resolution within a few us.
Or use a long term time base and advance the start point you're trying to hit.
ie
while((current - start) < delayticks);
start += delayticks;
2024-10-15 06:08 AM
Hi @Tesla DeLorean , thank you for your answer.
I tried the following:
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 47999;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 4294967295;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
void delay_ms(uint32_t delay) {
__HAL_TIM_SET_COUNTER(&htim2, 0);
while (__HAL_TIM_GET_COUNTER(&htim2) < delay) {
// wait for the timer to count the required time
}
}
int i = 0;
while(1) {
printf("%d\n", i++);
delay_ms(100000);
}
Unfortunately however, I still get poor accuracy:
14:57:15.909 > 0
14:58:55.844 > 1
15:00:35.777 > 2
15:02:15.670 > 3
15:03:55.545 > 4
15:05:35.432 > 5
15:07:15.332 > 6
Do you see any obvious mistakes, or do you have any further suggestions?
2024-10-15 06:16 AM
Hello @bns and welcome to the community,
@bns wrote:
+ You are using an internal source of Clock based on RC cell not a precise clock source as Crystal / HSE.
Did you try with an external crystal?
2024-10-15 06:31 AM
Hi @SofLit, thank you very much for your response!
Sorry for my obliviousness - how would I configure this? I do now see the options for the HSE/LSE in the System Core / RCC tab. What values would I need to set their options to, for the LoRa-E5? Would I also set it to Master Clock Output?
2024-10-15 06:34 AM
You need to set Crystal/Ceramic Resonator. But you need definitely having an external Crystal connected to OSC_IN and OSC_OUT pins.
2024-10-15 06:41 AM
According to the Seeed wiki, the LoRa-E5 has a TCXO connected at 32MHz. After configuring that as the HSE source, I would like to use it as the clock source.
Would the following Clock configuration make sense, or would it likely result in troubles? My apologies - I don't really have a feeling for it yet, besides knowing that I can't really go below ~20MHz for CPU/SPI.
2024-10-15 07:02 AM
@bns wrote:
Would the following Clock configuration make sense, or would it likely result in troubles? My apologies - I don't really have a feeling for it yet, besides knowing that I can't really go below ~20MHz for CPU/SPI.
I don't know about that "TXCO" clock source.
To me the configuration is good but:
You need to ensure that this TXCO is available and generating a precise clock.
Otherwise, you need an external crystal with the config I mentioned above.
2024-10-15 07:17 AM
Primary try go back to start and dont check Delay with printf. Printf is handled by fifos and next irq/os management, then generate random delays. Simply toggle GPIO pin is perfect for timing check.