Another full duplex serial variation!!
Carl Jacobs
Posts: 41
FullDuplexSerial has already been studied to death - why would anyone be interested in yet another variation?
Read On...
The object is in the OBEX at obex.parallax.com/objects/398/
This variation uses the left-over memory in the COG to store the Transmit (Tx) and Receieve (Rx) buffers. There are just over 1300 bytes of spare space available, and the Rx and Tx buffers may be freely allocated (in multiples of 4 bytes) to use this available space. There are no power-of-two limitations, if you want 4 bytes for Tx and 1296 bytes for Rx then that is permitted.
The nett result of this is that the object only requires 6 longs of hub memory.
The buffers are fully automatic and accessed through 2 longs in hub memory, Rx1_Buf and Tx1_Buf. Their operation is as follows:
Transmitter:
If Tx1_Buf is in the range 0..255 then that byte is still waiting for space in the Tx buffer. Once space is available the byte is inserted and Tx1_Buf is set to -1, at which point it is free to be used again. This looks much simpler in code:
Receiver:
If Rx1_Buf equals -1 then the Rx buffer is empty. If Rx1_Buf is in the range 0..255 then a byte is available, it can be read out with Rx1_Buf being set it to -1 to indicate that you're done. The cog will automatically grab the next byte from the internal Rx buffer and place it into Rx1_Buf. This looks much simpler in code:
Both Tx1_Buf and Rx1_Buf are typically updated by the driver cog at 300-400 thousand times a second.
From the previous examples it becomes a simple matter to access the serial driver from assembly language as well as via pointers passed to sub objects.
I shall make no claim that this object uses simple assembly language or that it is a minimal variation on FullDuplexSerial! This code was written from the ground up. It is partially commented. It uses a completely different form of multi-tasking to FullDuplexSerial. It has particularly tricky operation around the management of the internal FIFO buffers. The biggest challenge was distributing the management of the FIFO buffers between the bit bashing operations.
This object was written for two main reasons:
1) To minimize the memory footprint required by the serial driver
2) To allow easy access from JDForth - and other assembly language COGs.
The driver has 2 limitations which will not be a problem for most users:
1) Only FullDuplexSerial mode 0 is supported.
2) Only baud rates up to 345600 are supported for a 80MHz clock - which is about the same as FullDuplexSerial.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Carl Jacobs
JDForth - Forth to Spin Compiler http://www.jacobsdesign.com.au/software/jdforth/jdforth.php
Includes: FAT16 support for SD cards. Bit-bash Serial at 2M baud. 32-bit floating point maths.·Fib(28) in 0.86 seconds. ~3x faster than spin, ~40% larger than spin.
Read On...
The object is in the OBEX at obex.parallax.com/objects/398/
This variation uses the left-over memory in the COG to store the Transmit (Tx) and Receieve (Rx) buffers. There are just over 1300 bytes of spare space available, and the Rx and Tx buffers may be freely allocated (in multiples of 4 bytes) to use this available space. There are no power-of-two limitations, if you want 4 bytes for Tx and 1296 bytes for Rx then that is permitted.
The nett result of this is that the object only requires 6 longs of hub memory.
The buffers are fully automatic and accessed through 2 longs in hub memory, Rx1_Buf and Tx1_Buf. Their operation is as follows:
Transmitter:
If Tx1_Buf is in the range 0..255 then that byte is still waiting for space in the Tx buffer. Once space is available the byte is inserted and Tx1_Buf is set to -1, at which point it is free to be used again. This looks much simpler in code:
PUB tx(txbyte) { Wait for space in the Tx buffer } repeat while tx1_buf => 0 { Send a byte } tx1_buf := txbyte
Receiver:
If Rx1_Buf equals -1 then the Rx buffer is empty. If Rx1_Buf is in the range 0..255 then a byte is available, it can be read out with Rx1_Buf being set it to -1 to indicate that you're done. The cog will automatically grab the next byte from the internal Rx buffer and place it into Rx1_Buf. This looks much simpler in code:
PUB rx : rxbyte { Wait for a byte in the Rx buffer } repeat while (rxbyte := rx1_buf) < 0 { Indicate that the byte has been read } rx1_buf := -1
Both Tx1_Buf and Rx1_Buf are typically updated by the driver cog at 300-400 thousand times a second.
From the previous examples it becomes a simple matter to access the serial driver from assembly language as well as via pointers passed to sub objects.
I shall make no claim that this object uses simple assembly language or that it is a minimal variation on FullDuplexSerial! This code was written from the ground up. It is partially commented. It uses a completely different form of multi-tasking to FullDuplexSerial. It has particularly tricky operation around the management of the internal FIFO buffers. The biggest challenge was distributing the management of the FIFO buffers between the bit bashing operations.
This object was written for two main reasons:
1) To minimize the memory footprint required by the serial driver
2) To allow easy access from JDForth - and other assembly language COGs.
The driver has 2 limitations which will not be a problem for most users:
1) Only FullDuplexSerial mode 0 is supported.
2) Only baud rates up to 345600 are supported for a 80MHz clock - which is about the same as FullDuplexSerial.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Carl Jacobs
JDForth - Forth to Spin Compiler http://www.jacobsdesign.com.au/software/jdforth/jdforth.php
Includes: FAT16 support for SD cards. Bit-bash Serial at 2M baud. 32-bit floating point maths.·Fib(28) in 0.86 seconds. ~3x faster than spin, ~40% larger than spin.
Comments
If you look arround I also wrote another full duplex serial driver with external 256 Byte FIFO buffers for transmiting and receiving data.
I was originally looking to make the buffers internal but I decided not to because it would remove the ease of acess to them as programs would need to wait until the driver was ready to take data into or out from the buffers.
One question, is the 345600·baud rate the absolute max under light conditions or stress heavy conditions? When I was·building mine, I found that my program coud take about 680 cyles·if it had to read new transmit·data, send it,·receive new sent data, and store it all at the same·time. Your program looks about the same·length as mine, so I was wondering. Because mine could reach that speed it it was only sending, and maybe receiving·at one packet at a time.
Anyway, more choices is better than less, thanks for helping out the community.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nyamekye,
The code has been carefully written to bypass the concerns you have. It has a form of ping-pong multitasking that is a *lot* more complex than FullDuplexSerial. Essentially the receiver and transmitter are two separate state machines, and a lot of the development effort went into making sure that none of the states stall the bit banging process for too long.
The limiting factor for baud rate is the same as FullDuplexSerial - as the speed increases the jitter on the transmit bits gets increasingly worse until it is no longer functional. The receiver is actally a bit easier to write, as you just need to sample somewhere within 25% to 75% of the bit period to read the bit.
I achieved the internal FIFO buffer processing at the expense of the other modes - my driver only supports mode 0. I wouldn't be too difficult to hard-code the other modes, but most of the time I'm using either a MAX232 or FTDI232 - which I believe will probably be quite common for most Propeller users.
Regards,
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Carl Jacobs
JDForth - Forth to Spin Compiler http://www.jacobsdesign.com.au/software/jdforth/jdforth.php
Includes: FAT16 support for SD cards. Bit-bash Serial at 2M baud. 32-bit floating point maths.·Fib(28) in 0.86 seconds. ~3x faster than spin, ~40% larger than spin.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nyamekye,