cancel
Showing results for 
Search instead for 
Did you mean: 

While loop blocking PWM timerUpdate callback in stepper motor application

SStru.1
Associate II

I am working on a 2-axis CNC machine using an STM32F103C8T6 and using the HAL libraries. I've setup a seperate timer for each axis of the machine and have those configured in PWM mode.

I have a function called step_x(numberSteps, Direction) which takes in a number of steps and sets this as the target number of steps, sets the direction via GPIO write and then starts the PWM in interrupt mode:

void step_x(uint32_t numberSteps, uint16_t direction){
	RELEASE_X=0;
	steps_x_target = numberSteps;
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, direction_x);
	__HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);
	HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_1);
}

This then starts the PWM and I am counting the number of pulses via the timer update callback function:

void TIM1_UP_IRQHandler(void)
{
  if (__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_UPDATE))
  {
    if (__HAL_TIM_GET_IT_SOURCE(&htim1, TIM_IT_UPDATE))
    {
    	step_update('X');
    	__HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_UPDATE);
        __HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_CC1 );
      }
    }
  }

Inside this callback, step_update() is called taking as a parameter which axis I am working with.

The step_update function adds +1 to a count for the number of steps that have occured and stops the PWM when the number of steps is equal to the target number of steps that was set. It also calls a function which keeps track of the position in mm rather than steps. (Y and Z axis cases removed for the sake of brevity)

void step_update(char axis){
	switch(axis){
		case 'X':
			steps_x++;
			updatePosition(axis);
			if(steps_x==(2*steps_x_target)){ //check if 2* because the update event happens twice every pulse
				HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
				steps_x_target=0;
				steps_x=0;
				RELEASE_X=1;
				if(limitSwitchX_Trigger==1){
					positionX=0;
					limitSwitchX_Trigger=0;
					NVIC_EnableIRQ(EXTI0_IRQn);
				}
			}
			break;
		case 'Y':
 
			break;
 
		case 'Z':
 
			break;
 
		}
}

I'm sure this is not an entirely efficient way to do this however it works well enough except for the fact that I have no way to call the step_x() function and wait for it to finish before making the call to the next one. I added the volatile variables RELEASE_X which is set to 0 when step_x() is called and set to 1 when the step_update() function has stopped the PWM when the target steps are reached. I thought using this that I may be able to do something like this which I would expect to step 800 pulses in one direction and then step 800 pulses in another direction:

step_x(800,0);
while(RELEASE_X!=1);
step_x(800,1);

However what happens is that the while loop ends up blocking the Timer1_Update callback from occuring and the pulses don't get counted. I expected that because the pulse counting is done in an ISR callback that the MCU would just jump to the ISR from this while loop and update the steps until RELEASE_X is set to true and then advance to the next call of step_x()? Why is this not so?

Could someone suggest a way that I can write code which will allow me to call a function which steps a certain amount of steps while waiting for them to finish before moving on to the next call? I am trying to implement Bresenhams line algorithm next and so I need to step a certain amount of steps and then only return from the call and advance to the next line of code when the steps are complete. (Essentially, how can I make this function blocking but without toggling GPIO pins/bit bashing)

https://github.com/Blargian/EPR400

5 REPLIES 5
TDK
Guru

> However what happens is that the while loop ends up blocking the Timer1_Update callback from occuring and the pulses don't get counted.

The main loop won't block interrupts. Either interrupts are disabled, or they're lower priority than the currently executing code. It should happen exactly as you expect.

It sounds like you said the program works in general, so I'm not sure why it's not working with the "while(RELEASE_X!=1);" line. Perhaps you've changed something else as well.

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

Would that apply to while loops within other functions called from the main loop?

step_x(800,0);
while(RELEASE_X!=1);
step_x(800,1);

The code above is being called not from within the main loop but from a seperate function in another file. If I set a breakpoint in the timer update callback it is reached as long as I don't have the "while(RELEASE_X!=1)" line. I have all of my interrupt priorities set to 0 for NVIC and I'm not disabling the interrupts for the timers explicitly anywhere. I should add that I have declared RELEASE_X as volatile so that the compiler doesn't optimize out the read value. If I move the while loop to within the step_x function I get the same behaviour.

TDK
Guru

Functions called from the main loop will execute at the same priority as the main loop. The MCU doesn't know it's a different function.

Be aware setting breakpoints isn't always the best way to verify behavior. They can act funny sometimes. You could also run your program, then hit pause and see where it is. If it's stuck in the "while(RELEASE_X!=1);" loop, you could investigate further to see why.

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

If I pause the program remains in this while loop. I also set a break point in the callback. If I have this "while(RELEASE_X!=1);"  loop present then the breakpoint in the callback doesn't get triggered but if I uncomment this line then it does.

Hmm, I'm not really sure. Seems like it should be working, but maybe I'm missing something.
If you feel a post has answered your question, please click "Accept as Solution".