Serial data receive problem. Need some suggestions.
Don M
Posts: 1,653
My project can be connected to various brands of devices that communicate serially. The problem I'm having is that with one certain device I don't always get recognition of the ACK that it sends. My logic analyzer always shows that it ACK's and my Tek digital scope (right at the Prop pin) always shows that it ACK's. The receive line is tied high (3.3V) and pulled low by the device.
Here's a screen shot from the scope:
I think the problem is with how quickly it ACK's. Here is a screen shot of an ACK from the device that isn't always recognized. The Prop is sending the Hex 08 08 in the top line:
It ACK's approx 34 uSec after the last 08. Sometimes my program catches it sometimes not. About 50 / 50.
Here's a screen shot of an ACK from a device that is always recognized:
The ACK from this device is approx 0.46 mSec after the last 08.
Here is a represetation of the code I am using:
I added the term.str commands just to monitor on PST otherwise it they aren't in there. It doesn't seem to affect the outcome either way. I also tried using serial.rx and that makes no difference either other than the program hangs if there isn't a device connected or doesn't reply back. It's like I need to start receiving before I send the second 08 but I don't how I could do that as the program would wait to either start receiving or just hang before the second 08 is sent.
So how can I solve this? Any suggestions?
Thanks.
Don
Here's a screen shot from the scope:
I think the problem is with how quickly it ACK's. Here is a screen shot of an ACK from the device that isn't always recognized. The Prop is sending the Hex 08 08 in the top line:
It ACK's approx 34 uSec after the last 08. Sometimes my program catches it sometimes not. About 50 / 50.
Here's a screen shot of an ACK from a device that is always recognized:
The ACK from this device is approx 0.46 mSec after the last 08.
Here is a represetation of the code I am using:
pub reset serial.rx_flush serial.tx($1_08) serial.tx($0_08) if serial.rx_time(10) == $1_00 RESULT := 1 term.str(string("Y",13)) else RESULT := 0 term.str(string("N",13))
I added the term.str commands just to monitor on PST otherwise it they aren't in there. It doesn't seem to affect the outcome either way. I also tried using serial.rx and that makes no difference either other than the program hangs if there isn't a device connected or doesn't reply back. It's like I need to start receiving before I send the second 08 but I don't how I could do that as the program would wait to either start receiving or just hang before the second 08 is sent.
So how can I solve this? Any suggestions?
Thanks.
Don
Comments
-Phil
Here's the serial.rx_time code:
Per your suggestion I increased the rx_time from 10 to 20 and it's no different. I don't understand your suggestion here as the device ACK's way less than 1/2 a mSec. With all the other serial devices I try that respond later than this device the code always returns that an ACK was received.
I thought I was clearing out the buffer by using the command serial.rx_flush?
-Phil
Here is a modifed version of my code just to poll this device and read it's reply. There is no other routine run. I have this setup to where I press a button and it runs this code only 1 time with each press.
And here is a screen shot of PST after several runs. You can see there is an inadvertant bit set when it fails. I don't know where that bit comes from. You can see the buffer was flushed each time and indicates a -1.
Any ideas?
Post edit: l is defined as a word
Phil- the data inversion is handled by the serial object.
That extra "one" bit looks like it's coming from a baudrate timing problem. Either the receiver is set for too low a baudrate or the device is transmitting too fast. Try adjusting the baudrate in your serial object up a little, and see if that helps.
Either that, or the device is sending the ACK before the receiver is ready to receive it. How soon after starting the serial object do you call reset?
-Phil
How do you code around that?
Here are some screen shots.
These are ok:
This one ACK'd in 72 uSec
This one ACK'd in 80 uSec
Here's one that ACK'd before the second byte of the transmit finished
I still think it could be a baudrate issue. Those bytes received as %1_1000_0000 are indicative that the 9th bit was received while the receiver was still sampling the 8th bit. IOW the receiver is too slow.
OTOH, if the serial object that you are using does not do its receiving in the background or is not full duplex, that could also cause the problem you're seeing, since it's not switching from transmit to receive soon enough and sees the first data bit as the start bit.
Can you post your serial object, please? Or why not post all of your code.
-Phil
My program has only been receiving when it's told to but I may have to rethink that.
I know I didn't mention it before but the baud rate is 9600. Shouldn't be a problem (I think...).
As I mentioned above it is an on / off setup as I have written it and I think you are right in that it doesn't switch on the receive soon enough to catch the bits correctly. However if you look in post #12 you see 1 trace in particular that receives the ACK before the transmit is finished (at least that is the way I see it) but it still is a valid operation. In some other commercial products that also communicate with this same device they handle that situation ok. I have looked at the logic trace to prove it and I wonder how it can even be. It's as if the device knows ahead of time what it is receiving. I tried fooling it by altering the second byte as I thought that maybe it didn't care about authenticating the proper command but I couldn't fool it.
Phil- I sent you an email as listed in your profile.
Regarding the device sending the ACK before the second byte is received, that's not so unusual. Some devices will not wait for the stop bit to write data to the receive buffer, as long as the last data bit is received okay. It's not the best policy, of course, since a stop bit of the wrong polarity could signify a framing error.
I'll take a look at my email now, and see what you sent me.
-Phil
OTOH, if your serial object object runs in the foreground and suspends reception to transmit data, you will not be able to get it to work correctly when the external device returns an ACK so quickly.
-Phil
It's probably ugly but it works. I know in the above threads where I showed the binary value the 9th bit was always set if there was a response. It was the 8th bit that was always messing up the earlier logic.
Any other suggestions I'm all ears.
Thanks.
Don
Is there anything in your serial object that mentions the term "half duplex" ?
-Phil
Actually I stand corrected. The serial object is half duplex. I solved it thus far by using 2 instances of the object- 1 for receiving and the other for transmitting. Hopefully I won't run out of cogs for my project. Maybe I can have the serial object converted to full duplex.
So evidently the previous setup wouldn't switch fast enough to the receive mode in order to catch the data.
Thanks everyone for your help and comments.
Don