Shop OBEX P1 Docs P2 Docs Learn Events
Loopback problem. — Parallax Forums

Loopback problem.

StephenMooreStephenMoore Posts: 188
edited 2012-08-18 21:05 in Propeller 1
This I know is one of the most basic microcontroller problems and yet it is also one of the most time consuming.... asynchronous serial data comm.

I have Pin 0 jumped to Pin 1 on a Prop USB Protoboard.

Code Ex 1 one works, code Ex 2 gives gibberish.


Ex 1:
CON 
        _clkmode = xtal1 + pll16x
        _xinfreq = 5_000_000
        
       drillRx = 0
       drillTx = 1 
VAR


  byte char[128]
  
OBJ


  pst: "Parallax Serial Terminal"
  drill: "FullDuplexSerial"


PUB main | i, k
 
  
  pst.Start(115200)
  drill.Start(drillRx, drillTx, 0, 115200)
  waitcnt(clkfreq * 2 + cnt)
repeat
 drill.str(@x2)
  i := 0
  repeat strsize(@x1)
   char[i++] := drill.rx
  
    
 pst.str(@char) 
 waitcnt(clkfreq+cnt)     


DAT
x1       byte  "0020000000001000", $0D,0
y1       byte  "0000002000001000", $0D,0
rot1     byte  "0000000000301000", $0D,0
x2       byte  "-020000000001000", $0D,0
y2       byte  "0000-02000001000", $0D,0
rot2     byte  "00000000-0301000", $0D,0 

Ex 2:
CON 
        _clkmode = xtal1 + pll16x
        _xinfreq = 5_000_000
        
       drillRx = 0
       drillTx = 1 
VAR


  byte char[128]
  
OBJ


  pst: "Parallax Serial Terminal"
  drill: "FullDuplexSerial"


PUB main | i, k
 
  
  pst.Start(115200)
  drill.Start(drillRx, drillTx, 0, 115200)
  waitcnt(clkfreq * 2 + cnt)
repeat
 drill.str(@x2)
  i := 0
 waitcnt(clkfreq / 1000 + cnt)
 repeat while (char[i++] := drill.rxcheck) <> -1     
 pst.str(@char) 
 waitcnt(clkfreq+cnt)     


DAT
x1       byte  "0020000000001000", $0D,0
y1       byte  "0000002000001000", $0D,0
rot1     byte  "0000000000301000", $0D,0
x2       byte  "-020000000001000", $0D,0
y2       byte  "0000-02000001000", $0D,0
rot2     byte  "00000000-0301000", $0D,0 

Also, I really need to talk to a drill that is RS-232. Does anyone have any suggestions for a reliable and cheap CMOS to RS-232 converter?

