Thursday, September 2, 2010

Windows to PIC Interface - (Hexapod Part 7)

The full source code can be found here.

In my last post I mentioned that the PIC randomly stops responding to instructions from the PC, although it holds the servo in position so the interrupt was still running.

My serial port monitor showed me that I was still sending data so it probably wasn't a problem at the PC end. I'm using a Prolific USB to serial converter so that could have been failing but it seemed unlikely. The key indicator that it was my firmware was that if I hard reset the PIC everything started working again.

After a quick debugging session with MPLab I found that it was stalled waiting for more bytes to arrive in the RX buffer. The offending code looks like this

SetPositions:
    btfss PIR1, 5 ;has something been received?
    goto $-2
    movf RCREG, w
;check for servo number
    btfss PIR1, 5 ;has something been received?
    goto $-2
    movf RCREG, w
    movwf SERVO0POS
goto CommsLoop

The problem is that when a comms error occurs, in this case a buffer overrun, the receiver is disabled. This meant the processor endlessly waited for bit 5 of PIR1 to be set, which indicates when something is received. I knew this routine was too basic when I wrote it but I didn't think it was going to bite me this early on.

The solution, which is not a complete solution, is to check for comms errors and if there is one, clear the error and resume receiving. This does mean that some data is lost and this can be observed. When the scroll bar on the UI is moved continuously (causing an overrun, I assume while the processor is in the ISR) a byte may be dropped. This will cause the servo to jump to the position of whatever byte is received when reception is resumed.

I think the proper solution is to use a second, higher priority, ISR that adds bytes received into a file register buffer for later processing. This may cause some latency in the servo ISR but should be small enough to have no noticeable impact. I'll also consider running the processor at 20Mhz, instead of 4Mhz. This would mean that receiving a byte and moving it into a buffer will have 1/5th the impact it would currently have.

Anyway, the current 'solution' (stop gap?) is as follows

SetPositions:
 call ReceiveIntoW ;wait for servo number
 ;check for servo number
 call ReceiveIntoW ;wait for position
 movwf SERVO0POS
goto CommsLoop


ReceiveIntoW:
 btfsc PIR1, 5  ;has something been rx'd?
goto CompleteReceive            ;yes, go deal with it
 btfss RCSTA, OERR ;has there been an overrun error?
goto ReceiveIntoW               ;no, go check for rx'd data
 bcf  RCSTA, CREN ;clear the error by reseting the receiver
 bsf  RCSTA, CREN
goto ReceiveIntoW               ;go wait again

CompleteReceive:
 movf RCREG, w
 return

No comments:

Post a Comment