Shop OBEX P1 Docs P2 Docs Learn Events
single pin bi-directional serial IO — Parallax Forums

single pin bi-directional serial IO

Chip CoxChip Cox Posts: 73
edited 2010-02-18 17:37 in Accessories
Ok, I've been reading posts and downloading objects for about 12 hours now and am more confused than when I started.· I'm trying to communicate with a RC-4 relay board from EFX-Tek.· I can send messages to the board and the relays turn on fine.· So I know that I'm on the right pin, and that the format of my strings is correct.· There are 3 pins going to this board, power, ground and signal.· Every example I find shows serial communication over 2 pins ( rx and tx ).· But that would make it to easy.· When I send the commands to get the status of the board, or the firmware version, etc, all I get back is an echo of the command I sent.· Now just for grins, I decided to try this with another serial device I have ( one of Parallax's GPS units ).· I think I have the same problem there, but since it only responds to commands, I can't tell if anything is getting through to it.· Can someone give me an example ( spin only if possible my assembly is rusty ) of bi-directional communication on a single line.· Also, can it be done using the fullduplexserial object??· It's probably something simple and basic I'm doing wrong, but it's just not clicking.
Thanks

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2010-02-15 05:29
    Parallax (and other sensor manufacturers) often use bidirectional serial communications to save a signal line and an I/O pin. The FullDuplexSerial driver isn't really designed for bidirectional serial signalling. You could set it up for open drain/source mode and use a pullup resistor (probably built into the RC-4). You'd want to set the "ignore tx echo on rx" mode as well because anything sent to the RC-4 would appear in the receive buffer as well without this mode set. It's simpler to use the Simple_Serial driver which is intended for this sort of use.
  • Chip CoxChip Cox Posts: 73
    edited 2010-02-15 11:51
    Wow talk about a fast response. That's just about what I need. The only problem I see is that it blocks until it gets a response. If the RC4 or other device is turned off for some unknown reason, the cog would hang waiting for a response to a command that will never be received. I'm not really concerned about power consuption so what would be the impact of another pub that had a tight loop checking ina for the port to be set instead of the waitpeq? That way, I could use a cnt condition on the loop much the same way that rxtime does in fullduplexserial??

    something like
    t:=cnt
    repeat until ( ina(port)==1) or ((cnt-t) / (clkfreq /1000)) > ms ' where ms is the milisecond timeout on the wait
    if ina(port)
    'read it

    Thanks
  • kwinnkwinn Posts: 8,697
    edited 2010-02-15 16:10
    I have used the fcFullDuplexSerial4FC object to send serial data over a single line (shared power and signal) using 2 pins. No mods are required to the serial object. All that is required is a resistor between the Tx and Rx pin and for the signal line to be connected to the Rx pin.
    Keep in mind that anything you transmit from the prop Tx pin will also be received on the Rx pin as well as possibly being echoed by whatever is at the other end.
    This object is based on FullDuplexSerial but allows you to have 4 serial ports so I am sure you could use FDS if you only need one port.
  • Mike GreenMike Green Posts: 23,101
    edited 2010-02-15 17:29
    You could do something like what you suggested (use a loop with a timeout instead of WAITPEQ) or you could start up a separate cog that sends the command to the RC-4 and waits for (and buffers) the response from the RC-4. Your main program would use a timeout for the whole sequence and stop the separate cog if a timeout occurred.
  • Chip CoxChip Cox Posts: 73
    edited 2010-02-15 20:39
    You're slipping. That response took over an hour... <LOL>. I guess it would depend on whether I'm short cogs or not. How much overhead ( time ) is associated with starting and stopping a new cog. Is there any type of queue for processes waiting for a cog? What I'm thinking here is that if I had multiple cogs running already monitoring specific high frequency ports, but needed to communicate back to another sensor, memory stick, network, etc occasionally but the communication could come from any of the other cogs, is there anything in place to help manage the cog resources so that the requests for the low volume services could queue up to use one specific cog? Way outside of the scope of this discussion I know, I was just wondering.
    Thanks again
  • Mike GreenMike Green Posts: 23,101
    edited 2010-02-15 21:03
    It takes about 100us at 80MHz to start up a cog, most of that spent copying the 512 longs of code from hub ram to cog ram, one long every 16 system clocks.

    There's no queuing for cogs. Either one is available in which case it's started or none are available in which case the COGNEW fails and returns -1 for the cog number used.

    In Spin, there's no way to generate a pointer to code, so it's impossible to have queues of routines to be executed. It's possible to cheat if you know the internal structure of the Spin interpretive code and the various control tables used, but I wouldn't recommend doing that except as a demonstration of concept. It's quite possible to have an overlay manager written in assembly.

    The way this sort of thing is done is by starting up a cog that continually looks in a queue for actions to be performed. When it finds one, it does the requested operation, then goes to wait again. Essentially it's a sort of high level interpreter. Things like the floating point package work this way.
  • Chip CoxChip Cox Posts: 73
    edited 2010-02-16 04:14
    Man, you are awesome. Everytime I talk to you I get a little further down the path. My RC4 is talking to me fine now. I added two functions to the simple_serial object.
    PUB rxtime(ms) - like the fullduplexserial version, calls rxcheck until it returns something or the timeout expands ( copied directly from fullduplexserial )
    PUB rxcheck checks ina. if it's 1 then it calls the rx function
    PUB rx is unchanged , it uses waitpeg but since we already know it's set, we don't have an issue with blocking.

    It works great with the RC4. But then I got ambitious and tried it with my parallax GPS in smart mode. It seems to work great when I'm only expecting 1 byte back, but if I'm expecting more than one byte back, the subsequent bytes are not right ( unless we suddenly have more than 60 minutes in an hour ). I've played with type casting to byte since the variables are defined as local variables in a function, the are longs, but either I did that wrong, or that's not the problem. I'll clean up the code some tomorrow and post it unless you have a duuuh you stupid kid do this answer off the top of your head before then.
    Thanks
  • Mike GreenMike Green Posts: 23,101
    edited 2010-02-16 04:28
    I don't do "duuuh you stupid kid". It's rarely true.

    Regarding your multibyte input attempts ... It must be something you've added or changed because Simple_Serial works well for what it does. When you have a chance to post your changes and your test program, we can take a look at what you've done and see if we can find what's not working. Please use the Attachment Manager to post your source file (use the Post Reply button to access that).
  • Chip CoxChip Cox Posts: 73
    edited 2010-02-17 02:33
    Ok,
    · Here ya go.· I've beaten my head against this for to long now.· I'm affraid I can't see the forest for the trees any more.· At one point I was using rxtime·( my code ) but just to eliminate that, I commented out the·"time" part·so I'm·just using the basic rx command from simple_serial.· In order to make simple serial a little more compatiable with fullduplexserial, I added a start function that calls init but leaves out the mode which init doesn't care about.· I also·added a stop which calls·finalize.···It may just be chance, but the first byte ( hour ) that gets returned seems to be correct.· But the minutes ( 164 ) and Seconds ( 254 ) aren't·valid.· At this point I need another set of eyes.

    Thanks
  • Mike GreenMike Green Posts: 23,101
    edited 2010-02-17 05:27
    Here's what I'd write for "rxcheck".
    PUB rxcheck: rxByte
      rxByte := -1                                          ' -1 if no received byte
      if rxOkay
         dira[noparse][[/noparse]sin]~                                         ' make rx pin an input
         if ina[noparse][[/noparse]sin] == inverted & 1                        ' check for start bit    
            rxByte := rx                                    ' receive a byte
    


    I think what's going on is that the calls to debug are taking just enough time for the next "rx" call to miss the leading edge of the start bit and mess up the timing. The rx routine waits for the midpoint of the stop bit before exiting which leaves only 1/2 bit time before the next start bit begins. I would try moving your debug statements to after the last rx call or leaving them out for now. Alternatively, you could drop the Baud for the GPS module to 2400 Baud.
  • Chip CoxChip Cox Posts: 73
    edited 2010-02-17 12:46
    Like I said, you are awesome. Ut wirjs great at 4800 baud. The debug statements were just that debug statements put there when the responses didn't work right when the display was at the bottom. So taking them out entirely isn't a problem. And they were not there when it was originally having problems. But with all the other checking and things I tried, having them there probably masked anything I did that actually helped <lol>.
    I'm guessing that was the problem since at one time, my rxcheck basically looked the same as yours except with the else instead of setting rxByte to -1 as an initial value and falling through. But, with serial IO, the timing is so critical that the delay for the else could cause problems I guess. Is it really that close on the timing? I would think the else would essentially be another if as far as timing goes and you have another if in the command. Wouldn't the timings between the two wash then???
    Now I just need to get the rxtime working right <lol>
  • Mike GreenMike Green Posts: 23,101
    edited 2010-02-17 15:07
    I'd write rxtime as follows:
    PUB rxtime(ms) : rxbyte | t
    
    ' Wait ms milliseconds for a byte to be received
    ' returns -1 if no byte received, $00..$FF if byte
    
      ms *= clkfreq / 1000                                     ' convert to clock ticks
      t := cnt
      repeat while (rxbyte := rxcheck) == -1          ' repeat until something received
        if cnt - t > ms                                             ' check for timeout and return -1 if so
          return -1
    



    At 4800 Baud, 1/2 bit time is around 100us. A couple of calls for debug I/O can take that long.
  • Chip CoxChip Cox Posts: 73
    edited 2010-02-18 17:37
    Didn't work, must be taking to much time. oh well. I guess I can try it with the speed knocked down to 2400.
Sign In or Register to comment.