TXX - 8mbps Serial Transmitter with Extended Features, for use by PASM and Spin code.
jac_goudsmit
Posts: 418
After writing Spin and PASM code for many years, I finally had something that's worthy of uploading to OBEX: a fast serial transmitter that can be used by PASM as well as Spin code.
See: http://obex.parallax.com/object/870. https://github.com/JacGoudsmit/TXX.
I needed an alternative for the FullDuplexSerial driver for my S/PDIF receiver project (https://hackaday.io/project/24911). I needed it to be faster than FullDuplexSerial, and I needed it to be easy to use from PASM: in particular, I wanted it to generate hex dumps without going through Spin code.
Current features are:
Enjoy!
===Jac
UPDATE: I changed the code so that it shifts out the bits via the PHSA timer register, and uses an unrolled loop to improve the maximum speed from 4 to 8 megabits per second. Thanks for the tip, @Kuroneko!
See: http://obex.parallax.com/object/870. https://github.com/JacGoudsmit/TXX.
I needed an alternative for the FullDuplexSerial driver for my S/PDIF receiver project (https://hackaday.io/project/24911). I needed it to be faster than FullDuplexSerial, and I needed it to be easy to use from PASM: in particular, I wanted it to generate hex dumps without going through Spin code.
Current features are:
- Supports bitrates up to 8 megabits per second at 80MHz (minimum 10 cycles per bit).
- Measured maximum throughput when printing a nul-terminated string at 3mbps (highest supported speed of the Parallax Serial Terminal) with an 80MHz clock is about 250,000 characters per second (320 clock cycles per character). Theoretical throughput at 8mbps should be around 500,000 characters per second.
- The slowest command is a request to print the signed decimal representation of $8000_0000 ("-2147483648") which takes 17916 cycles at 3mbps with an 80MHz clock (223.95 microseconds).
- Reads bytes, words or longs from the hub and formats them as human-readable numbers in unsigned decimal, signed decimal, hexadecimal or binary. Printing of arrays of numbers is supported (elements of the array will be separated by a space in the output).
- Reads nul-terminated strings or fixed-length buffers and transmits them straight to the output, either directly or after replacing unprintable characters with a period "." .
- Baud rate and pin number for serial output can be changed without stopping the cog. Lowest baudrate is about 76bps (@80MHz) because of the number of bits used in the command to pass the bit time.
- Can automatically generate a formatted hexdump of up to 4KB of hub memory, with ASCII representation.
- All functionality is controlled by changing a single command longword in hub memory; this makes it easy to control the transmitter cog from Spin as well as PASM.
- Default values of the bit fields in the command longword are such that setting the command to a hub address (bit-extended with zero-bits) will print a nul-terminated string from that address.
- Includes self-benchmarking feature: When processing of a command has completed, the code stores the number of elapsed cycles in the hub..
- Spin demo module implements various spin helper functions and demonstrates the functionality with benchmark testing.
- Txx.spin module compiles to 310 longs at this time.
Enjoy!
===Jac
UPDATE: I changed the code so that it shifts out the bits via the PHSA timer register, and uses an unrolled loop to improve the maximum speed from 4 to 8 megabits per second. Thanks for the tip, @Kuroneko!
Comments
Very cool, so when are you going to post the companion RX program so we have a super hi speed prop to prop comms?
Jim
I'm not currently planning on writing a receiver module, sorry. As I mentioned, I wrote this as a side project and I don't have any use for a receiver at this time.
For high-speed prop-to-prop comms there is a forum thread by Beau Schwabe here. He uses some programming tricks to transfer data at the absolute highest possible speed. My OBEX submission is not intended for prop-to-prop communications, it's intended to generate human-readable text at high speed. Whenever humans are at the incoming end of a serial port, speed is usually not that critical.
===Jac
I recently searched for a high speed serial interface that maintained some of the spin functions...
I have successfully tested this to 3Mbps on a propeller running at 6.25mhz(a prop scope)
Jonathan Dummer(lonesock) made one that has killer speeds using two cogs.
"Fast Full-Duplex Serial"
http://forums.parallax.com/discussion/comment/1212013/#Comment_1212013
Heres v1 of FFDS1 (1 COG)
http://forums.parallax.com/discussion/143514/fast-full-duplex-serial-1-cog-a-k-a-ffds1
A while back I was asked to build something that would decode LTC so that a display could log how many advert slots went out within any one hour period - resetting at the top-of-the-hour (hence the LTC locking). I first thought about making this the one PROP project that I finished to a "useful thing" but didn't see anything about decoding the stream - got pressured into getting something started - saw some AVR code ... it worked but I have always regretted not having done it on the hallowed PROP.
Then they started adding requests - Will it give "Log files"? - Will it supply a screen? ... all of those things would have been easy with 8 Cogs (I think). As it was I had to use two AVRs - one to do the continuous decode (about 100uS processor time free) and one to do the light/switch sequence (glorified traffic lights. So there were "2 Cogs" used anyway
Yes. I added a little hardware to convert the biphase signal into a pulse train to make the polarity of the incoming signal irrelevant. Each time the incoming signal changes, the Propeller gets a pulse, and it basically only has to measure the time between pulses. I use two cogs to decode the biphase signal: one to decode the bits and one to detect the preambles that indicate the start of a subframe. The cogs communicate via a couple of I/O pins, and timing is very tight in some places. My hackaday page (linked in the first post) describes how I tried several different approaches and this one works best.
So basically the two cogs of the biphase decoder store a longword in the hub every time a subframe comes in (up to 96000 times per second), and other cogs can synchronize by waiting for an I/O line and then reading the longword from the hub and processing it. This makes it pretty easy to write all kinds of useful other cogs. For example:
I have to say I'm not familiar with LTC but it looks like it would be easy to decode with a Propeller. Especially because it runs at a much slower pace than S/PDIF (S/PDIF biphase has transitions at over 3MHz when encoding a 48kHz stereo PCM signal, but LTC biphase works at audio frequencies, more than 1000 times slower). I don't think my S/PDIF decoder would be useful for that; it leans kinda heavily on the fact that the interval between bits is only 4 instructions plus one wait-instruction. It configures at timer to count pulses on the input, and waits for one bit period, then checks if the pulse counter went up by one (meaning the encoded bit was 0) or by two (meaning the encoded bit was 1).
===Jac
I must get around to doing something on my own. Finding a suitable solution, on a chip I had been playing with before was too good to not use (and I am lazy ...). It seems that the original task setters will not be with us for much longer so it is all a bit "me wanting to prove something to me". I did get a lash-up running with PureData, firstly by the same AVR "cheat" and secondly by ditching the LTC and using the station NTP for the accurate "hourly resets"