2023-11-30 10:18 PM - edited 2023-11-30 10:19 PM
Hi,
I am using STM32G4 in my project. I need delays in my project multiple places. I am using hardware timer interrupt for delay.
I am using TIM1 configured with 50 usec delay.
HAL_TIM_Base_Start_IT(&htim1);
HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_2);
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2)
{
if( flag_50 usec==1){
//read adc;
flag_50 usec=0; }
if(flag_800usec==1){
//check switch high/low
flag_800 usec=0 }
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM1)
{
uint16_t varible=0;
flag_50 usec=1;
variable++;
//take one variable to increment timer
if(varible==16)
flag_800usec==1;
}
}
1.As mentioned I need different delays in my project. For every pwm pulse rising edge after 50 usec I need to adc value and then after 800 usec I need to check one switch high/low. It should be repeated process. I am planning to use same timer for delay.
2.Once 50 usec delay done I need to take one variable to increment it for every 50 usec if it reached 16 times means(16*50 usec=800 usec) then I will take flag_800 usec to high and I will check the same in main function.
3.For remaining delays like 3 sec,2 sec I am planning do the same.
Is it correct process. If not Please suggest some other process to do it.
Thanks
Solved! Go to Solution.
2023-12-12 05:41 AM
You would check TIMx_CNT against a stored timestamp (i.e. elapsed time) in the same way as you would check the flag set by interrupt upon elapsed time.
In microcontroller programming, there is no universal "good" solution. What I've vaguely described above can be interpreted and implemented in several different ways, and details do matter. If you're comfortable with your solution and you don't mind that it consumes the computing power of the processor, then go ahead and use it.
JW
2023-12-01 01:04 AM - edited 2023-12-01 01:04 AM
One way to do this is just leave the timer free running to its maximum (TIM2 is conveniently 32-bit), say with prescaler set so that TIM2_CNT increments at a 1MHz rate.
In main loop then, at the start of the timed event you read out TIM2_CNT and remember it in a variable, and then just wait until difference between TIM2_CNT and the stored value gets equal or more than 50. The same for the other delays. No interrupt needed for this method.
JW
2023-12-10 08:42 PM
Hi @waclawek.jan ,
1.I am generating 50 usec delay from timer1.Below configuration for 50 usec in stm32g4
APB2-48 Mhz
prescaler :2400-1
counter period:65535-1
2. The code which I mentioned does it work?
static uint32_t v = 0; // Declare v as a static variable outside the function
typedef struct
{
uint16_t flag_50;
uint16_t flag_100usec;
uint16_t flag_800usec;
uint16_t flag_1sec;
uint16_t flag_2sec;
uint16_t flag_3sec;
} Em_de;
extern Em_de delay;
Em_de delay = {0};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim == &htim1)
{
delay.flag_50 = 1;
v++;
if (v == 2)
{
delay.flag_100usec = 1;
}
else if (v == 16)
delay.flag_800usec = 1;
else if (v == 20000)
delay.flag_1sec = 1;
else if (v == 40000)
delay.flag_2sec = 1;
else if (v == 60000)
delay.flag_3sec = 1;
else if (v == 120000)
delay.flag_6sec = 1;
if (v >= 120000)
v = 0;
}
}
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
if (htim == &htim2)
{
// PWM pulse finished callback for htim2
if (delay.flag_50 == 1)
{
delay.flag_50 = 0; // Reset the flag
uint16_t adcValue = readADC();
// Process the ADC value as needed
}
if (delay.flag_800usec == 1)
{
// Check if the 800 microseconds flag is high
// Perform the required logic here
delay.flag_800usec = 0; // Reset the flag
}
}
}
2023-12-11 04:23 AM
APB2-48 Mhz
prescaler :2400-1
counter period:65535-1
That means, timer clock is 50us, and period is 65535*50us=3.28s.
That's probably not what you want.
Also, note, that it takes quite a couple of machine cycles to service an interrupt. If you want one interrupt per 50us = 2400 machine cycles (e.g. by using prescaler = 0 and period = 2400 - 1), the interrupt service must take much less cycles so that it won't significantly slow down the whole mcu. Especially if you use Cube/HAL, which adds quite some overhead; not using optimization may make this not workable at all.
This is why I suggested a solution which would avoid using interrupts at all.
JW
2023-12-11 04:44 AM
The MCU's aren't well suited to interrupts into the 100's of KHz, simply because you end up wasting so many cycles in friction (unproductive work, entering/exiting interrupt context, HAL code and callbacks).
Yes, the basic premise of your code and sequencing looks to be ok, but everything also has to execute within the prescribed time window too. You could probably do something more efficiently in a tight/fast main loop sequencing of a TIM->CNT.
Ideally push as much as possible into HW, ie by making TIM's do pin actions/pulse, or use DMA to drive periodic output or sequences.
2023-12-11 09:24 PM - edited 2023-12-11 09:47 PM
Hi @waclawek.jan,
1.My mistake,
Now I changed
APB2-48 Mhz
prescaler=100-1
counter period =24-1.
2. for delay function: Below function is what are you suggesting? if yes, delay function is blocked delay right, it will block the execution of other functions when delay is called?I need non blocking delay that's why I am thinking about using interrupt.
is it correct?
void delay_us(uint32_t us) {
uint32_t start_time = TIM2->CNT;
while ((TIM2->CNT - start_time) < us) {
}
}
volatile uint32_t start_time; // Variable to store the starting time volatile uint32_t delay_completed = 0; void start_and_check_delay_elapsed(uint32_t us) { start_time = TIM2->CNT; // Record the current timer value delay_completed = 0; // Reset the flag while (!delay_completed) { if ((TIM2->CNT - start_time) >= us) { delay_completed = 1; // Set the flag when the delay has completed } } } //Can above code acts as non blocking delay???
In above functions second code can use for non blocking delay?
If not please suggest
Thanks
2023-12-12 05:41 AM
You would check TIMx_CNT against a stored timestamp (i.e. elapsed time) in the same way as you would check the flag set by interrupt upon elapsed time.
In microcontroller programming, there is no universal "good" solution. What I've vaguely described above can be interpreted and implemented in several different ways, and details do matter. If you're comfortable with your solution and you don't mind that it consumes the computing power of the processor, then go ahead and use it.
JW