2018-04-20 07:24 PM
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 cycledTerm = (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 okelse if(pid_out < 0)
DutyCycle = DutyCycle + pid_out; // this is overflowingelse
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; }}
}
2018-04-20 10:06 PM
I think that DutyCycle should be an int16_t too...
2018-04-21 05:08 AM
'
if the value of pid is less than 0, the returned value of DutyCycle is somewhere like 65123,'unlikely due to overflow - if true, throw out the compiler - as it is wrong.
likely due to the DutyCycle going negative through successively adding a negative number to it.
'For example :
DutyCycle = (uint16_t)50 - (int)(-2) , i would expect to get 48.'
in that case, throw out your expectation - as it is wrong.
2018-04-21 08:56 AM
As the others suggested.
Data type promotion in C is sometimes a bit peculiar.
It is ALWAYS a good idea to test and validate algorithms (like your PID controller) on a PC environment, with easy and convenient debugging + logging.
2018-04-21 10:34 AM
>>likely due to the DutyCycle going negative through successively adding a negative number to it.
Would suspect that too, would suggest instrumenting rather than probing in the debugger.
I'd probably range check it rather than blindly apply.
Would also stay in signed 32 bit variables instead of doing a lot of unnecessary casting back and forth. 16-bit math isn't any more efficient in this context. And TIM2 is 32-bit wide
2018-04-21 05:04 PM
I would expect,
DutyCycle = (uint16_t)50 - (int)(-2) , i would expect to get 52
2018-04-21 05:45 PM
In the end i did not find the root cause for this behaviour, but i used a diferent aproach, trying limit the integrator (anti-windup).
After the calculations are made, i only update DutyCycle = pid result, this seems to work pretty well after tuning the pid parameters
Sorry for the mistake, its basic math.... +(-) results -, yes
DutyCycle = (uint16_t)50 + (int)(-2) should yield 48.
2018-04-21 08:37 PM
don't try to fix your problem: you have a problem because there is a logic flaw in your approach. once you fix the logic, the problem will just go away.