PDA

View Full Version : Full Duplex Serial: Simultaneous Read and Write



flo
12-27-2009, 05:13 PM
I'm having problems transmitting and receiving simultaneously on my propeller using the FullDuplexSerial.spin object.

My propeller has a few buttons wired to the I/O pins and is listening for command strings sent from the computer over the USB cable. I want the propeller to alert the computer when a button was pressed.

Right now I have 2 cogs running where Comm is just listening for strings and Comm2 is sending strings out:



Comm.start(31,30,0,9600)
Comm2.start(31,30,0,9600)

cogBtnScan := cognew(scanButtons,BtnScanStack)

repeat

Comm.RxStr(@x)
'....parses string and does stuff with it

PRI scanButtons

dira := 1

repeat
'...read button states; lets say button "a" was pressed, then:
Comm2.str(string("a",13))
waitcnt(cnt+8_000_000)





But this doesn't work. I'm not receiving anything on the computer side. I know my software on the computer works because I can simply echo back what's received and I can read it. It seems like the scanButtons cog is crashing.

Is it because I have 2 cogs trying to access the same I/O pins?

Leon
12-27-2009, 06:13 PM
It isn't a good idea to have two cogs using the same pins for I/O.

Leon

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Amateur radio callsign: G1HSM

Peter Jakacki
12-27-2009, 06:23 PM
It's called FullDuplex for a reason, you can send and receive at the same time plus as Leon said, using two cogs on the same pins will not work as the transmit will never go low while one cog holds it high. Just use the one cog as you are not trying to transmit from both tasks.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
*Peter*

flo
12-28-2009, 03:11 AM
Thanks for the responses Peter and Leon. Using your suggestions I'm running only one cog but it's crashing as soon as the scanButtons cog tries to call Comm.str(string("a",13))




Comm.start(31,30,0,9600)

cogBtnScan := cognew(scanButtons,BtnScanStack)

repeat

Comm.RxStr(@x)
'....parses string and does stuff with it

PRI scanButtons

repeat
'...read button states; lets say button "a" was pressed, then:
Comm.str(string("a",13))
waitcnt(cnt+8_000_000)



Are objects only accessible to the cog that created them?

StefanL38
12-28-2009, 05:09 AM
Flo,

if you ATTACH your COMPLETE code to a posting
like shown in the picture, the community can give much better advise without guessing through the fog what MIGHT be
around your quoted code.

As a quick hint
if two different cog call FullDuplexSerial at overlapping times the buffers were mixed up.
What do you guess comes out if two people talk at the same time?

best regards

Stefan

flo
12-28-2009, 05:54 AM
Thanks Stefan, hopefully this will be much clearer for you guys!


Stefan:38 said...

As a quick hint
if two different cog call FullDuplexSerial at overlapping times the buffers were mixed up.
What do you guess comes out if two people talk at the same time?



I looked through FullDuplexSerial and it has 2 buffers: tx and rx. I don't completely understand whats going on, but it doesn't look like rx_buffer is using tx_buffer and Vice Versa.

Thanks for the help guys.

localroger
12-28-2009, 06:11 AM
flo, FDXS's transmit and receive operations are completely independent and coexistent. It's actually a very robust object, I use it all the time in fairly high performance applications. It's good practice to group all of your FDXS operations in one cog's codestream so that the calls don't overlap, but not totally necessary. It's not clear why you launch a cog to scan buttons; button scanning tends to have a low computational price (you don't need to sample them a million times a second) so it's easy enough to include in the main loop of your application, with cog launching reserved for those functions that need actual high speed response. Without your code posted I can't be sure but I think you may be trying it the other way around, keeping your main loop fast while farming "low priority" functions out to cogs. You can do it that way and make it work but it's much harder.

flo
12-28-2009, 06:32 AM
The reason I put the button scanning in a different loop is because RxStr hangs the app until a string comes in and I was unable to get RxStrTime to work. I don't know how to check if it returned "-1" because it's returning strings... Anyone use it before?

So if I understand localroger, you would do something like this in a single cog:

scanButtons
if buttons have changed -> send serial string out
receive Serial Command in but with a timeout
repeat

I attached the zip archive to my previous post. Do you guys see it?

heater
12-28-2009, 06:49 AM
Presumably RxStrTime is returning a value which is the address in memory where received string is to be found. If there is no string received in the specified time it returns a value of -1 (not the string "-1") which cannot ever be a valid address and is used to indicate the "no string available" situation. So just check if the returned value == -1.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.

StefanL38
12-28-2009, 02:19 PM
Hi Flo,

first of all compliment about your formatting of the spin-file well done

I downloaded your code and have several hints about bugs

maybe it is working with 6 longs but

the absolute minimum for stacksize is 9 longs. Better use 50 longs to have some extra space if parameters or function calls are added
So the crash of the program is caused by the call of COBINED with the too small stack of 6 longs.




Comm.str(string("a",13)) {{-------leaving this line uncommented out crashes the microcontroller}}








VAR
byte x[8]

long BtnScanStack[50] ' long BtnScanStack[6]





the at-operator "@" is missing




cogBtnScan := cognew(scanButtons,@BtnScanStack) 'cogBtnScan := cognew(scanButtons,BtnScanStack)




You don't have to re-invent the wheel again. The RxStr-method is already able to receive a string (=bytesequence of 1-15 bytes terminated by the delimiter character

As ExtFDS is running in its own cog. Just send the string up to 15 characters (plus delimitercharacter) are stored in the receivebuffer of ExtFDS and as long as you
don't send any more characters these characters stay ready to read out in the buffer. Your program can do other things for hours and days. If more than 16 bytes are received
the oldest bytes get overwritten by the newest bytes

From these comments you can see how important it is to post your COMPLETE code

best regards

Stefan

flo
12-30-2009, 12:14 PM
Could someone post some example code of their serial out, if possible. I've been running in circles.





if (Comm.RxStrTime(1,@x) <> -1)
AppendChar(@x, 13)
Comm.str(@x)





Is this the correct way to check for -1? When I do this, it just sends empty strings to my computer.

StefanL38
12-30-2009, 01:31 PM
@heater: RxStrTime does NOT return a result value. So you caN'T check for -1

flo,

you are using RxStrTime to receive SINGLE bytes. RxStrTime is for receiving MULTIPLE bytes.
To give you further advice please do me a favor and post how your COMPLETE data-exchange looks like.

Especially how long is the longest command-string?

How do you send the command-string? I mean this: let's assume your commandstring is "START"
From the PC do you send the string "START"+CR at ONCE

or do you send it as single characters?

"S" then there is a pause of 3 seconds
"T" then there is a pause of 0,1 seconds
"A" then there is a pause of 5 seconds
"R" then there is a pause of 1,2 seconds
"T" then there is a pause of 40 seconds
CR then there is a pause of 9 seconds (CR means the DELIMITER-character decimal value 13)

If you send it at ONCE "START" CR
you simply code a




RxStrTime(1,@MyStr)




If the boolean expression (MyStr[0] == 0) is true nothing was received
otherwise you received the COMPLETE string

YOU DON'T have to put together every char to a string. That's what RxStr and RxStrTime are doing already.

If a string-receiving (=bytesequence) has started to come in,
RxStrTime will receive all these characters at ONCE.
So if MyByte[0] contains something NOT equal to zero it contains already the COMPLETE string, if the string is sended at ONCE

So please post a DETAILED description of your data-exchance and archive and attach your COMPLETE project again

best regards

Stefan