cancel
Showing results for 
Search instead for 
Did you mean: 

Program gets stuck in for loop after interrupt runs

deep_rune
Associate III

This has me scratching my head - my program runs fine UNLESS the interrupt occurs, after which it gets stuck in a for loop near the start of the program. I can't see any way these two things are connected with each other - there dont share variables. The main loop is as follows

int main(void)
{
  HAL_Init();
  SystemClock_Config();
 
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_SPI1_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_TIM16_Init();
 
  ADC12_COMMON ->CCR |= 1<<19 | 1 <<17; // set ADC clock options
  ADC1->CR |= 1>>0; // enable ADC
  ADC1->CR |= ADC_CR_ADSTART; // start conversion
 
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
 
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4);
 
  HAL_TIM_PWM_Start(&htim16, TIM_CHANNEL_1);
 
  while (1)
  {
	  while(((ADC1->ISR) & 0b00000100)==0)
	  {
	  }
 
 		for(j=0;j<10;j++)
		{
		  ADC_result_pre[i][j] = ADC1->DR; //fetch adc data
		}
		VCA_raw[i]= (ADC_result_pre[i][0]+ADC_result_pre[i][1]+ADC_result_pre[i][2]+ADC_result_pre[i][3]+ADC_result_pre[i][4]+ADC_result_pre[i][5]+ADC_result_pre[i][6]+ADC_result_pre[i][7]);
		ADC_result[i] = VCA_raw[i] / 8;
 
 
		switch(ADC1->SQR1)   //switch dac channel to the next
		{
		case 0b101000000:
		  ADC1 ->SQR1 = 0b110000000;
		  i=1;
		  break;
 
		case 0b110000000:
		  ADC1 ->SQR1 = 0b101000000;
		  i=0;
		  break;
		}
 
		ADC1->CR |= ADC_CR_ADSTART;
 
//======================================================================
 
		LED1_prep = ADC_result[0]>>4;
		RED1 = 255 - LED1_prep;
		BLUE1 = LED1_prep;
 
		if(RED1 <= 127)
		{
			GREEN1 = RED1*2;
		}
		else
			GREEN1 = BLUE1*2;
 
		set_rgb1(RED1,BLUE1,GREEN1); //second spot is actually blue // third is green
 
		LED2_prep = ADC_result[1]>>4;
		RED2 = 255 - LED2_prep;
		BLUE2 = LED2_prep;
		if(RED2 <= 127)
				{
					GREEN2 = RED2*2;
				}
				else
					GREEN2 = BLUE2*2;
 
		set_rgb2(RED2,BLUE2,GREEN2); //1st green, 2nd red, third blue
 
//========================================================================
 
		Prepare_States(ADC_result[0],0); //get the mode info for the first channel
		prep_values(0);
 
//		dac_channel = 1;
		Prepare_States(ADC_result[1],1); //and for the second
//		prep_values(1);
 
  }
}

It gets stuck on the for loop on line 32. I can see j incrementing up to 9, then it gets reset and stays in the loop. The interrupt is as follows

void EXTI15_10_IRQHandler(void)
{
		uint32_t mask = 0;
		uint32_t Chuff = ChangeFlag;
 
		if (Chuff & 1<<2)
			mask = (1<<4);
		else
			mask = (1<<20);
 
		if (Chuff & 1<<3)
			mask |= (1<<12);
		else
			mask |= (1<<28);
 
		GPIOA->BSRR = mask;
 
		Chuff |= 1<<0;
		ChangeFlag |= Chuff;
		EXTI->PR1 |= 1<<11; //turn off interrupt request
}

I can't see any way these things are related. Any help much appreciated!

5 REPLIES 5
TDK
Guru

Next time, include your chip number.

There's nothing on line 32 for it to get stuck on.

It's possible an interrupt is being called continuously which prevents the processor from doing anything in the main loop. It's not clear if you're enabling interrupts with ADC or not. It doesn't look like you clear the ISR flags anywhere.

for(j=0;j<10;j++)
		{
		  ADC_result_pre[i][j] = ADC1->DR; //fetch adc data
		}

 This isn't going to work as intended. The DR register is not a FIFO, it only holds the last conversion. Maybe I'm missing the logic here.

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

Thanks for the comment. Im using an STM32L412. I didn't want to use the HAL to clear the interrupt request so Im using

EXTI->PR1 |= 1<<11;

is this OK? it seems to work fine and in any case, using the HAL

HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);

doesn't solve the problem.

The problem seems to be with the variable 'changeflag'. I want this to be accessible within my main program, so I've declared it as

extern volatile uint8_t ChangeFlag;

in both the program and the interrupt file. Is this the correct way to declare it?

TDK
Guru

> EXTI->PR1 |= 1<<11;

> is this OK?

Yes, I missed that.

> The problem seems to be with the variable 'changeflag'

I don't understand. You're saying ChangeFlag is causing the program to be stuck in a for loop? How did you reach that conclusion? You're not even using ChangeFlag in the main loop anywhere.

The variable should be declared/defined normally in one source file and the declared as "extern" in the others, or in an included header.

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

It sounds like you understand exactly what im saying

When i run in debug mode, I run the program and it runs fine. As soon as I connect the external trigger to the circuit it enters the interrupt, then when it exits it stays in that for loop on line 32 forever - im using the step into command to see each line of execute. i see the variable j increment up to 9, reset and count up again without ever leaving the for loop.

I deleted everything from the interrupt apart from a slightly modified command

ChangeFlag |= 1<<0;

it still happens. If i delete that and leave the interrupt blank, it stops happening.

it seems weird to me too

so if i have

uint32_t ChangeFlag;

in main.c and

extern uint32_t ChangeFlag;

in stm32l4xx_it.c - this is correct?