cancel
Showing results for 
Search instead for 
Did you mean: 

resolving a conflict between using Timer3 interrupt and HAL_Delay()

HIngv.1
Associate II

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?

6 REPLIES 6

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

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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 1, HAL_MAX_DELAY);
	HAL_I2C_Master_Receive(&hi2c1, ACC_ADDR, &data, 1, HAL_MAX_DELAY);
	aBuffer[5] = data;
}//end getAccData

> 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

Thank you. I figured it was on my end and wanted to confirm.

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

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.