AnsweredAssumed Answered

Variable overflows inside timer irq handler - stm32f427

Question asked by anton.bogdan on Apr 21, 2018
Latest reply on Apr 22, 2018 by dhenry

Hello,

i am using a stm32f427 trough C with IAR compiler, and i am facing a strange situation.

 

To have a overview, the functionality of the app,  is relaying on 3 ISR's.

 

Timer1 IRQ handler - runs at 25khz where  some comutation, and update dutycycle registers is performed

Timer2 IRQ handler - is used to calculate the rpm of the motor, via 3 hall sensors events, the rate of this isr can vary, depending on the speed of the hall signals.

Timer4 IRQ handler - runs at a fixed 1000hz rate, where i compute some PID algorithm

 

The problem is in timer4 irq handler,    if the value of pid is less than 0, the returned value of DutyCycle is somewhere like 65123,

 

For example :

 DutyCycle = (uint16_t)50 - (int)(-2) , i would expect to get 48.

 

If the pid_out is <=0, the dutycycle value is ok.

 

Why is this behaviour?

 

 

 

I have posted bellow the code from the irq handlers, as well as the variables declared globaly

 

 

 

 

 

uint16_t DutyCycle = 50;

 

float iTerm = 0.0;
float iTerm_last = 0.0;
float dTerm = 0.0;
float p_out = 0.0;

float KP = 0.2;
float KI = 0;
float KD = 0;

float SampleTime = 0.001;
int16_t pid_out =0;

 

 

 


void TIM4_IRQHandler(){


    if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
     {   TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
 

p_SetPoint = 200; // set desired speed for motor at 200rpm
p_error = p_SetPoint - mrpm; // calculate the error

iTerm = iTerm_last + ((float)p_error * SampleTime);
iTerm_last = iTerm; // save current iTerm for the next cycle
dTerm = (p_error - p_error_last)/SampleTime;
pid_out = (KP * p_error) + (KI*iTerm) + (KD*dTerm);
p_error_last = p_error;


if(pid_out > 400)
     DutyCycle= 400; // this works ok

else if(pid_out < 0)
    DutyCycle = DutyCycle + pid_out; // this is overflowing

else
    DutyCycle = pid_out;

 

}
}

 

 

 

 


void TIM1_CC_IRQHandler()
{

   if (TIM_GetITStatus(TIM1, TIM_IT_CC4) != RESET)
       {    TIM_ClearITPendingBit(TIM1, TIM_IT_CC4);

 

            if(DutyCycle < 400)

             { // safe guard not to exceed 400 dutycycle
                 TIM1->CCR1=DutyCycle; // update Ch1 duty cycle
                 TIM1->CCR2=DutyCycle; // update Ch1 duty cycle
                 TIM1->CCR3=DutyCycle; // update Ch1 duty cycle

             }

}

 

 

 

 

 

void TIM2_IRQHandler()
{   uint8_t nSample = 6;

 

 

    if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
     {   TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
   

       t_sum = (uint16_t)TIM2->CCR1;
       t = (uint32_t)(t_sum *14);
       t= t * 18;
       t = t/1000;
       t= 60000/t;

t_buf=t_buf+t; // store in the buffer for average
t_cnt++;

if(t_cnt==nSample)

   {
       mrpm = t_buf/t_cnt;
       t_cnt=0;
      t_buf=0;
    }

  }

}

Outcomes