Hi,
At the moment I'm not doing anything with the USART interrupt - it's never been fired during these tests. But I'll need to use it for the "front end" later on - if I get there - and the is to stuff data into a buffer and signal the main program when a LF or CR arrives.
Just so we're all on the same page, here are the current interupts:
INT2_INT - High priority ISR in ASM
IC2QEIF_INT - High priority ISR in PBP but "declared" as ASM in the INT_LIST macro
TMR2_INT - Low priroity ISR in PBP
RX_INT - Low priotity ISR in PBP
I originally had the TMR2 interrupt as high priority but then I didn't get more than a few kHz before it started to miss pulses. The DoServo routine that is run as the TMR2 ISR is quite "heavy" since it does all the math including the PID routine:
Code:
DoServo: 'Interrupt handler starts here.
PortB.5 = 1 'Used for timing purposes
GetPosition:
'Since the position counter isn't double buffered we can get to situations
'where the lowbyte overflows between readings of the high and low byte. This
'is prevented by reading the high byte two times and compare the two readings.
'If they are the same then we're fine, if not re-read the registers.
PosHigh = POSCNTH 'Get high byte of counter
PosLow = POSCNTL 'Get low byte of counter
PosTemp = POSCNTH 'Get high byte again
If PosHigh - PosTemp = 0 then Goto Done 'Compare, if equal we're done.
PosHigh = POSCNTH 'If not, get values again.
PosLow = POSCNTL
Done:
'The high word of the Position variable is handled by the RollOver ISR that gets
'tripped by IC2QEIF when POSCNT = MAXCNT.
Position.Word0 = POSHIGH * 256 + PosLow 'Put high and lowbyte together.
Speed = Position - oldPosition 'Calculate current motor speed.
INTCON3.4 = 0 'Temporarily disable INT2 interrupt
TempStepBuffer = StepBuffer
StepBuffer = 0
INTCON3.4 = 1 'Re-enable INT2 interrupt.
If TempStepBuffer.7 = 1 then 'Step buffer is negative
Setpoint = Setpoint - ABS (TempStepBuffer)
Else
SetPoint = Setpoint + TempStepBuffer
Endif
pid_Error = Setpoint - Position 'Calculate error....
'Now we have our error-signal in the variable that the PID-routine expects
'so we call the PID-filter with a GOSUB. The filter will respond with the
'output in variable pid_out.
Gosub PID 'and send to PID filter
' (PID filter execution time measured to ~190uS worst case @20Mhz)
If pid_out.15 = 0 then 'If the output from the pid-filter
Direction = 1 'is positive we want to drive the
Duty = pid_Out 'motor forward.
Else
Direction = 0 'If it's negative we want to drive
Duty = ABS (pid_Out) 'it backwards.
Endif
CCP1CON.5 = Duty.1 'Set the two LSB's of the dutycycle-
CCP1CON.4 = Duty.0 'register. Then shift them out and
CCPR1L = Duty >> 2 'set the remainig 8 bits.
oldPosition = Position 'Store position for next interrupt.
ISRCount = ISRCount + 1
PortB.5 = 0
@ INT_RETURN ;ISR is complete, return from here.
The actual PID code isn't shown here, I've measured the execution time of the complete DoServo ISR and it seems to vary alot, from 160uS all the way up to 400uS.
So, I guess I'll need to stick with DT-Ints since re-writing the DoServo routine including the PID code in ASM would take me years. Question is what else, if anything, can be improved to increase the speed. The thing is that I was hoping to add more code to the DoServo routine but I guess that may not be a good idea.
Thanks alot guys!
/Henrik.
Bookmarks