2023-03-14 09:20 AM
Hi all,
Hardware - STM32L4R9 Disco with STEVAL-MK172V1 eCompass
I'm stuck trying to resolve some kind of conflict I'm having with Hal_Delay. I've lowered the priority of the timer interrupt so that SysTick is a higher priority. I've tried using both the TIM3_IRQHandler() found in the stm32xxxx_it.c file in core, and writing in HAL_TIM_PeriodElapsedCallback at the bottom of my main. with either of those methods, if there is no code to be handled, the loops and interrupts function so that I get the output loop over UART I'm using as a method of output for now, just without the data I'm ultimately calculating. I've made use of __disable and __enable_irq() in the interrupt handlers in an attempt to prevent conflict, but any time I try to execute any portion of what I'd like to be updating, the controller gets stuck in an infinite loop either as a result of of trying to run HAL_Delay, HAL_TIM_Base_Start_IT or printf (which is set up to print to the UART connection I have set up over the USB cable.
When I run debug and step through everything, sometimes it gets to main while loop before getting frozen, sometimes its when I run HAL_TIM_Base_Start_IT is where it gets stuck in a loop. when I pause the debugger after hitting this loop, it's almost always in either HAL_Delay or HAL_GetTick, with the variables showing delay = 5, tickstart = ~1545 and wait = 6.
I suspect I'm missing something fundamental about timing interrupts that my brain is skipping over that has to do with the fact that the process I want run at each interrupt is more complex than flipping a bit or an LED. I've tried to break down my function to only execute the most basic need (polling a set of 12 registers over i2c on another device) but It doesn't rectify the issue. what am I missing about using a timer interrupt that would create this conflict?
2023-03-14 09:29 AM
Prepare a *minimal* but complete compilable example exhibiting the problem, and post.
The best way to do this is to start from scratch and add only what's necessary.
JW
2023-03-14 10:05 AM
I think it's likely I'm trying to do too much with the interrupt. I was hoping to run at least updating the accel/mag buffer variables when the interrupt triggers, but it seems the most I should be doing is flipping a bit or changing a bool sort of thing. I was hoping to get away with more than that
IRQ handler:
void TIM3_IRQHandler(void)
{
/* USER CODE BEGIN TIM3_IRQn 0 */
__disable_irq();
/* USER CODE END TIM3_IRQn 0 */
HAL_TIM_IRQHandler(&htim3);
/* USER CODE BEGIN TIM3_IRQn 1 */
getMagData();
getAccData();
__enable_irq();
/* USER CODE END TIM3_IRQn 1 */
}
and then get Mag/ACC data is probably where its too long?
void getMagData(void){
uint8_t data;
uint8_t reg;
reg = OUTX_L_REG_M;
HAL_I2C_Master_Transmit(&hi2c1, MAG_ADDR, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, MAG_ADDR, &data, 1, HAL_MAX_DELAY);
mBuffer[0] = data;
reg = OUTX_H_REG_M;
HAL_I2C_Master_Transmit(&hi2c1, MAG_ADDR, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, MAG_ADDR, &data, 1, HAL_MAX_DELAY);
mBuffer[1] = data;
reg = OUTY_L_REG_M;
HAL_I2C_Master_Transmit(&hi2c1, MAG_ADDR, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, MAG_ADDR, &data, 1, HAL_MAX_DELAY);
mBuffer[2] = data;
reg = OUTY_H_REG_M;
HAL_I2C_Master_Transmit(&hi2c1, MAG_ADDR, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, MAG_ADDR, &data, 1, HAL_MAX_DELAY);
mBuffer[3] = data;
reg = OUTZ_L_REG_M;
HAL_I2C_Master_Transmit(&hi2c1, MAG_ADDR, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, MAG_ADDR, &data, 1, HAL_MAX_DELAY);
mBuffer[4] = data;
reg = OUTZ_H_REG_M;
HAL_I2C_Master_Transmit(&hi2c1, MAG_ADDR, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, MAG_ADDR, &data, 1, HAL_MAX_DELAY);
mBuffer[5] = data;
}//end getMagData
void getAccData(void){
uint8_t data;
uint8_t reg;
reg = OUTX_L_A;
HAL_I2C_Master_Transmit(&hi2c1, ACC_ADDR, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, ACC_ADDR, &data, 1, HAL_MAX_DELAY);
aBuffer[0] = data;
HAL_Delay(5);
reg = OUTX_H_A;
HAL_I2C_Master_Transmit(&hi2c1, ACC_ADDR, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, ACC_ADDR, &data, 1, HAL_MAX_DELAY);
aBuffer[1] = data;
HAL_Delay(5);
reg = OUTY_L_A;
HAL_I2C_Master_Transmit(&hi2c1, ACC_ADDR, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, ACC_ADDR, &data, 1, HAL_MAX_DELAY);
aBuffer[2] = data;
HAL_Delay(5);
reg = OUTY_H_A;
HAL_I2C_Master_Transmit(&hi2c1, ACC_ADDR, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, ACC_ADDR, &data, 1, HAL_MAX_DELAY);
aBuffer[3] = data;
HAL_Delay(5);
reg = OUTZ_L_A;
HAL_I2C_Master_Transmit(&hi2c1, ACC_ADDR, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, ACC_ADDR, &data, 1, HAL_MAX_DELAY);
aBuffer[4] = data;
HAL_Delay(5);
reg = OUTZ_H_A;
HAL_I2C_Master_Transmit(&hi2c1, ACC_ADDR, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, ACC_ADDR, &data, 1, HAL_MAX_DELAY);
aBuffer[5] = data;
}//end getAccData
2023-03-14 10:33 AM
> I think it's likely I'm trying to do too much with the interrupt.
Yes.
The usual pattern is to set a flag in the interrupt and leave; and then in main loop check that flag and if set, perform the lengthy action.
JW
2023-03-14 10:51 AM
Thank you. I figured it was on my end and wanted to confirm.
2023-03-14 03:36 PM
You can't disable interrupts and expect delays and timeouts, dependent on a higher priority interrupt, to function properly/desirably..
Interrupts and callbacks should do the least amount of work possible. If you've got a long amounts of linear work, and blocking, perhaps thing of using an RTOS with tasks/threads, so other things can run concurrently.
2023-03-15 07:14 AM
I saw that experimenting further. If I'm understanding correctly, Systick also utilizes an interrupt to increment so globally disabling interrupts also disables Systick, correct?
I have not learned much about RTOS yet, so that's going to be new territory for me.