简体   繁体   中英

STM32 - While loop blocking behaviour of timerUpdate callback in stepper motor application

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 two parameters which are the number of steps to make and the direction to move in. The function sets the number of steps as the target number of steps in a global variable, sets the direction via GPIO write and then starts the PWM in interrupt mode using the HAL library:

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

It's not really an answer as to why this happened but I solved the problem by disabling the timer update and global interrupts in CubeMX under the NVIC tab. I removed the callback functions from my main.h and main.c and then I modified the step_x function to be:

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);
    while(RELEASE_X!=1){
         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 );
              }
    }
    }
}

Basically just moved the code that was in the callback function to within the while loop in the step_x function. The function is now a blocking function which is atually what I need anyway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM