Shop OBEX P1 Docs P2 Docs Learn Events
Serial Communication — Parallax Forums

Serial Communication

floflo Posts: 38
edited 2010-03-10 10:02 in Propeller 1
Hi guys,

I've been working on this little project to send serial commands from my computer to the prop. I managed to get it to receive strings which I then convert to decimals and then do some processing on those decimals. However, I realized I was being stupid and I should just send decimals to begin with. This is what I'm sending as a string:

1002255

where the first digit (1) is a command, the next 3 (002) is a channel, and last three (255) is a value. This works fine but I'm sending 7 data bytes when I could send just 3!

I'm very new to serial communication and micro controller programming so I need some help figuring some stuff out.

I'm using FTDI drivers on my computer to send serial commands to the prop. Whats the max baud rate I can use? I need to send 1200 channel-value pairs a second. Is this possible?

Comments

  • MagIO2MagIO2 Posts: 2,243
    edited 2010-03-05 05:47
    Simple math, isn''t it:

    1200 rate per second x (3 bytes per channel + 1 byte for start/stop-bit and some spare time) = 4800 bytes per second = 38400kbit per second.

    You can go up to the megabit per second area with the FTDI.
  • floflo Posts: 38
    edited 2010-03-06 23:28
    I'm having trouble detecting the "-1" if rxHexTime function times out.

    Here's the code in question (I've also attached an archive to this):

    
      repeat
         recBytes := Comm.rxHexTime(10)
    
         if(recBytes == -1)
               Comm.str(STR.Combine(Num.ToStr(recBytes,NUM#DEC),string(" (nothing)",10)))
    
         else
               Comm.str(STR.Combine(Num.ToStr(recBytes,NUM#DEC),string(" (something)",10)))
               waitcnt(cnt+80_000_000)
    
    
    



    I keep receiving "255 (something)" on my computer. Is the -1 decimal being converted to 255 in ascii?

    I'm so confused,
    Flo
  • JomsJoms Posts: 279
    edited 2010-03-06 23:38
    Try debuging what 'recBytes' is returning... If I remember right, doesn't -1 = false on the Prop?

    You might want to change the actual Comm object to send something different then a -1... Just an idea?
  • kwinnkwinn Posts: 8,697
    edited 2010-03-07 02:05
    It may be the data you are sending.

    PUB rxHexTime(ms) :Value | place, ptr, x, temp
    {{
    Accepts and returns serial hexadecimal values, such as "A2F4" as a number. <<<<< In this case it is expecting an ascii string "A2F4<cr>"
    with a timeout value. No data returns -1
    String must end in a carriage return (ASCII 13) <<<<<<<<
    x := Serial.rxHexTime(100) ' accept string of digits for value with 100mS timeout
    }}

    In other words I don't think this is doing what you intend. In fact it is doing the opposite - receiving 4 bytes to convert to 2 bytes.
  • kwinnkwinn Posts: 8,697
    edited 2010-03-07 02:10
    You can convert what you send to 2 bytes <<< IF "the number of commands multiplied by the number of channels is less than 256" END IF >>>> <<<< AND "the value is less than 256" END AND >>>>>
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-03-07 20:50
    You need to define recByte as long, otherwise you don't see a difference in a timeout and the data 255 sent. A timeout will return $ffff_ffff, but after asigning it to a byte variable you'll have $ff, which is 255 in decimal. If on the other hand the serial interface receives a 255 ($ff) you don't see a difference.
  • floflo Posts: 38
    edited 2010-03-08 05:29
    Thank you so much MagIO2! That was it! It needed to be a long!

    Also thanks kwinn for pointing that out. So instead of using those wrapper functions (rxDec and rxHex), I'm simply using rxTime to send 4 bytes total.
  • floflo Posts: 38
    edited 2010-03-09 04:42
    Hey everyone, thanks for all the help so far. I hope I'm not wasting everyones time with these questions.

    So I'm sending data packets of 4 bytes: channel, value, $00, and command (The order lets me quickly check if the data packet is done because channel can never be $00).

    If I send 4 data packets (16 bytes) it works great. But if I send 8 data packets (32 bytes) it does crazy stuff:

    I send the hex equivalent of this (channel:value; bolded to emphasize correlation)
    [b]1:255[/b]
    2:255
    3:255
    7:255
    8:255
    [b]9:255[/b]
    [b]10:255[/b]
    [b]14:255[/b]
    
    



    but my prop only sees and echos:
    1:255
    9:255
    10:255
    14:255
    
    



    So I'm thinking the buffer is overflowing but if I increase the buffer size to rx_buffer[noparse][[/noparse]64] in FullDuplexSerial, it seems to crash. So is it really the buffer?

    If instead I send:
    [b]1:255[/b]
    2:255
    3:255
    7:255
    8:255
    
    



    It'll respond:
    1:255
    
    



    I've attached the code if it helps any. I'm totally stumped.

    Thanks again guys
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-03-09 08:47
    1.
    In your main you don't need to initialize all the button-variables. All variables in the VAR section are initialized with 0 by the compiler. So, each additional initialization is a waste of HUB-RAM.
    Please note ... this is not a general advice. Of course there are programs/functions which need to be 'restartable'. In other words the same code is run several times and needs to do it's job from the beginning. There initialization makes sense.

    2.
    Why do you store bytes in a long array (x)? Once you found out that recByte is not -1 (for timeout), you can store recByte in a byte array.

    3.
    Hard to say what's wrong, if you only see one side of the code. Maybe the problem is in the sender. Try·to use·debugging-code. For example you can print the complete x-array after receiving a byte to see what it looks like after processing the byte.

    ·
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-03-09 09:05
    Thinking about it, it looks like your loop is to slow. Comment out the rest starting with "scanButtons" and/or slow down the sender by waiting a while in between the packages.
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-03-09 09:20
    Some explainations for your changes in FullDuplexSerial.

    This version is not designed to have a variable TX/RX buffer-size. It contains a lot of hardcodes which rely on the size being 16. If you change the buffer-size, you have to change some code too. For example the PASM code will not use the additional buffer. The PASM still uses @rx_buffer + 16 for its tx_buffer. That's why it looks like being crashed. SPIN code is writing to tx_buffer, but PASM expects the bytes in @rx_buffer + 16
    ...

    I think there is a version out which has bigger buffers. PhiPi? Cluso? heater? I don't remember ... I'm to old ... ;o)

    But a bigger buffer will not fix the problem if your sender can continuously send. Then it will only delay the problems. So, you have to make your loop faster. The button stuff can be done in an additional COG, so it does not eat up your time in the main-loop.

    PS: saying that .. to output the whole x-array is of course no longer a good advice ;o)

    Post Edited (MagIO2) : 3/9/2010 9:25:14 AM GMT
  • floflo Posts: 38
    edited 2010-03-09 17:58
    I had tried commenting out the "scanButtons" and button code but it produced the same results. I'll try it again along with the pause between sends at lunch.

    What's encouraging is that the bug is consistent; the values that get processed are always the same.
  • floflo Posts: 38
    edited 2010-03-10 03:56
    I commented out the code and slowed down the baud rate to 9600. Now, 8 data packets (32 bytes) works great, and anything more than 8 data packets produces similar problems as before.


    At 80 MHz, the prop should be much faster than the 9600 baud that the bytes are coming in at. Why is this being such a problem? Could it be a memory management issue where the other cog isn't able to read while the bytes are coming in? I must be crazy smhair.gif
  • kwinnkwinn Posts: 8,697
    edited 2010-03-10 04:21
    It is probably due to the speed of spin. It is an interpreter. I usually check the speed of my programs by toggling a pin and looking at it with a scope. A frequency meter would also work.
  • AribaAriba Posts: 2,690
    edited 2010-03-10 05:54
    Try this serial objects, it has a receive buffer of 128 bytes (can also be set to 256).
    Beside that it is compatible to FulDuplexSerial.

    Andy
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-03-10 06:53
    If the stream coming in is constant, then making the buffer bigger won't help. It will only shift the problem to the 50th packed or so.

    I already told you what the problem is - the loop is to slow. In more detail:
    The problem is your output-stream. You receive 4 bytes and start to send back 5-7 bytes. And you convert before sending (STR.combine & Num.ToStr) and I did not have a look into DMXout yet, but this at least eats up some time for calling . As you don't sync incoming stream with outgoing stream, the driver receives data while sending and can't process the data fast enough. So, you end up with buffer overflows. Is the program that sends the data written by yourself? Can you change it in the final version? Then you could use a handshake protocol.
    If you need to send with this data-rate, you have to split up the program and let several COGs do the job.
  • floflo Posts: 38
    edited 2010-03-10 08:37
    MagIO2, could you further explain the input-output problem? Are you referring to the output stream being the DMX object or the "Str.combine & Num.ToStr"?

    I fully commented out the code that reply's to the computer ("str.combine & Num.ToStr") and am left with:

    
    Comm.start(31,30, 0, 9600)
    DMXout.Start(DMXPin)
    
      counter := 0
      prevByte := $ff
      
      repeat
    
         recByte := Comm.rxCheck
    
         if(recByte <> -1)  {{=============received a byte}}
    
                 x[noparse][[/noparse]counter] := recByte
                 counter := counter + 1
                 if(prevByte == $00 AND recByte == $01)
                         counter := 0
                         DMXout.Write(x[noparse][[/noparse]0],x)
    
                 prevByte := recByte 
    
    
    



    The above code isn't able to send more than 32bytes before it crashes. What I'm trying to get at is that the code you helped me write is better than before (16 vs 32 bytes) but it doesn't explain why it's an input/output stream problem. DMX runs at 250k baud while the prop is receiving bytes at 9600 baud and all the code is doing is receiving bytes and sending to the DMX cog.

    Does that mean the slowdown is happening at the memory management level where the HUB's round robin is too inefficient (even if it's running at 40 Mhz)?
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-03-10 10:02
    No, with output stream I meant the Comm.str . The DMX stuff is independent. But now after removing those Comm.str-calls it starts becoming a mistery ;o)

    You really load the changed program to the propeller or is an old version the top-object?
    The baud-rate matches on propeller and PC side?
    Propeller is really running with a crystal?

    Now I'd first check that the data received is really what you send. Just have a 1kB buffer and fill up it in a quick loop doing nothing else. Then send it back (converted to HEX). Verify the result.

    BTW: Are you sure that the channel can't be 0? DMX simply uses channel to put the value into an array. And an array starts with index 0.
    Maybe additional 0s cause the problem.
Sign In or Register to comment.