View Full Version : Using FullDuplexSerial....

10-12-2006, 07:29 AM
This below is giving me trouble. Too 'newbie' to comprehend what's wrong.

Hitting F10 give me "Expected a unique parameter name". I've defined the pins, mode and baudrate up in CON.

I'm not sure if it should be in a separate or same cog as the main will run in.

PRI uartD(rxpin, txpin, mode, baudrate) : okay
'' Start this in another cog?

rx := rxpin
tx := txpin
baud := clkfreq / baudrate
okay := cognew(Control1, @stack) > 0

I've seen some code where something is started, then shortly later it is stopped to free a cog. Wouldn't that mean the 'something' wouldn't be usable later?

Can anyone steer me to understanding getting a soft uart going?

Harley Shanko
h.a.s. designn

Mike Green
10-12-2006, 08:04 AM
The message means that one of the parameter names like rxpin or txpin is already defined as a CON or VAR or some such. The compiler is a little "funny" about the scope of names. In most other languages, the names of the parameters are defined local to a subroutine and override any global constant or variable names. Not so in SPIN. The name of a parameter or result or local variable cannot be the same as the name of any named constant (CON), variable (VAR), external object (OBJ), subroutine (PRI/PUB), or data label (DAT). You can reuse the name of a parameter, result, or local variable in another subroutine, but that's all.

In terms of what you're trying to do in your question, what do you want to actually do?

Peter Jakacki
10-12-2006, 08:15 AM
Hi Harley, are you using the FullDuplexSerial object or how are you doing it? If you are use the object then shouldn't you be calling "baud" with the baudrate rather than trying to assign a value to a function?

PUB baud(baudrate)
bit_ticks := clkfreq / baudrate
coginit(cog,@entry, @rx_head)

Also you need to pass the pointer to the communications buffers in cognew(Control1, @stack) but I am not sure what you are doing here with "stack".

When you invoke cognew you are requesting a new cog to run the code "Control1" which is loaded into that cog if successful. The cog you are requesting this from is obviously running the Spin interpreter. In the "okay :=" you are reading a flag but you lose out on finding out which cog was assigned, use the normal "+ 1" method and save that in a variable like "cog" so that you can stop it later on with cogstop.

P.S. I'm a newbie too especially when it comes to Spin so feel free to correct me if I'm wrong. I also see that Mike has answered your immediate question.


10-12-2006, 10:54 PM
Will explain the situation.

This design will be using a soft UART for comm to another board (uses a PIC running on 5v) and to another Prop (need more I/O, and some high speed stuff, than the first Prop). Figured I could use FullDuplexSerial in the main cog, and again in a another cog for the other Prop.

I've been studying the Monitor Demo trying to understand how to init the two soft UARTs and how to i/f with them; that is read from and write to the UARTs. I miss interrupts right now; can't get my head around 'no interrupts'. Can't figure out the 'hooks' that make it work.

Didn't figure getting this part working would be this much of a challenge. Wonder how many other surprises and challenges are in store.

Might there be a good example of handling FullDuplexSerial?

Harley Shanko
h.a.s. designn

Mike Green
10-12-2006, 11:12 PM
If you want to use more than one soft UART, you will need to declare two copies of the FullDuplexSerial object. The Propeller Tool will make sure that there's only one copy of the program itself, but two copies of the data area.

Prop_Tx = 4 ' Data from other Prop
Prop_Rx = 5 ' Data to other Prop
Prop_Baud = 9600
PIC_Tx = 6 ' Data from PIC
PIC_Rx = 7 ' Data to PIC
PIC_Baud = 9600
PropSer : "FullDuplexSerial"
PICSer : "FullDuplexSerial"
PUB main
' Note: In the following, the pin numbers used are based on the direction of
' data transmission from the view of the other processor. The FullDuplexSerial
' routine comments refer to RX and TX from the view of this Propeller.

PropSer.start(Prop_Tx, Prop_Rx, %0000, Prop_Baud)
PICSer.start(PIC_Tx, PIC_Rx, %0000, PIC_Baud)

' At this point the soft UARTs are running, have 16 byte buffers. You can receive
' from PropSer with a call to PropSer.rxcheck or PropSer.rx or PropSer.rxtime(ms)
' where "ms" is a timeout in milliseconds. You can transmit to PropSer with a call
' to PropSer.tx(txbyte). There are transmit formatting routines for binary (bin),
' hexadecimal (hex), decimal (dec), and zero-terminated strings (str). To do the same
' for the PICSer UART, just use PICSer instead of PropSer.

Mike Green
10-12-2006, 11:21 PM
Depending on how independent you want the two co-processors to be, you could do all the processing to handle them in one cog (the main one) like:

if (c := PropSer.rxcheck) <> -1
' process a byte from the other Propeller
if (c := PICSer.rxcheck) <> -1
' process a byte from the PIC

Alternatively, you could have another cog communicate with the PIC and use the main cog to communicate with the other Propeller. In that case, you'd need to communicate back and forth between the two cogs much as if you had a co-processor for each cog (which is, in fact, what you have) just using common memory rather than a communications channel.

10-13-2006, 12:25 AM
Thanks, Mike, for the example for using FullDuplexSerial. Makes it look so simple.

Now, it may take a while for me to study/understand what all is happening. I see now how both soft UARTs can be in the Main (Top object) program. Thought the second one would HAVE to be in a separate cog. Any advantage/disadvantage to having in same or in separate cogs? (Program space, flexibility, etc.?)

Presently the PIC UART is running at 38400 baud, and planned to also run the second Prop i/f at 38400. Hopefully that is no problem.

I'm constantly amazed what all people are having the Propeller do, and pleased to be working with it. Quite an exciting device. http://forums.parallax.com/images/smilies/yeah.gif

Harley Shanko
h.a.s. designn

Mike Green
10-13-2006, 12:49 AM
1) The actual UART function in the FullDuplexSerial object resides in a cog (for each full duplex channel). This does the actual "bit-banging" and does the manipulation of the I/O pins. It communicates with the "interface" routines written in SPIN by means of transmit and receive buffers declared in the FullDuplexSerial object. The interface routines (like .tx, .rx, .rxcheck) can be called from any cog running SPIN although, if you try to receive or transmit from more than one cog at a time, you'll get into trouble since both cogs will try to put data into or get data out of the same buffer at the same time. The fix for this is to use the semaphores (LOCKxxx). It would be unusual to have to do this. Normally, only one cog would make use of any one full duplex channel.

2) No problem running at 38400 Baud. The half duplex routines in SPIN work to 19200 Baud. The FullDuplexSerial routines should work to at least 384 kB.

3) The main reason for choosing to split a function into 2 cogs is simplicity. Interrupt routines and multithreading can get so convoluted sometimes and terrible to try to debug. Often, a very complex interaction can appear very straightforward when single threaded. On the Propeller, it's easy just to provide a separate processor to do the thread. Only where the threads have to interact do you have to do anything special and the semaphore stuff (LOCKxxx) is often all you need (if that).