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: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.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.
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