sm

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-08-18 12:31
    I've used this chip many times with the Prop to communicate with RS232 devices.
  • kwinnkwinn Posts: 8,697
    edited 2012-08-18 12:33
    This line:

    >> repeat while (char[i++] := drill.rxcheck) <> -1

    := sets char[i++] to the value of drill.rxcheck

    should that not be a comparison ( == ) ?

    Never mind, I see what you are trying to do.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-08-18 12:40
    @Kwinn,

    I don't think he wants a comparison there.

    @sm,

    What do you mean by "gibberish". I'm not sure how your comparison will work since "char" is a byte array and "-1" is only meaningful as a long.

    I'd suggest using a long in the comparison with "-1" and then save the long to the byte array if it's not "-1".
  • StephenMooreStephenMoore Posts: 188
    edited 2012-08-18 12:50
    Hi guys.

    I'm not sure about it either.

    FullDuplexSerial.rxcheck says it returns a -1 if no byte available. I took -1 to be a signed twos complement byte value ($FF).

    By gibberish I mean not the string I sent out.
  • Mike GreenMike Green Posts: 23,101
    edited 2012-08-18 13:38
    -1 is a signed twos complement 32-bit value ($FFFFFFFF or -1). It's stored (into char) as an 8-bit value ($FF), but the conversion is done as the value is stored. The expression (char[i++] := drill.rxcheck) still is a 32-bit value.
  • StephenMooreStephenMoore Posts: 188
    edited 2012-08-18 14:12
    Does that mean the high byte of the 32 bit return value is stored into char or the low byte? Which would be $FF in either case.

    Also, do char..char[i+3] receive the return value from rxcheck?
  • Mark_TMark_T Posts: 1,981
    edited 2012-08-18 14:18
    repeat while (char[i++] := drill.rxcheck) <> -1
    

    You have a conditional expression with side-effects, usually a bad idea. The ++ operator is incrementing i everytime round the loop stomping $FF bytes all over memory. Separate condition from effects:
      repeat while (testvar := drill.rxcheck) <> -1
      char [i++] := testvar   ' side effect only if actually read.
    

    rxcheck is trying to be both a predicate and a data-transfer operation, hence the confusion.
  • Mike GreenMike Green Posts: 23,101
    edited 2012-08-18 14:53
    Because char is declared as a byte array, the Spin compiler produces byte store operations which store the low order 8 bits of the 32 bit stack value into the specified byte of char. As Mark_T mentioned, you're storing some $FF bytes into char, specifically, when .rxcheck doesn't have a serial byte to return, it returns a -1 ($FFFFFFFF) value which is stored into char, then the loop exits.
  • StephenMooreStephenMoore Posts: 188
    edited 2012-08-18 14:58
    Do you mean like this (which does not work either)?
    CON 
          _clkmode = xtal1 + pll16x
          _xinfreq = 5_000_000
          drillRx = 0
          drillTx = 1 
    VAR
      byte char[128] 
    OBJ
      pst  : "Parallax Serial Terminal"
      drill: "FullDuplexSerial"
      
    PUB main | i, k, testVar
      
      pst.Start(115200)
      drill.Start(drillRx, drillTx, 0, 115200)
      waitcnt(clkfreq * 2 + cnt)
      
    repeat
    
    
      drill.str(@myStr)
      i := 0
      waitcnt(clkfreq / 1000 + cnt)
     
          repeat while (testVar := drill.rxcheck) <> -1     
           char[i++]:= testVar
      
      pst.str(@char)
      
      waitcnt(clkfreq+cnt)     
    
    
    DAT
    myStr       byte  "This string is hard to read.", $0D,0
    
  • StephenMooreStephenMoore Posts: 188
    edited 2012-08-18 15:07
    Update:

    I changed Baud Rate to 9600 and get the following:

    PartialREad.jpg


    Which is better than gibberish but still short of the mark. Hasn't anyone tested FullDuplexSerial in loopback mode?

    sm
    784 x 922 - 82K
  • StephenMooreStephenMoore Posts: 188
    edited 2012-08-18 15:15
    Another update... this code works! But it does not work at Baud = 115200.
    CON       _clkmode = xtal1 + pll16x
          _xinfreq = 5_000_000
          drillRx = 0
          drillTx = 1
          
    VAR
      byte char[128]
       
    OBJ
      pst  : "Parallax Serial Terminal"
      drill: "FullDuplexSerial"
      
    PUB main | i, k, testVar
      
      pst.Start(115200)
      drill.Start(drillRx, drillTx, 0, 9600)
      waitcnt(clkfreq * 2 + cnt)
      
    repeat
    
    
      drill.str(@myStr)
      i := 0
      waitcnt(clkfreq/1000  + cnt)
     
          repeat while (char[i++] := drill.rxcheck) <> -1
           waitcnt(clkfreq/1000 + cnt)
           
      char[i-1] := 0 
      pst.str(@char)
      
      waitcnt(clkfreq+cnt)     
    
    
    DAT
    myStr       byte  "This string is hard to read.", $0D,0
    
  • Mike GreenMike Green Posts: 23,101
    edited 2012-08-18 15:27
    Your program is still incorrect. It stores an $FF byte into char when drill.rxcheck first returns a -1 (when the FDS buffer is empty) and it doesn't store a zero byte at the end of the string at that point. It's much better to have something like:
    repeat
       if (testVar := drill.rxcheck) == -1
          char[i]~
          quit
       char[i++] := testVar
    
  • StephenMooreStephenMoore Posts: 188
    edited 2012-08-18 16:54
    I see your point. If the returned value was actually $000000FF, I would interpret it as end of transmitted string instead of valid data. Only by looking at the returned value of $FFFFFFFF is the real empty buffer seen.

    Thanks for that subtlety.

    Still, the program only works with the millisecond delay inserted between character reads. That does not seem right.
  • kuronekokuroneko Posts: 3,623
    edited 2012-08-18 17:06
    ATM you're using rxcheck. How do you distinguish between end of string (i.e. ready for display) and character being received (at 9600 it takes a while)? Wouldn't the use of the (blocking) rx method and a delimiter (e.g. CR or even NUL) be easier here?
  • Mike GreenMike Green Posts: 23,101
    edited 2012-08-18 17:13
    What's happening is that the buffer size in FullDuplexSerial is only 16 bytes for transmit and 16 bytes for receive and your string is longer than 16 bytes. The first 16 bytes get copied to the buffer and the main program stalls one character at a time as the characters are transmitted. They're simultaneously received and placed in the receive buffer, but the receive part of the program doesn't execute until the string being transmitted is placed into the transmit buffer by FullDuplexSerial. At this point, it's transmitting the character 16 bytes from the end. The receive buffer has 13 characters in it at this point. With the WAITCNTs, the remaining 3 places in the buffer will fill up and additional characters will be discarded.

    I may have the numbers off by 1 or 2, but you need to shorten the test string or increase the buffer sizes for this program to work properly.
  • StephenMooreStephenMoore Posts: 188
    edited 2012-08-18 18:29
    True. Usually there will be an anticipated response sequence.

    For debugging the system I was using rxcheck to avoid locking up the program.

    I still can't tell the difference between hardware problems and FullDuplexSerial problems in loopback mode. As I say, I can't read anything at all at 115200 baud in loopback mode.
  • StephenMooreStephenMoore Posts: 188
    edited 2012-08-18 18:32
    Is there a version of FullDuplexSerial with larger buffers out there?
  • StephenMooreStephenMoore Posts: 188
    edited 2012-08-18 18:56
    Thanks Mr. Green for elucidating this. With a string size of 15 characters it works fine at the higher baud rate with out any waitcnt required.
  • cavelambcavelamb Posts: 720
    edited 2012-08-18 19:10
    Thanks Mr. Green for elucidating this. With a string size of 15 characters it works fine at the higher baud rate with out any waitcnt required.

    Mike is pretty sharp, isn't he?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-08-18 19:24
    sm,

    You might want to consider using a four port serial object. Tracy Allen's version is pretty slick and lets you easily set any size of buffers.
  • StephenMooreStephenMoore Posts: 188
    edited 2012-08-18 21:05
    Everybody involved...thanks.

    Here are my improvements:

    1) Changed code to proper method for receiving characters:

    2) Switched to "FullDuplexSerial4portPlus_0v3" and increased the rx/tx buffer sizes to eliminate character collisions

    3) Downloaded SimpleIDE version 0.8.1 to take advantage of the project feature using the SPIN compiler and the built in console... very nice piece of software.
    CON 
          _clkmode = xtal1 + pll16x
          _xinfreq = 5_000_000
          
          drillPort = 3
          drillRx   = 0
          drillTx   = 1
          drillCTS  = -1
          drillRTS  = -1
          drillBAUD = 115200
          
    VAR
      byte char[128]
       
    OBJ
      pst  : "Parallax Serial Terminal"
      drill: "FullDuplexSerial4portPlus_0v3"
      
    PUB main 
      
      pst.Start(115200)
      
      drill.Init
      
      drill.AddPort(drillPort, drillRx, drillTx, drillCTS, drillRTS, 32, 0, drillBAUD)
      
      drill.Start
      
      waitcnt(clkfreq * 2 + cnt)
      
    repeat
     char[0] := pst.CharIn
     pst.Char(pst#CS)
     
      case char[0]
      
       "1":
           drill.str(drillPort, @myStr1)
           getMsg
           drill.Str(drillPort, @myStr2)
           getMsg
           drill.Str(drillPort, @myStr3)
           getMsg
           drill.Str(drillPort, @myStr4)
           getMsg
           drill.Str(drillPort, @myStr5)
           getMsg
           
       "2":
           drill.Str(drillPort, @myStr7)
           getMsg 
           
                      
    '////////////////// Receive response ///////////////// 
    PRI getmsg | i, testVar
     i := 0
         repeat
           if (testVar := drill.rxcheck(drillPort)) == -1
            char[i]~
            quit
           char[i++] := testVar     
          
      pst.str(@char)
    '////////////////////////////////////////////////////  
          
    DAT
    myStr1       byte  "!G 1 500", $0D, 0
    myStr2       byte  "!G 1 0", $0D, 0
    myStr3       byte  "!S 1 200", $0D, 0
    myStr4       byte  "!G 1 300", $0D,0
    myStr5       byte  "!S 1 100", $0D,0
    myStr6       byte  "!G 1 0", $0D,0
    myStr7       byte  "This is my very long string.", $0D, 0 
    

    As it turns out I have three serial ports that are needed in this project:

    1) Xbee to receive commands and report status with remote laptop
    2) Arduino to control CNC moves (the Propeller does its own share of machine control too)
    3) RoboteQ drill motor

    So as it turns out I have saved 2 cogs by using Mr. Allen's 4 port Serial Driver. Thank you very much Duane.

    Sincerely,

    sm
Sign In or Register to comment.