cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 · Coding within HAL ISR inserts delay

Yvo
Associate II

Hello, all.

First of all, thank you for taking your time for reading this and helping me out.

I am using STM32H743ZI Nucleo board, preparing the project for a power electronics application. Before any control algorithm I'm checking that the Interrupt Service Routines work as expected, at the frequency they are programmed... but they dont.

I might be missing something evident and I apologise for that, since I am new on ST (coming from TI). What I'm trying is that Update Interrupt of Timer17 run every 80.00kHz, and I'm debugging it by toggling a GPIO each interrupt execution. The code is the following

void System_Init()
{
	// TIMER 1 (PWM ABC) · Initialization
	HAL_TIM_Base_Start (&htim1);                     // Starting Base-time
	HAL_TIM_PWM_Start (&htim1, TIM_CHANNEL_1);       // Starting PWM
	TIM1 -> ARR = PWM_ABC_TIM1ARR;                   // Assigning the Auto-Reload value
	TIM1 -> CCR1 = (PWM_ABC_TIM1ARR+1)*0.5;          // Initializing duty ratio to 0.5
 
	// TIMER 17 (AUX) · Initialization
	HAL_TIM_Base_Start_IT(&htim17);                  // Starting Base-time
	TIM17 -> ARR = PWM_ABC_TIMAUXARR;                // Assigning the Auto-Reload value
 
	// RAMPGEN · Initialization
	RAMPGEN_MACRO (ramp_PWM);
	ramp_PWM.Freq=PWM_ABC_MOD_FREQ;
	ramp_PWM.StepAngleMax= 1.0 / (2.0 * (float)PWM_ABC_SW_FREQ);
}
 
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	//int aux_counter;
	if (htim == &htim17)
	{
		HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_14);
		//RAMPGEN_MACRO (ramp_PWM);
		//PWM_ABC_RAMP = TWOPI * ramp_PWM.Out;
		//PWM_ABC_DUTY_A = 0.5+(0.5*(sin(PWM_ABC_RAMP)));
		//PWM_ABC_DUTY_B = 0.5+(0.5*(sin(x - TWOPIDIV3)));
		//PWM_ABC_DUTY_C = 0.5+(0.5*(sin(x - FOURPIDIV3)));
 
		//TIM1 -> CCR1 = (PWM_ABC_TIM1ARR+1)*PWM_ABC_DUTY_A;          // Initializing duty ratio to 0.5
		//__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, (PWM_ABC_TIM1ARR+1)*PWM_ABC_DUTY_B); // Update Duty B
		//__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, (PWM_ABC_TIM1ARR+1)*PWM_ABC_DUTY_C); // Update Duty C
 
	}
}

Note that several references are done to Timer 1, since it will be later used with PWM, explained later.

The point is that with this simple piece of code, everything runs as expected:

0693W00000CzcQ7QAJ.png 

The frequency of the signal is 40.00kHz (the interrupt toggles the pin at 80kHz), so everythings OK.

THE PROBLEM starts when I uncomment the code within HAL_TIM_PeriodElapsedCallback function. Only by uncommenting 4 lines of code (which are a simple macro generating a ramp from 0 to 1, a multiplication, a sine calculation and a Tim1 duty update), the frequency of the interrupt is not stable anymore.

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	//int aux_counter;
	if (htim == &htim17)
	{
		HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_14);
		RAMPGEN_MACRO (ramp_PWM);
		PWM_ABC_RAMP = TWOPI * ramp_PWM.Out;
		PWM_ABC_DUTY_A = 0.5+(0.5*(sin(PWM_ABC_RAMP)));
		//PWM_ABC_DUTY_B = 0.5+(0.5*(sin(x - TWOPIDIV3)));
		//PWM_ABC_DUTY_C = 0.5+(0.5*(sin(x - FOURPIDIV3)));
 
		TIM1 -> CCR1 = (PWM_ABC_TIM1ARR+1)*PWM_ABC_DUTY_A;          // Initializing duty ratio to 0.5
		//__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, (PWM_ABC_TIM1ARR+1)*PWM_ABC_DUTY_B); // Update Duty B
		//__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, (PWM_ABC_TIM1ARR+1)*PWM_ABC_DUTY_C); // Update Duty C
 
	}
}

The results are presented on the following image, where it can be checked how, for the (almost) same number of samples, the max and min of the frequency are way far from the 40.00kHz...0693W00000CzcRFQAZ.png 

I came to this problem because the very same was happening if I used the interrupt of ADC void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)... the more lines of code I added, the most the signal distorts.

I assume that the problem is on how I am coding within the ISR, so:

  1. Is there any evident thing I'm missing on the implementation of the ISR?
  2. Is there any protocol in order to code within an ISR? Any flag to clear before coding or some way of calling the function
  3. SOS

Any doubt in order to have more info on the problem, do not hesitate in asking,

Thank you very much,

Best regards to all

3 REPLIES 3
TDK
Guru

> Is there any evident thing I'm missing on the implementation of the ISR?

Nope.

> Is there any protocol in order to code within an ISR? Any flag to clear before coding or some way of calling the function

Nope.

> SOS

The chip can only do so much at once. Reduce the number of things you're doing in the ISR to help this (as you've already seen).

HAL adds overhead. If that causes issues for your project, you can ditch HAL and drive things yourself, but you lose parts of the HAL framework.

> RAMPGEN_MACRO (ramp_PWM);

> PWM_ABC_DUTY_A = 0.5+(0.5*(sin(PWM_ABC_RAMP)));

You say you're only adding 4 lines, but these two look pretty heavy. Using floating point in the ISR causes additional delays as it needs to push the FP registers onto the stack (and pop them afterwards).

If you feel a post has answered your question, please click "Accept as Solution".

> Using floating point in the ISR causes additional delays as it needs to push the FP registers onto the stack (and pop them afterwards).

I'd say, sin() is probably far more time consuming than the context push/pop.

JW

Pavel A.
Evangelist III

What is the priority of your interrupt? are other interrupts of same or higher priority enabled?