|
|
View previous topic :: View next topic |
Author |
Message |
bfemmel
Joined: 18 Jul 2004 Posts: 40 Location: San Carlos, CA.
|
Interrupt Driven PSP Port Communication Problems |
Posted: Mon Apr 18, 2005 10:38 am |
|
|
I am having problems with communications over the PSP port. We use it to communicate between a Windows CE system and a PIC18F6520. I recently rewrote the PSP routines to be interrupt driven since we were having problems with the previous communications routines after we revised the CE code from VB to C++. The C++ code was much faster than the VB code and showed a bug in the code prompting the rewrite.
The first problem was that we started missing bytes and having the communications hang. It seems that the CE code was so fast that if the PIC received or sent a byte and then set the external ready bit to signal the CE computer that the CE computer may have serviced the PSP port again before the PIC had left the interrupt routine. That at first did not sound like a problem to me, I just figured that the PIC would exit the interrupt and reenter right away to service the port again. But this was not happening. When I checked the Assembly listing I noticed that the code clears the PSP interrupt bit at the end of the routine right before it jumps back to the interrupt handler:
BCF F9E.7
GOTO 0084
This seems a bit strange to me. Is there a simple way around this? I would think that the interrupt should be cleared on entering the routine not on exiting. Right now I am setting a flag in the INT _PSP instead of setting the external PIC_Ready bit and then setting that external signal in my main loop outside of the interrupt. Of course this makes the PSP interrupt kind of a mute thing. I would do just as well with a polled routine because of that problem.
The second problem, and one that I have not fixed yet, is that even after we fixed the first problem, we still get a lot of errors in the communications, usually bad data in the command or status response bytes. We can lessen the errors by sprinkling the C++ code with 1 millisecond sleep statements but why do we need to do that?
Here is an example of the C++ Code that reads from and writes to the PIC without any sleep statements. The 0x188 port address is the external PIC Ready bit which is cleared in hardware whenever a read or write is done to port 0x180 which is the PSP port of the PIC. When we insert sleep(1) statements in between all the reads and writes we end up with communications that is a lot more reliable.
Code: | /* Send a two byte command to the PIC */
while ((pPIC->m_prlcRead(0x188) & 0x01) == 0);
pPIC->m_prlcWrite(0x180, 0x52);
while ((pPIC->m_prlcRead(0x188) & 0x01) == 0);
pPIC->m_prlcWrite(0x180, 0x50);
/* Read the status response from the PIC */
while ((pPIC->m_prlcRead(0x188) & 0x01) == 0);
sData = pPIC->m_prlcRead(0x180) << 8;
while ((pPIC->m_prlcRead(0x188) & 0x01) == 0);
sData += pPIC->m_prlcRead(0x180);
if (sData == 0x7270) // Checks for bad status returned
{ // Read two words of data from PIC
while ((pPIC->m_prlcRead(0x188) & 0x01) == 0);
asBlock[0] = pPIC->m_prlcRead(0x180) << 8;
while ((pPIC->m_prlcRead(0x188) & 0x01) == 0);
asBlock[0] += pPIC->m_prlcRead(0x180);
WAITREADSHORT;
while ((pPIC->m_prlcRead(0x188) & 0x01) == 0);
asBlock[1] = pPIC->m_prlcRead(0x180) << 8;
while ((pPIC->m_prlcRead(0x188) & 0x01) == 0);
asBlock[1] += pPIC->m_prlcRead(0x180);
}
|
Here is the code from my PSP port service routine.
Code: | #INT_PSP
void PSP_Service( void ) {
if ( psp_input_full() ) { // get the byte sent from host
if ( psp_overflow() ) { // something definitely went wrong
PSP_Buffer[0] = PSP_DATA; // clear out the register
PSP_BufferLen = PSP_BUFFER_ERROR; // signal an error to reset communication
} /* end of ( psp_overflow() ) */
else { // if it's not an overflow then input the command and data
if ( PSP_BufferIndex == 0 ) { // If this is the first byte received
Cmd_Timeout = CMD_TIMOUT_DELAY; // Reset the Command Timeout to track a RCV that hangs
commStatFlag = PSP_RCV; // Let's others know we are in the receive state
} /* end of PSP_BufferIndex ==0 */
if (PSP_BufferIndex < MAX_PSP_BUFFER_SIZE) { // should always run through here if all is well
PSP_Buffer[PSP_BufferIndex++] = PSP_DATA; // put the data into a buffer
}
else // Buffer overrun error
PSP_BufferLen = PSP_BUFFER_ERROR; // Set this to indicate an error and reset communications
if (PSP_BufferIndex == 2) {
switch ( PSP_Buffer[0] ) {
case 0x41: // Read an ADC value
case 0x53: // Read motor speed
PSP_BufferLen = 2;
break;
case 0x48: // Set heater power
PSP_BufferLen = 4;
break;
default: // unrecognized command
PSP_BufferLen = PSP_BUFFER_ERROR; // Set this to indicate error and reset PSP
break;
} /* end command length switch */
} /* end of PSP_Buffer == 2 */
if (PSP_BufferLen == PSP_BUFFER_ERROR) { // if there was an error, reset comm parameters
Start_PSP_Wait(); // set the comm status to wait and reset the buffers
}
else if (PSP_BufferLen > PSP_BufferIndex) // have not reached end data yet so set PIC_Ready
setReadyBit = TRUE; // Next time through main loop, set PIC Ready
// Set_PIC_Ready(); // sets the external bit to signal the host
else
rcvComplete = TRUE; // TRUE signals that all bytes have been received and that
// this is the end of the input string!
// we won't set the PIC_READY until the command is complete and the
// transmit buffer is set up. That will happen in the CheckCommand routine
} /* end of psp_overflow() = False */
} /* end of psp_input_full() */
else if ( !psp_output_full() ) { // Check to see if the output buffer is empty
if (PSP_BufferLen > PSP_BufferIndex) { // if there is still more to send ...
PSP_DATA = PSP_Buffer[PSP_BufferIndex++]; // put the buffer data into the port and increment counter
setReadyBit = TRUE; // Next time through main loop, set PIC Ready
} /* end of "still more data to send" */
else // if the transmission is complete ...
Start_PSP_Wait(); // set the comm status to wait and reset the buffers
} /* end of send byte */
} /* end of PSP_Service() Interrupt */
|
Does anyone have any ideas as to what I should check next in trying to debug this problem? I am at a loss for what to look at next. I know that this is difficult without the schematic for the hardware and a more complete listing from my code but given the fact that the code worked fine with the VB code and now has a problem with the faster C++ code, I am assuming that the parts of the code that empty the buffer, perform the command and refill the buffer with command response status and data are still working fine. I am just looking for a direction to go in debugging this.
Many Thanks - Bruce |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Apr 18, 2005 12:22 pm |
|
|
Quote: |
I noticed that the code clears the PSP interrupt bit at the end of the
routine right before it jumps back to the interrupt handler:
Is there a simple way around this? |
Do a search in the CCS manual for the keyword: NOCLEAR |
|
|
bfemmel
Joined: 18 Jul 2004 Posts: 40 Location: San Carlos, CA.
|
|
Posted: Mon Apr 18, 2005 2:41 pm |
|
|
PCM programmer;
Thanks for the tip on instructing the compiler to not clear the int flag. I added the NOCLEAR option to the interrupt declaration and then added a bit clear to the beginning of the routine like this;
Code: |
bit_clear(*0xF9E,7); // clears the interrupts at the beginning of the routine instead of the end
|
and that part works just peachy. Now the interrupt runs in a tight loop to get the data as required instead of shelling out to the main loop to say it is ready for another byte.
Now if I could only get the data going back and forth to be as good. It seems that when we rush things using the interrupts and not putting the sleep in the C++ code on the host that the data transmission gets garbled a good percentage of the time.
I am still very confused. I guess I need to break down and get a logic analyzer.
Any more ideas from anyone would be welcome.
Bruce |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|