Shop OBEX P1 Docs P2 Docs Learn Events
Serial data receive problem. Need some suggestions. — Parallax Forums

Serial data receive problem. Need some suggestions.

Don MDon M Posts: 1,653
edited 2012-09-12 05:19 in Propeller 1
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:

TEK0010.JPG


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:

ACK 1.png


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:

ACK 2.png


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
681 x 299 - 10K
640 x 480 - 76K
543 x 289 - 10K

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-09-11 09:16
    Which serial object are you using? FullDuplexSerial's rxtime returns a byte value, but you're checking for $1_00, which is bigger than a byte. But maybe your rx_time is different. Also, have you tried waiting a little longer to see if your hit ratio improves? Also, what happens if there is residual data in the buffer ahead of the ACK?

    -Phil
  • Don MDon M Posts: 1,653
    edited 2012-09-11 10:01
    Which serial object are you using? FullDuplexSerial's rxtime returns a byte value, but you're checking for $1_00, which is bigger than a byte. But maybe your rx_time is different.

    Here's the serial.rx_time code:
    pub rx_time(ms) | t, data 
    
    '' Wait ms milliseconds for a data word (or buss reset) to be received
    '' -- returns -1 if nothing received
    
      t := cnt                                                      ' sync with system cnt
      repeat ms                                                     ' wait up to ms milliseconds
        data := rx_check                                             ' check buffer
        if (data => 0)                                               ' if something there
          quit                                                      ' abort loop
        waitcnt(t += MS_001)                                        ' else wait 1ms
        
      return data
    
    
    Also, have you tried waiting a little longer to see if your hit ratio improves?

    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.
    Also, what happens if there is residual data in the buffer ahead of the ACK?

    I thought I was clearing out the buffer by using the command serial.rx_flush?
  • Don MDon M Posts: 1,653
    edited 2012-09-11 10:04
    I should add that the serial data I am working with is 9 bit and that the serial object was modified to handle 9 bit.
  • Dave HeinDave Hein Posts: 6,347
    edited 2012-09-11 10:18
    What value do you get from rx_time? Is is a -1 or something else?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-09-11 10:43
    Looking at your analyzer traces, your output data is inverted, while the return data from the device has normal polarity. Is this simply a function of where you're probing the signals?

    -Phil
  • Don MDon M Posts: 1,653
    edited 2012-09-11 10:51
    Dave Hein wrote: »
    What value do you get from rx_time? Is is a -1 or something else?

    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.
    pub reset    
    
      serial.rx_flush
    
      term.dec(serial.rx_check)      ' to see what's in buffer after flush
      term.tx(13)
      
      serial.tx($1_08)
      serial.tx($0_08)
    
      l := serial.rx_time(20)
      term.dec(l)                   ' to see decimal value in buffer
      term.bin(l, 12)               ' to see binary value in buffer
      if l == $1_00
        RESULT := 1
        term.str(string("Y",13))
      else
        RESULT := 0
        term.str(string("N",13))  
    
    

    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.

    PST 1.PNG


    Any ideas?

    Post edit: l is defined as a word
    338 x 553 - 10K
  • Don MDon M Posts: 1,653
    edited 2012-09-11 10:52
    Looking at your analyzer traces, your output data is inverted, while the return data from the device has normal polarity. Is this simply a function of where you're probing the signals?

    -Phil

    Phil- the data inversion is handled by the serial object.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-09-11 10:54
    Don,

    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
  • Don MDon M Posts: 1,653
    edited 2012-09-11 10:55
    BTW- The far left bit that is set- 000100000000 is the 9th bit that is set in this protocol for an ACK.
  • Don MDon M Posts: 1,653
    edited 2012-09-11 11:01
    Here's an updated code and screen shot from PST. There were some changes made from previous post. I changed the .bin to 16 bits to indicate the full word in binary and the screen shot to show the decimal value that I missed the first time.
    pub reset    
    
      serial.rx_flush
    
      term.dec(serial.rx_check)      ' to see what's in buffer after flush
      term.tx(13)
      
      serial.tx($1_08)
      serial.tx($0_08)
    
      l := serial.rx_time(20)
      term.dec(l)                   ' to see decimal value in buffer
      term.bin(l, 16)               ' to see binary value in buffer
      if l == $1_00
        RESULT := 1
        term.str(string("Y",13))
      else
        RESULT := 0
        term.str(string("N",13))
    
    

    PST 2.PNG
    356 x 406 - 9K
  • Don MDon M Posts: 1,653
    edited 2012-09-11 11:48
    Upon some further investigation with the logic analyzer I see some varied response times from this device giving me trouble. It seems the response has to come later than 34uSec or it isn't caught correctly. In fact in some of the traces the ACK response comes before the second byte of the transmit has finished.

    How do you code around that?

    Here are some screen shots.

    These are ok:
    This one ACK'd in 72 uSec
    ACK 4 72 Y.png


    This one ACK'd in 80 uSec
    ACK 3 80 Y.jpg


    Here's one that ACK'd before the second byte of the transmit finished
    ACK 6 U.jpg
    890 x 311 - 13K
    1024 x 287 - 48K
    1024 x 273 - 40K
  • Don MDon M Posts: 1,653
    edited 2012-09-11 11:55
    Maybe I need to be receiving all the time and then just flush the buffer prior to sending my transmit command....
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-09-11 12:12
    Don M wrote:
    Maybe I need to be receiving all the time ...
    Most serial objects do receive all the time, unless you specifically stop, then restart them.

    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
  • Don MDon M Posts: 1,653
    edited 2012-09-11 13:02
    Most serial objects do receive all the time, unless you specifically stop, then restart them.

    My program has only been receiving when it's told to but I may have to rethink that.
    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.

    I know I didn't mention it before but the baud rate is 9600. Shouldn't be a problem (I think...).
    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.

    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.
    Can you post your serial object, please? Or why not post all of your code.

    Phil- I sent you an email as listed in your profile.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-09-11 13:20
    Don,

    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
  • Don MDon M Posts: 1,653
    edited 2012-09-11 13:40
    So in order to be "receiving in the background" how do I go about that? Are there some example projects or OBEX code that demonstrate this type of procedure I can learn from?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-09-11 13:51
    If your serial object starts another cog, it's already receiving in the background. You do not have to do anything else except remembering not to call its stop method. Also, note that just because 9600 baud is relatively slow, that does not mean that reception is unaffected by timing errors. Still, though, if your serial object is based upon FullDuplexSerial, these should not be issues -- assuming that the external device's baudrate is accurate, which it might not be.

    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
  • Don MDon M Posts: 1,653
    edited 2012-09-11 14:23
    The serial object does launch another cog. I think it's a matter of writing (understanding) the logic to utilize this and to know when to ask for the data.
  • Don MDon M Posts: 1,653
    edited 2012-09-11 14:49
    Well until I can find another way here's my work around:
    pub reset    
    
      serial.rx_flush
      
      serial.tx($1_08)
      serial.tx($0_08)
      pause(10)                     ' to wait for data to accumulate in buffer
     if (serial.rx_check >> 8) == 1    ' to check for 9th bit received
        RESULT := 1
        term.str(string("Y",13))
      else
        RESULT := 0
        term.str(string("N",13))
    
    

    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
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-09-11 15:34
    Don M wrote:
    It's probably ugly but it works.
    There definitely is an ugh factor there. :)

    Is there anything in your serial object that mentions the term "half duplex" ?

    -Phil
  • Don MDon M Posts: 1,653
    edited 2012-09-11 16:44
    Unfortunately no there isn't :(
  • Don MDon M Posts: 1,653
    edited 2012-09-12 05:19
    Don M wrote: »
    Unfortunately no there isn't :(

    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
Sign In or Register to comment.