Shop OBEX P1 Docs P2 Docs Learn Events
Serial Objects for SPIN Programming — Parallax Forums

Serial Objects for SPIN Programming

HumanoidoHumanoido Posts: 5,770
edited 2011-12-31 09:41 in Propeller 1
A List of Serial Objects for SPIN Programming

Tired of endlessly looking for the serial object you need? This list bypasses the limited OBEX-search function and lists the primary serial objects along with their specific links, authors, and information. Includes SPIN objects and one parallel object. Includes special serial objects, some customized, from posts which may not be in the OBEX.

Simple Serial by Chip Gracey - Parallax
http://obex.parallax.com/objects/183/
Bit-bang serial driver for low baud rate (~19.2K) devices. * This driver is designed to be method-compatible with the FullDuplex serial object, allowing it to be used when high speed comms or devoting an independent cog for serial I/O is not necessary. * Bi-directional communication on the same pin is also supported.

Faster Simple Serial with Parity by Marc Gebauer
http://forums.parallax.com/showthread.php?109781-Faster-Simple-Serial-with-Parity
I had·the use for a serial driver that would do 38400 BAUD, 8 bit, even·parity and would'nt use a cog. I didn't need full duplex operation, so I played around with Simple_Serial. Here it is. I call it Fast_Simple_Serial. I have tested send and receive·from 300·to 38400 BAUD with no-parity, even-parity, and odd-parity. Note, the receiver ignores the parity bit. I have added a Demo object that was written for the Propellor Demo Board·which sends and receives to and from the USB FTDI Serial Port and is intended to·connect·with Hyperterminal. Basically when you type on the keyboard in Hyperterminal, the keys are echo'd back.

Full Duplex Serial by Chip Gracey - Parallax
http://obex.parallax.com/objects/54/
Full duplex asynchronous serial object. It will do 115,200 and has 16 byte buffers.

Modified Tim Moore's 4 port driver By Juergen Buchmueller
http://forums.parallax.com/showthread.php?128184-Serial-Objects-for-SPIN-Programming&p=962912#post962912
See post #7 on this thread's page
supports only two ports but with bigger buffers - big enough for an xmodem packet. (64 bytes increased to 256 bytes).

Extended Full Duplex Serial by Martin Hebel
http://obex.parallax.com/objects/31/
Extends out FullDuplexSerial to allow reception of character strings that end in a carriage return for decimal, hexadecimal and alpha-numeric uses. Allows use of timeout values. This version also allows use of defined delimiter characters, and returning whole and fractional portions of a numeric string.

FullDuplexSerial_rr004 by Cluso99
http://obex.parallax.com/objects/570/
FullDuplexSerial object v1.2 with modification to allow easy resizing of buffers 8/16/32/64/128/256 by specifying size in CON section of code only. (Does not do 512)

FullDuplexParallel by Terry E Trapp, KE4PJW
http://obex.parallax.com/objects/644/
This is the FullDuplexParallel object v1.0. It is based on the FullDuplexSerial object v1.1 from the Propeller Tool's Library folder with modified documentation and methods for converting text strings into numeric values in several bases. It interfaces the propeller with the FTDI FT245 Parallel FIFO. The FTDI FT245 allows for high performance I/O to a PC.

FullDuplexSerial_mini.spin by Rkrasowski
Stuff commented out which is not used.
http://forums.parallax.com/showthread.php?129460-Not-enough-COGs
http://forums.parallax.com/attachment.php?attachmentid=78079&d=1297305158

Fast 250Kbps fullduplexserial obex object by Clock Loop
http://forums.parallax.com/showthread.php?120273-Inter-Propeller-communication
http://forums.parallax.com/showthread.php?p=820293

Full Duplex Serial Port Driver by Kwabena W. Agyeman
http://obex.parallax.com/objects/397/
A full duplex serial port driver that runs on one cog. The code has been fully optimized with a super simple spin interface for maximum speed and is also fully commented. Provides full support for: Receiving bytes, Receiving strings, Transmitting bytes, Transmitting strings, Baud Rate from 1 BPS to 250,000 BPS - Full Duplex. This driver has a 256 byte receiving FIFO buffer. This driver has a 256 byte transmitting FIFO buffer.

Full duplex 8.42 MegBaud output to parallax serial Terminal demo by Clock Loop. Thread here Download here You can force error packets if you lift the 10k resistor on the rx pin.

(14.5 Meg Baud) High Speed Prop-to-Prop Serial Communication by Beau
http://forums.parallax.com/showthread.php?99222-Propeller-DEMO-%2814.5-Meg-Baud%29-High-Speed-Prop-to-Prop-Serial-Communication
http://forums.parallax.com/showthread.php?p=694610
I have run this DEMO and tested over 100 Billion data Bits with no Transmission Errors over the distance of 10 feet from one Propeller to another Propeller. “14.5 Meg Baud Upgrade using 4 I/O Pins.... This is still work in progress.· Using only 1 COG for the Transmitter, and 1 COG for the Receiver, 14.5 Mega Baud Communication Packets can be achieved. With slight modification to the "Transmitter" (using 1 COG) and "Receiver" (using 2 COGs ; 180 deg out of phase) 29 Mega Baud communication packets should be achieved through the current implementation of 4 - I/O pins. The current demo sends pseudo random Packets with a length of 32768 bits in approximately 2.25mS (<-14.5Mega Baud) at a repetition rate of 174 Hz effectively providing a constant throughput of 5.7 Mega Baud.· Keep in mind that the 174 Hz is deterministic of the overhead required for the display and Packet confirmation.· Also, the demo provides a "real time" visual representation of the Transmitter's I/O state displayed on the·Receiver screen.

SerialMirror by Mirror
http://obex.parallax.com/objects/189/
A FullDuplexSerial enhancement that allows a single serial connection to be used from within multiple spin files. Primarily aimed as a debugging aid, this file also illustrates how to use the DAT section to make single-instance objects which may be called from multiple spin files. This objects allows relatively easy change of Rx and Tx buffer sizes to the various powers of 2.

MultiCogSerialDebug by Peter Verkaik
http://obex.parallax.com/objects/232/
Derived from SerialMirror V07.05.10 All printing (also from multiple COGs) is done using cprintf. Each cprintf call is a message. The more parameter in cprintf lets you prohibit that the message is interleaved with text from another COG. To keep output clear, end each (compound) message with a \r or \r\n. Receiving should be done by a single COG that can dispatch received messages. See the test program for detailed usage.

Multiple serial port driver by Tim Moore
http://obex.parallax.com/objects/340/
Supports upto 4 serial ports with 1 COG. Also supports hardware flow control on any of the ports.

Tim Moore's pcFullDuplexSerial4FC with larger rx buffer by Duane Degn
http://forums.parallax.com/showthread.php?129714-Tim-Moore-s-pcFullDuplexSerial4FC-with-larger-rx-buffer
pcFullDuplexSerial4FCex.spin uses one cog to control up to four serial ports. After studying the code for a while, I saw how Tim reused the variable space in the hub after the cog is launched. After tracking down which variables were used by both Spin and PASM and which ones were only used within the cog, I realized there was even more space that could be reclaimed. At the cost of three longs, I was able to double the rx buffer from 64 byte per port to 128 bytes per port.

JDCogSerial by Carl Jacobs
http://obex.parallax.com/objects/398/
A full duplex serial that has *ALL* the buffer memory stored in the COG. The VAR footprint is tiny at only 6 longs. The buffer pointers are fully automatic, which allows easy access from assembly as well as sub-objects. The buffer sizes may be set at any number of bytes (in multiples of 4) to the total spare capacity of the COG (a bit over 1300 bytes). Only mode 0 is supported, with baud rates to above 345600 for a 80MHz clock.

Parallax Serial Terminal by Jeff Martin - Parallax
http://obex.parallax.com/objects/457/
This object works with the Parallax Serial Terminal; see Propeller Downloads page or install Propeller Tool v1.2.6 (or newer). It includes handy methods for output/input (Char, CharIn, Str, StrIn, Dec, DecIn, Bin, BinIn, Hex, HexIn) and cursor positioning (Home, Position, NewLine, MoveLeft, MoveRight, etc.) as well as control character constants that match the function of the Parallax Serial Terminal. A demo and a "quick start" template are provided.

jm_irtxserial by Jon McPhalen
http://obex.parallax.com/objects/462/
Allows for serial transmission (up to 2400 baud) over an IR link. Compatible with output methods of simple_serial and fullduplexserial.

Half Duplex Serial Port Driver by Kwabena W. Agyeman
http://obex.parallax.com/objects/538/
A half duplex serial port driver. The code has been fully optimized with a super simple spin interface for maximum speed and is also fully commented. Provides full support for: Even parity bit generation, Even parity bit checking, Odd parity bit generation, Odd parity bit checking, Mark parity bit generation, Mark parity bit checking, Space parity bit generation, Space parity bit checking, Receiving bytes, Receiving strings, Transmitting bytes, Transmitting strings, Baud Rate from 1 BPS to 19,200 BPS - Half Duplex.

Serial Com by Aleks
obex.parallax.com/objects/356/
A communication routine loosely based on I2C with included demo programs to communicate between two Propeller IC's.
~note-> This has only been tested on the Spin Stamp, whereas this is the only propeller I have access to. It requires a CS, SDA, and CLK line to operate. I have had success communicating between the two stamps I used, and displaying the results on an LCD screen. My contact info is in the Readme.txt.

spin FD_Serial_Conf.spin by Andy
http://forums.parallax.com/showthread.php?111836-Custom-Serial&p=797716
http://forums.parallax.com/attachment.php?attachmentid=59874&d=1239071285
Here is a variation of the FullDuplexSerial object, which allows configuration of the datasize 7..9 bits, with an additional Parity bit. Also the Buffer size can easy be changed.

Fast Inter-Propeller Communication by Bobb Fwed
http://forums.parallax.com/showthread.php?117840-Fast-Inter-Propeller-Communication-Object
obex.parallax.com/objects/546/
http://forums.parallax.com/showthread.php?118076-Fast-Inter-Propeller-Communication-Features
I just tested it at 100MHz and got a throughput of 1.37MB/s (including all overhead). Also tested at 80MHz producing 1.10MB/s. It has been tested with over a meter of wiring between two Propellers, but i can't see why it wouldn't work with much longer wires.

[POC] single wire high speed serial link (updated 20101124) by kuroneko
http://forums.parallax.com/showthread.php?110325-POC-single-wire-high-speed-serial-link-%28updated-20101124%29

FastSerial by Peter Jakacki
http://forums.parallax.com/showthread.php?114492-Prop-Baudrates
Half-duplex high speed precision serial driver. Adapted from FullDuplexSerial, This driver dedicates a cog to either receiving or transmitting serial data in a half-duplex fashion. The aim is to have precise bit timing which is important at high-speeds at and above 115K baud. The transmit routines have been to tested to 1Mbit and the receive routines work at 1Mbit

HighSpeed Serial Tx (3Mbps) / Rx (2Mbps) + autobaud for FT232R/Prop GPL by Stephen Moraco
http://forums.parallax.com/showthread.php?102696-HighSpeed-Serial-Tx-%283Mbps%29-Rx-%282Mbps%29-autobaud-for-FT232R-Prop-GPL&p=720623
This is a set of block-send and block-receive routines.· That is they are designed to reduce communication between cogs by only transporting data between them on buffer-full or line-end events.

Other Communication Software & Techniques
Full-speed (12 Mb/s) bit-banging USB Host controller by Scanlime
http://forums.parallax.com/showthread.php?121321-Working-full-speed-%2812-Mb-s%29-bit-banging-USB-Host-controller
So far it supports Control, Bulk IN/OUT, and Interrupt IN transfers. There are a couple simple demos included: Device enumeration and descriptor parsing, a very simple HID demo, and an even simpler mass storage demo. As you'd expect, there is a huge list of caveats for something that pushes the limits of the Propeller and the USB spec to this extent.. It uses four cogs, requires overclocking the Prop to 96 MHz, and even though the line rate is 12 Mb/s the actual usable data throughput is significantly lower. But, this lets you talk to a lot of fun new peripherals that were previously unavailable to the Propeller. So it should be fun :)

XModem receive routine for use with CP/M by Mike Green
http://forums.parallax.com/showthread.php?114023-Sphinx%E2%80%94as-seen-at-UPEW!/page10
It uses a simple checksum even though there's a CRC variable. The return value is the length of the file received.

BS2 Functions Communications by Juffra
http://forums.parallax.com/showthread.php?120273-Inter-Propeller-communication

5Mbit/sec ASCII Streaming from/to Hub RAM by Pjv
http://forums.parallax.com/showthread.php?120125-5Mbit-sec-ASCII-streaming-from-to-Hub-RAM&p=882980

Inter cog communications in Spin by SRLM
http://forums.parallax.com/showthread.php?109427-Inter-Cog-Communication

Inter cog communications in Assembly by Mctrivia
http://forums.parallax.com/showthread.php?109427-Inter-Cog-Communication

Variable access across cogs by StefanL38
http://forums.parallax.com/showthread.php?109427-Inter-Cog-Communication

Faster Inter-Propeller Communication by Synapse
http://forums.parallax.com/showthread.php?128714-Fast-Inter-Propeller-Communication

Useful 1-Wire Routines by Cam Thompson
http://obex.parallax.com/objects/18/
attachment.php?attachmentid=77494&d=1295673516

Special Comments by Mike Green
http://forums.parallax.com/showthread.php?129357-BS2_Functions.spin-Timing-question
The routines in BS2_Functions.spin are written for the general case and are written completely in Spin without any use of assembly language. Spin is interpreted and while much faster than the BS2 equivalent operations, is much slower than assembly language. For example, a serial input/output routine completely written in Spin will operate up to 19.2KBps with an 80MHz Propeller system clock (5MHz crystal * 16 with the PLL multiplier). The equivalent using an assembly language low-level serial I/O routine (FullDuplexSerial) can go well over 230KBps at 80MHz. The same sort of thing is true for clocked serial I/O (SHIFTIN / SHIFTOUT), but more so. The Spin routines are comparable to the asynchronous serial versions, but, using assembly and some other features (like the cog counters), you can easily get 10MHz clock speeds. There have been some special purpose serial I/O routines written (for Prop to Prop communications) that operate at 20MHz with an 80MHz system clock.

Tweaks and Experiments by Lawson
http://forums.parallax.com/showthread.php?114492-Prop-Baudrates
jm_txrx_demo_tweeked.zip
termv19b.zip

Multiple Instances of Full Duplex Serial Interfacing
http://forums.parallax.com/showthread.php?129464-Multiple-instances-of-Full-Duplex-Serial-interacting

For C-Like Language functions Using Spin
cserial.spin As noted by Dave Hein
http://forums.parallax.com/showthread.php?121206-cserial
cserial.spin
cserial_test.spin
It's not written in C. It's written in Spin. It's part of the CLIB object, which provides C-like functions for Spin programs. However, cserial itself does not have any C attributes. This is part of the CLIB object in the OBEX. It is yet another modified version of FDS that does not use VAR variables, but either uses buffers that are defined in DAT or buffers that are provided by the calling program, in which case it uses a handle to reference them. The bufferes can be any power of 2 in size, and the rx and tx buffers can be different sizes. There is an additional feature where an instance can be protected by a lock to make it cog-safe. I included all of the old routines of FullDuplexSerial for compatibility, and I added new versions that require a device handle.· The new versions use the same name, but with a 1 added.· As an example, the new version of str is str1.

· - Multiple serial ports may be started from any object or cog
· - Any serial port is accessable from any object or cog using a device handle
· - Transmit and receiver buffers can be different sizes
· - Buffer sizes are defined by calling parameters
· - Mode bit 4 enables the use of a lock to make the transmit multi-cog safe

The cserial.spin object in CLib can handle multiple cogs.· You call it the same way you would call the FullDuplexSerial methods, except you set bit 4 in the mode flag to make it·cog-safe.· You would call the start·function as follows: fd.start(31, 30, %10000, 115200)
The·start method·should only be called once, normally from cog 0 in the top object.· Check out the test program in CLib.· I have several cogs waiting on the same flag, and then they all print at the same time.
You can download CLib from the OBEX at http://obex.parallax.com/objects/594/·.
http://forums.parallax.com/showthread.php?122169-Ho-to-reuse-FullDuplexSerial-from-multiple-COGs-RESOLVED-use-cserial

Send information to a computer using the FullDuplexSerial object
http://forums.parallax.com/showthread.php?129795-FullDuplexSerial-communication-problems
Thread by Mlanting
In order to do serial communication you need a clock calibrated more accurately than what the internal oscillator is. You need to use an external crystal.
     OBJ
  serial        :               "FullDuplexSerial"
PUB Main
  serial.Start(31, 30, 0, 9600)
  repeat
    serial.str(string("test"))
    waitcnt(clkfreq + cnt)

rxSerialTest-bst-archive-110630-121933.zip by Tracey Allen
Remarkable lowest current drain (1mA) RX communications code

http://forums.parallax.com/showthread.php?128184-Serial-Objects-for-SPIN-Programming&p=1014074&viewfull=1#post1014074
I had need for receiving infrequent but unpredictable packets of data at 115200 baud, with the hitch that the system had to operate at low current. That means clkfreq=5MHz if possible. The attached program rxSerial_ta_10.spin works for this. It is receive-only with an intrinsic current drain of 1 mA. Other programs that I tried, even those that were not rx-only, would not reach 115200 for general purpose buffering to hub ram at clkfreq=5MHz. Most talk has been about high speed, not low current. The problem is really the same as receiving at 1.8 megabaud with an 80MHz clkfreq (I = 16 mA). The trick was to rearrange the stuff that has to happen during the 1.5 bit times between the middle of the last data bit and the end of the stop bit, 65 clock ticks at 5MHz/115200baud. I hope this will be useful to others, and of course constructive comments are welcome.

Modified rxSerialDemo-bst-archive-110630-191917.zip by Tracey Allen
http://forums.parallax.com/showthread.php?128184-Serial-Objects-for-SPIN-Programming&p=1014272&viewfull=1#post1014272
I modified the demo for my rxSerial_ta_10. Now it can run on a single prop, with one cog sending the test data to the receiving cog under test. The transmitter is dedicated to sending a fixed string of characters pulled from cog memory over and over at the selected baud rate and at a selected interval. You can try mismatched baud rates. The rx and tx pins on the Prop are tied together and the debugging data goes out the p31 system port. This tx routine transmits with very close to one stop bit without extra for pulling the next byte from memory, and easily does 115200 on a 5MHz clock. Routines that transmit a string from spin always add a little extra time between bytes, so they are not as challenging to the receiver. I've been testing also with a logic analyzer, to visualize the event positions. You can see the position of the ready-for-start pulse wander depending on how the routine hits the hub access. It has to stay within a margin of the stop bit. rsSerial_ta_10 cut off one hub access by storing the head pointer in the cog, writing but not reading it. (Transmit is easier than receive. Most of the pasm tx routines should reach pretty high baud rates. For example JonnyMac's JM_txserial.)

JM_txserial by JonnyMac
http://www.google.com/url?sa=t&source=web&cd=1&sqi=2&ved=0CBgQFjAA&url=http%3A%2F%2Fforums.parallax.com%2Fattachment.php%3Fattachmentid%3D70747%26d%3D1275281933&rct=j&q=jm_txserial&ei=NAcOToePN7LdiAK1pY2FDg&usg=AFQjCNFmwnnl_8u-otvk1NEjeUsr-TICTA&cad=rja
True mode serial transmit driver -- with buffer
338 x 147 - 9K
«1

Comments

  • BigFootBigFoot Posts: 259
    edited 2010-12-23 08:48
    Which one of these objects would you recommend for 115 Kbaud operation with a 6.25 MHz crystal ?
  • HumanoidoHumanoido Posts: 5,770
    edited 2010-12-25 11:11
    FullDuplexSerial dedicates a cog to receive and send bytes in assembler which makes it possible to send/receive data up to 115200 baud. Simple Serial is written in SPIN which manages up to 19200 baud. There is a high speed version posted in the Forum. Fast Simple Serial is up to 38,400 baud. According to the programs, they're designed for 80MHz. Code can be modified for an overclocked chip depending on the purpose of your application.
  • Clock LoopClock Loop Posts: 2,069
    edited 2010-12-25 12:24
    IF someone would install a "fullduplexserial" type wrapper around this megbaud, it would be at the top of everyones list.

    Serial MegBaud. (8.42 megbaud)
    http://forums.parallax.com/showthread.php?99222-Propeller-DEMO-%2814.5-Meg-Baud%29-High-Speed-Prop-to-Prop-Serial-Communication&highlight=megbaud
  • HumanoidoHumanoido Posts: 5,770
    edited 2010-12-25 12:51
    Clock Loop wrote: »
    IF someone would install a "fullduplexserial" type wrapper around this megbaud, it would be at the top of everyones list.

    Serial MegBaud. (8.42 megbaud)
    http://forums.parallax.com/showthread.php?99222-Propeller-DEMO-%2814.5-Meg-Baud%29-High-Speed-Prop-to-Prop-Serial-Communication&highlight=megbaud
    I'm sure Beau could give some tips on accomplishing this.
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-01-09 23:31
    Quick Reference

    Simple Serial by Chip Gracey - Parallax
    Faster Simple Serial with Parity by Marc Gebauer

    Full Duplex Serial by Chip Gracey - Parallax
    Extended Full Duplex Serial by Martin Hebel
    FullDuplexSerial_rr004 by Cluso99
    FullDuplexParallel by Terry E Trapp, KE4PJW
    Full Duplex Serial Port Driver by Kwabena W. Agyeman
    Full duplex 8.42 MegBaud output to parallax serial Terminal demo by Clock Loop
    (14.5 Meg Baud) High Speed Prop-to-Prop Serial Communication by Beau

    SerialMirror by Mirror
    MultiCogSerialDebug by Peter Verkaik
    Multiple serial port driver by Tim Moore
    JDCogSerial by Carl Jacobs
    Parallax Serial Terminal by Jeff Martin - Parallax
    jm_irtxserial by Jon McPhalen
    Serial Com by Aleks
    Half Duplex Serial Port Driver by Kwabena W. Agyeman
    spin FD_Serial_Conf.spin by Andy
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-01-10 16:38
    I found another one. Modified Tim Moore's 4 port driver so supports only two ports but with bigger buffers - big enough for an xmodem packet. (64 bytes increased to 256 bytes).
    By Juergen Buchmueller
    ''******************************************************************
    ''*  Based on                                                      *
    ''*  Full-Duplex Serial Driver v1.1                                *
    ''*  Author: Chip Gracey                                           *
    ''*  Copyright (c) 2006 Parallax, Inc.                             *
    ''*  See end of file for terms of use.                             *
    ''*                                                                *
    ''*  Juergen Buchmueller 2010-04-21                                *
    ''*   Modified to support 2 serial ports only                      *
    ''*   Increased RX buffer size to 256 bytes each                   *
    ''*  Tim Moore 2008 - 64 byte buffers x 4 ports                    *
    ''*   Modified to support 4 serial ports                           *
    ''*   It should run 1 port faster than FullDuplexSerial or run     *
    ''*   up to 4 ports                                                *
    ''*   Merged 64 byte rx buffer change                              *
    ''*   Merged Debug_PC (Jon Williams)                               *
    ''*   Uses DAT rather than VAR so can be used in multiple objects  *
    ''*   If you want multiple objects using this driver, you must     *
    ''*   copy the driver to a new file and make sure version long is  *
    ''*   unique in each version
    ''*   Added txflush                                                *
    ''*   Optimization perf                                            *
    ''*    1 port up to 750kbps                                        *
    ''*    2 port up to 230kbps                                        *
    ''*    3 port up to 140kbps                                        *
    ''*    4 port up to 100kbps                                        *
    ''*   Tested 4 ports to 115Kbps with 6MHz crystal                  *
    ''*   These are approx theoretical worse case you may get faster   *
    ''*   if port is active but idle                                   *
    ''*   Added RTS/CTS flow control                                   *
    ''*                                                                *
    ''*   There is no perf penalty supporting 4 serial ports when they *
    ''*   are not enabled                                              *
    ''*   There is no perf penalty supporting CTS and RTS              *
    ''*   Enabling CTS on any port costs 4 clocks per port             *
    ''*   Enabling RTS on any port costs 32 clocks per port            *
    ''*   Main Rx+Tx loop is ~256 clocks per port (without CTS/RTS)    *
    ''*   compared with FullDuplexSerial at ~356 clocks                *
    ''*                                                                *
    ''*   There is a cost to read/write a byte in the transmit/        *
    ''*   receive routines. The transmit cost is greater than the      *
    ''*   receive cost so between propellors you can run at max baud   *
    ''*   rate. If receiving from another device, the sending device   *
    ''*   needs a delay between each byte once you are above ~470kbps  *
    ''*   with 1 port enabled                                          *
    ''*                                                                *
    ''*   Size:                                                        *
    ''*     Cog Initialzation code 1 x 8 + 4 x 25                      *
    ''*     Cog Receive code 4 x 30 words                              *
    ''*     Cog Transmit code 4 x 26 words                             *
    ''*     Spin/Cog circular buffer indexes 4 x 4 words               *
    ''*       Used in both spin and Cog and read/written in both       *
    ''*       directions                                               *
    ''*     Spin/Cog per port info 4 x 8 words                         *
    ''*       Passed from Spin to Cog on cog initialization            *
    ''*     Spin per port info 4 x 1 byte                              *
    ''*       Used by Spin                                             *
    ''*     Spin/Cog rx/tx buffer hub address 4 x 4 words              *
    ''*       Passed from Spin to Cog on cog initialization            *
    ''*     Spin/Cog rx/tx index hub address 4 x 4 words               *
    ''*       Passed from Spin to Cog on cog initialization            *
    ''*     Spin per port rx buffer 4 x 64 byte                        *
    ''*       Read by Spin, written by cog                             *
    ''*     Cog per port rx state 4 x 4 words (overlayed on rx buffer) *
    ''*       Used by Cog                                              *
    ''*     Spin per port tx buffer 4 x 16 byte                        *
    ''*       Written by Spin, read by Cog                             *
    ''*     Cog per port tx state 4 x 4 words (overlayed on tx buffer) *
    ''*       Used by Cog                                              *
    ''*     Cog constants 4 words                                      *
    ''*   A significant amount of space (4 x 16 words) is used for     *
    ''*   pre-calculated information: hub addresses, per port          *
    ''*   configuration. This speeds up the tx/rx routines at the cost *
    ''*   of this space.                                               *
    ''*                                                                *
    ''*   Note: There are 8 longs remaining in the cog's memory,       *
    ''*   expect to do some work to add features :).                   *
    ''*                                                                *
    ''*   7/1/08: Fixed bug of not receiving with only 1 port enabled  *
    ''*           Fixed bug of rts not working on ports 0, 2 and 3     *
    ''*  7/22/08: Missed a jmpret call in port 1 and 3 tx              *
    ''*           Fixed a bug in port 3 tx not increasing tx ptr       *
    ''*  7/24/08: Added version variable to change if need multiple    *
    ''*           copies of the driver                                 *
    ''*                                                                *
    ''******************************************************************
    
    CON
      FF                            = 12                    ' form feed
      CR                            = 13                    ' carriage return
    
      NOMODE                        = %000000
      INVERTRX                      = %000001
      INVERTTX                      = %000010
      OCTX                          = %000100
      NOECHO                        = %001000
      INVERTCTS                     = %010000
      INVERTRTS                     = %100000
    
      PINNOTUSED                    = -1                    'tx/tx/cts/rts pin is not used
      
      DEFAULTTHRESHOLD              = 0                     'rts buffer threshold
    
      BAUD1200                      = 1200
      BAUD2400                      = 2400
      BAUD4800                      = 4800
      BAUD9600                      = 9600
      BAUD19200                     = 19200
      BAUD38400                     = 38400
      BAUD57600                     = 57600
      BAUD115200                    = 115200
          
    PUB Init
    ''Always call init before adding ports
      Stop
    
    PUB AddPort(port,rxpin,txpin,ctspin,rtspin,rtsthreshold,mode,baudrate)
    '' Call AddPort to define each port
    '' port 0-3 port index of which serial port
    '' rx/tx/cts/rtspin pin number                          XXX#PINNOTUSED if not used
    '' rtsthreshold - buffer threshold before rts is used   XXX#DEFAULTTHRSHOLD means use default
    '' mode bit 0 = invert rx                               XXX#INVERTRX
    '' mode bit 1 = invert tx                               XXX#INVERTTX
    '' mode bit 2 = open-drain/source tx                    XXX#OCTX
    '' mode bit 3 = ignore tx echo on rx                    XXX#NOECHO
    '' mode bit 4 = invert cts                              XXX#INVERTCTS
    '' mode bit 5 = invert rts                              XXX#INVERTRTS
    '' baudrate
      if cog OR (port > 1)
        abort
      if rxpin <> -1
        long[@rxmask0][port] := |< rxpin
      if txpin <> -1
        long[@txmask0][port] := |< txpin
      if ctspin <> -1
        long[@ctsmask0][port] := |< ctspin
      if rtspin <> -1
        long[@rtsmask0][port] := |< rtspin
        if (rtsthreshold > 0) AND (rtsthreshold < 256)
          long[@rtssize0][port] := rtsthreshold
        else
          long[@rtssize0][port] := 192                      'default rts threshold 3/4 of buffer
      long[@rxtx_mode0][port] := mode
      if mode & INVERTRX
        byte[@rxchar0][port] := $ff
      long[@bit_ticks0][port] := (clkfreq / baudrate)
      long[@bit4_ticks0][port] := long[@bit_ticks0][port] >> 2
    
    PUB Start : okay
    '' Call start to start cog
    '' Start serial driver - starts a cog
    '' returns false if no cog available
    ''
      rxbuff_head_ptr0 := rxbuff_ptr0 := @rx_buffer0
      rxbuff_head_ptr1 := rxbuff_ptr1 := @rx_buffer1
      txbuff_tail_ptr0 := txbuff_ptr0 := @tx_buffer0
      txbuff_tail_ptr1 := txbuff_ptr1 := @tx_buffer1
      rx_head_ptr0 := @rx_head0
      rx_head_ptr1 := @rx_head1
      rx_tail_ptr0 := @rx_tail0
      rx_tail_ptr1 := @rx_tail1
      tx_head_ptr0 := @tx_head0
      tx_head_ptr1 := @tx_head1
      tx_tail_ptr0 := @tx_tail0
      tx_tail_ptr1 := @tx_tail1
      bit_ticks_ptr0 := @new_bit_ticks0
      bit_ticks_ptr1 := @new_bit_ticks1
      new_bit_ticks0 := long[@bit_ticks0][0]
      new_bit_ticks1 := long[@bit_ticks0][1]
      okay := cog := cognew(@entry, @rx_head0) + 1
    
    PUB Stop
    '' Stop serial driver - frees a cog
      if cog
        cogstop(cog~ - 1)
      longfill(@startfill, 0, (@endfill-@startfill)/4)      'initialize head/tails,port info and hub buffer pointers
    
    PUB getCogID : result
      return cog -1
    '
    PUB rxflush(port)
    ' Flush receive buffer
      repeat while rxcheck(port) => 0
    
    PUB rxavail(port) : truefalse
    
    '' Check if byte(s) available
    '' returns true (-1) if bytes available
      if long[@rx_tail0][port] <> long[@rx_head0][port]
        truefalse:=-1
      else
        truefalse:=0
    
    
    PUB rxcheck(port) : rxbyte
    '' Check if byte received (never waits)
    '' returns -1 if no byte received, $00..$FF if byte
    '  if port > 3
    '    abort
      rxbyte--
      if long[@rx_tail0][port] <> long[@rx_head0][port]
        rxbyte := byte[@rxchar0][port] ^ byte[@rx_buffer0][(port<<6)+long[@rx_tail0][port]]
        long[@rx_tail0][port] := (long[@rx_tail0][port] + 1) & $ff
    {
    PUB rxtime(port,ms) : rxbyte | t
    '' Wait ms milliseconds for a byte to be received
    '' returns -1 if no byte received, $00..$FF if byte
      t := cnt
      repeat until (rxbyte := rxcheck(port)) => 0 or (cnt - t) / (clkfreq / 1000) > ms
    }
    PUB rx(port) : rxbyte
    '' Receive byte (may wait for byte)
    '' returns $00..$FF
      repeat while (rxbyte := rxcheck(port)) < 0
    
    'PUB Lookahead(port) : rxbyte | tailvalue' returns a long with the next 4 bytes but doesn't read them (the rx_byte is actually a long)
    '   tailvalue := long[@rx_tail][port] ' tail value 0 to 63
    '   repeat 4 ' collect 4 bytes and turn them into a long
    ''     rxbyte := (rxbyte <<8) ' shift byte over by 1
    '     rxbyte := (rxbyte <<8) + byte[@rxchar0][port] ^ byte[@rx_buffer0][(port<<6)+tailvalue] ' get value and add to current value
    '     tailvalue := (tailvalue +1) & $FF ' add one and cycle if >255
    
    PUB Lookbehind(port) : rxbyte | headvalue ' takes the head and looks at the last 4 characters to come into the port
       headvalue := (long[@rx_head0][port] -4) & $FF' head value minus 4 and 0 to 255
       repeat 4 ' collect 4 bytes
         rxbyte := (rxbyte <<8) + byte[@rxchar0][port] ^ byte[@rx_buffer0][(port<<6)+headvalue]
         headvalue := (headvalue +1) & $FF ' add one and cycle if >255
    
    PUB tx(port,txbyte)
    '' Send byte (may wait for room in buffer)
    '  if port > 1
    '    abort
      repeat until (long[@tx_tail0][port] <> (long[@tx_head0][port] + 1) & $F)
      byte[@tx_buffer0][(port<<4)+long[@tx_head0][port]] := txbyte
      long[@tx_head0][port] := (long[@tx_head0][port] + 1) & $F
    
      if long[@rxtx_mode0][port] & NOECHO
        rx(port)
    {
    PUB txflush(port)
      repeat until (long[@tx_tail][port] == long[@tx_head][port])
    }
    PUB str(port,stringptr)
    '' Send string                    
      repeat strsize(stringptr)
        tx(port,byte[stringptr++])
    
    PUB strln(port,strAddr)
    '' Print a zero-terminated string
      str(port,strAddr)
      tx(port,CR)  
    
    PUB dec(port,value)
    '' Print a decimal number
      decl(port,value,10,0)
    
    PUB decf(port,value, width)
    '' Prints signed decimal value in space-padded, fixed-width field
      decl(port,value,width,1)
    
    PUB decx(port,value, digits)
    '' Prints zero-padded, signed-decimal string
    '' -- if value is negative, field width is digits+1
      decl(port,value,digits,2)
    
    PUB decl(port,value,digits,flag) | i
      digits := 1 #> digits <# 10
      if value < 0
        -value
        tx(port,"-")
    
      i := 1_000_000_000
      if flag & 3
        if digits < 10                                      ' less than 10 digits?
          repeat (10 - digits)                              '   yes, adjust divisor
            i /= 10
    
      repeat digits
        if value => i
          tx(port,value / i + "0")
          value //= i
          result~~
        elseif (i == 1) OR result OR (flag & 2)
          tx(port,"0")
        elseif flag & 1
          tx(port," ")
        i /= 10
    
    PUB hex(port,value, digits)
    '' Print a hexadecimal number
      value <<= (8 - digits) << 2
      repeat digits
        tx(port,lookupz((value <-= 4) & $F : "0".."9", "A".."F"))
    {
    PUB ihex(port,value, digits)
    '' Print an indicated hexadecimal number
      tx(port,"$")
      hex(port,value,digits)
    
    PUB bin(port,value, digits)
    '' Print a binary number
      value <<= 32 - digits
      repeat digits
        tx(port,(value <-= 1) & 1 + "0")
    
    PUB padchar(port,count, txbyte)
      repeat count
         tx(port,txbyte)
    
    PUB ibin(port,value, digits)
    '' Print an indicated binary number
      tx(port,"%")
      bin(port,value,digits)
    }
    PUB putc(port,txbyte)
    '' Send a byte to the terminal
      tx(port,txbyte)
    {
    PUB newline(port)
      putc(port,CR)
    
    PUB cls(port)
      putc(port,FF)
    }
    PUB getc(port)
    '' Get a character
    '' -- will not block if nothing in uart buffer
       return rxcheck(port)
    '  return rx
    
    PUB get_entry
      return @entry
    
    PUB get_tx_head
      return tx_head_ptr0
    
    PUB get_tx_tail
      return tx_tail_ptr0
    
    PUB get_tx_buffer
      return txbuff_ptr0
    
    PUB get_rx_head
      return rx_head_ptr0
    
    PUB get_rx_tail
      return rx_tail_ptr0
    
    PUB get_rx_buffer
      return rxbuff_ptr0
    
    PUB get_bit_ticks0
      return bit_ticks_ptr0
    
    PUB get_tx_head1
      return tx_head_ptr1
    
    PUB get_tx_tail1
      return tx_tail_ptr1
    
    PUB get_tx_buffer1
      return txbuff_ptr1
    
    PUB get_rx_head1
      return rx_head_ptr1
    
    PUB get_rx_tail1
      return rx_tail_ptr1
    
    PUB get_rx_buffer1
      return rxbuff_ptr1
    
    PUB get_bit_ticks1
      return bit_ticks_ptr1
    
    DAT
    '***********************************
    '* Assembly language serial driver *
    '***********************************
    '
                            org     0
    '
    ' Entry
    '                   
    'To maximize the speed of rx and tx processing, all the mode checks are no longer inline
    'The initialization code checks the modes and modifies the rx/tx code for that mode
    'e.g. the if condition for rx checking for a start bit will be inverted if mode INVERTRX
    'is it, similar for other mode flags
    'The code is also patched depending on whether a cts or rts pin are supplied. The normal
    ' routines support cts/rts processing. If the cts/rts mask is 0, then the code is patched
    'to remove the addtional code. This means I/O modes and CTS/RTS handling adds no extra code
    'in the rx/tx routines which not required.
    'Similar with the co-routine variables. If a rx or tx pin is not configured the co-routine
    'variable for the routine that handles that pin is modified so the routine is never called
    'We start with port 3 and work down to ports because we will be updating the co-routine pointers
    'and the order matters. e.g. we can update txcode3 and then update rxcode3 based on txcode3
    'port 3
    entry
    rxcode0 if_never        mov     rxcode0,#receive0     'statically set these variables
    txcode0 if_never        mov     txcode0,#transmit0
    rxcode1 if_never        mov     rxcode1,#receive1
    txcode1 if_never        mov     txcode1,#transmit1
    
    'port 1
                            test    rxtx_mode1,#OCTX wz   'init tx pin according to mode
                            test    rxtx_mode1,#INVERTTX wc
            if_z_ne_c       or      outa,txmask1
            if_z            or      dira,txmask1
            if_z_eq_c       or      txout1,domuxnc        'patch muxc to muxnc
            if_nz           movd    txout1,#dira          'change destination from outa to dira
                            test    rxtx_mode1,#INVERTRX wz 'wait for start bit on rx pin
            if_nz           xor     start1,doifc2ifnc     'if_c jmp to if_nc
                            or      ctsmask1,#0     wz
            if_nz           test    rxtx_mode1,#INVERTCTS wc
            if_nz_and_nc    or      ctsi1,doif_z_or_nc    'if_nc jmp
            if_nz_and_c     or      ctsi1,doif_z_or_c     'if_c jmp
            if_z            mov     txcts1,transmit1      'copy the jmpret over the cts test
            if_z            movs    ctsi1,#txcts1         'patch the jmps to transmit to txcts0  
            if_z            add     txcode1,#1            'change co-routine entry to skip first jmpret
                                                          'patch rx routine depending on whether rts is used
                                                          'and if it is inverted
                            or      rtsmask1,#0     wz
            if_nz           test    rxtx_mode1,#INVERTRTS wc
            if_nz_and_nc    or      rts1,domuxnc          'patch muxc to muxnc
            if_z            mov     norts1,rec1i          'patch to a jmp #receive1
            if_z            movs    start1,#receive1      'skip all rts processing                  
                            or      txmask1,#0      wz
    '        if_z            mov     txcode1,rxcode2       'use variable in case it has been changed
                            or      rxmask1,#0      wz
    '        if_z            mov     rxcode1,txcode1       'use variable in case it has been changed
    'port 0
                            test    rxtx_mode0,#OCTX wz    'init tx pin according to mode
                            test    rxtx_mode0,#INVERTTX wc
            if_z_ne_c       or      outa,txmask0
            if_z            or      dira,txmask0
                                                          'patch tx routine depending on invert and oc
                                                          'if invert change muxc to muxnc
                                                          'if oc change out1 to dira
            if_z_eq_c       or      txout0,domuxnc        'patch muxc to muxnc
            if_nz           movd    txout0,#dira          'change destination from outa to dira
                                                          'patch rx wait for start bit depending on invert
                            test    rxtx_mode0,#INVERTRX wz 'wait for start bit on rx pin
            if_nz           xor     start0,doifc2ifnc     'if_c jmp to if_nc
                                                          'patch tx routine depending on whether cts is used
                                                          'and if it is inverted
                            or      ctsmask0,#0     wz    'cts pin? z not set if in use
            if_nz           test    rxtx_mode0,#INVERTCTS wc 'c set if inverted
            if_nz_and_nc    or      ctsi0,doif_z_or_nc    'if_nc jmp
            if_nz_and_c     or      ctsi0,doif_z_or_c     'if_c jmp
            if_z            mov     txcts0,transmit0      'copy the jmpret over the cts test
            if_z            movs    ctsi0,#txcts0         'patch the jmps to transmit to txcts0  
            if_z            add     txcode0,#1            'change co-routine entry to skip first jmpret
                                                          'patch rx routine depending on whether rts is used
                                                          'and if it is inverted
                            or      rtsmask0,#0     wz    'rts pin, z not set if in use
            if_nz           test    rxtx_mode0,#INVERTRTS wc
            if_nz_and_nc    or      rts0,domuxnc          'patch muxc to muxnc
            if_z            mov     norts0,rec0i          'patch to a jmp #receive
            if_z            movs    start0,#receive0      'skip all rts processing if not used
                                                          'patch all of tx routine out if not used                  
                            or      txmask0,#0      wz
    '        if_z            mov     txcode,rxcode1        'use variable in case it has been changed
                                                          'patch all of rx routine out if not used                  
                            or      rxmask0,#0      wz
    '        if_z            mov     rxcode,txcode         'use variable in case it has been changed
    '
    ' Receive
    '
    receive0                jmpret  rxcode0,txcode0       'run a chunk of transmit code, then return
                                                          'patched to a jmp if pin not used                        
                            rdlong  bit_ticks0, bit_ticks_ptr0
                            mov     bit4_ticks0, bit_ticks0
                            shr     bit4_ticks0, #2
                            test    rxmask0,ina      wc
    start0  if_c            jmp     #norts0               'go check rts if no start bit
                                                          'will be patched to jmp #receive if no rts  
    
                            mov     rxbits0,#9            'ready to receive byte
                            mov     rxcnt0,bit4_ticks0    '1/4 bits
                            add     rxcnt0,cnt
    
    :bit0                   add     rxcnt0,bit_ticks0     '1 bit period
                            
    :wait0                  jmpret  rxcode0,txcode0       'run a chuck of transmit code, then return
    
                            mov     t1,rxcnt0             'check if bit receive period done
                            sub     t1,cnt
                            cmps    t1,#0           wc
            if_nc           jmp     #:wait0
    
                            test    rxmask0,ina     wc    'receive bit on rx pin
                            rcr     rxdata0,#1
                            djnz    rxbits0,#:bit0        'get remaining bits
    
                            jmpret  rxcode0,txcode0       'run a chunk of transmit code, then return
                            
                            shr     rxdata0,#32-9         'justify and trim received byte
    
                            wrbyte  rxdata0,rxbuff_head_ptr0'{7-22}
                            add     rx_head0,#1
                            and     rx_head0,#$FF          '256 byte buffer
                            wrlong  rx_head0,rx_head_ptr0  '{8}
                            mov     rxbuff_head_ptr0,rxbuff_ptr0 'calculate next byte head_ptr
                            add     rxbuff_head_ptr0,rx_head0
    norts0
                            rdlong  rx_tail0,rx_tail_ptr0 '{7-22 or 8} will be patched to jmp #r3 if no rts
                            mov     t1,rx_head0
                            sub     t1,rx_tail0           'calculate number bytes in buffer
                            and     t1,#$FF               'fix wrap
                            cmps    t1,rtssize0     wc    'is it more than the threshold
    rts0                    muxc    outa,rtsmask0         'set rts correctly
    
    rec0i                   jmp     #receive0             'byte done, receive next byte
    '
    ' Receive1
    '
    receive1                jmpret  rxcode1,txcode1       'run a chunk of transmit code, then return
                            
                            rdlong  bit_ticks1, bit_ticks_ptr1
                            mov     bit4_ticks1, bit_ticks1
                            shr     bit4_ticks1, #2
                            test    rxmask1,ina     wc
    start1  if_c            jmp     #norts1               'go check rts if no start bit
    
                            mov     rxbits1,#9            'ready to receive byte
                            mov     rxcnt1,bit4_ticks1    '1/4 bits
                            add     rxcnt1,cnt                          
    
    :bit1                   add     rxcnt1,bit_ticks1     '1 bit period
                            
    :wait1                  jmpret  rxcode1,txcode1       'run a chuck of transmit code, then return
    
                            mov     t1,rxcnt1             'check if bit receive period done
                            sub     t1,cnt
                            cmps    t1,#0           wc
            if_nc           jmp     #:wait1
    
                            test    rxmask1,ina     wc    'receive bit on rx pin
                            rcr     rxdata1,#1
                            djnz    rxbits1,#:bit1
    
                            jmpret  rxcode1,txcode1       'run a chunk of transmit code, then return
                            shr     rxdata1,#32-9         'justify and trim received byte
    
                            wrbyte  rxdata1,rxbuff_head_ptr1 '7-22
                            add     rx_head1,#1
                            and     rx_head1,#$FF         '256 byte buffers
                            wrlong  rx_head1,rx_head_ptr1
                            mov     rxbuff_head_ptr1,rxbuff_ptr1 'calculate next byte head_ptr
                            add     rxbuff_head_ptr1,rx_head1
    norts1
                            rdlong  rx_tail1,rx_tail_ptr1    '7-22 or 8 will be patched to jmp #r3 if no rts
                            mov     t1,rx_head1
                            sub     t1,rx_tail1
                            and     t1,#$FF
                            cmps    t1,rtssize1     wc
    rts1                    muxc    outa,rtsmask1
    
    rec1i                   jmp     #receive1             'byte done, receive next byte
    '
    '
    ' Transmit
    '
    transmit0               jmpret  txcode0,rxcode1       'run a chunk of receive code, then return
                                                          'patched to a jmp if pin not used                        
                            
    txcts0                  test    ctsmask0,ina    wc    'if flow-controlled dont send
                            rdlong  t1,tx_head_ptr0       '{7-22} - head[0]
                            cmp     t1,tx_tail0     wz    'tail[0]
    ctsi0   if_z            jmp     #transmit0            'may be patched to if_z_or_c or if_z_or_nc
    
                            rdbyte  txdata0,txbuff_tail_ptr0'{8}
                            add     tx_tail0,#1
                            and     tx_tail0,#$0F    wz
                            wrlong  tx_tail0,tx_tail_ptr0  '{8}
            if_z            mov     txbuff_tail_ptr0,txbuff_ptr0 'reset tail_ptr if we wrapped
            if_nz           add     txbuff_tail_ptr0,#1    'otherwise add 1
                            
                            jmpret  txcode0,rxcode1
    
                            shl     txdata0,#2
                            or      txdata0,txbitor      'ready byte to transmit
                            mov     txbits0,#11
                            mov     txcnt0,cnt
    
    txbit0                  shr     txdata0,#1       wc
    txout0                  muxc    outa,txmask0          'maybe patched to muxnc dira,txmask
                            add     txcnt0,bit_ticks0     'ready next cnt
    
    :wait                   jmpret  txcode0,rxcode1       'run a chunk of receive code, then return
    
                            mov     t1,txcnt0             'check if bit transmit period done
                            sub     t1,cnt
                            cmps    t1,#0           wc
            if_nc           jmp     #:wait
    
                            djnz    txbits0,#txbit0       'another bit to transmit?
    txjmp0                  jmp     ctsi0                 'byte done, transmit next byte
    '
    ' Transmit1
    '
    transmit1               jmpret  txcode1,rxcode0       'run a chunk of receive code, then return
                            
    txcts1                  test    ctsmask1,ina    wc    'if flow-controlled dont send
                            rdlong  t1,tx_head_ptr1
                            cmp     t1,tx_tail1     wz
    ctsi1   if_z            jmp     #transmit1            'may be patched to if_z_or_c or if_z_or_nc
    
                            rdbyte  txdata1,txbuff_tail_ptr1
                            add     tx_tail1,#1
                            and     tx_tail1,#$0F   wz
                            wrlong  tx_tail1,tx_tail_ptr1
            if_z            mov     txbuff_tail_ptr1,txbuff_ptr1 'reset tail_ptr if we wrapped
            if_nz           add     txbuff_tail_ptr1,#1   'otherwise add 1
    
                            jmpret  txcode1,rxcode0       'run a chunk of receive code, then return
                            
                            shl     txdata1,#2
                            or      txdata1,txbitor       'ready byte to transmit
                            mov     txbits1,#11
                            mov     txcnt1,cnt
    
    txbit1                  shr     txdata1,#1      wc
    txout1                  muxc    outa,txmask1          'maybe patched to muxnc dira,txmask
                            add     txcnt1,bit_ticks1     'ready next cnt
    
    :wait1                  jmpret  txcode1,rxcode0       'run a chunk of receive code, then return
    
                            mov     t1,txcnt1             'check if bit transmit period done
                            sub     t1,cnt
                            cmps    t1,#0           wc
            if_nc           jmp     #:wait1
    
                            djnz    txbits1,#txbit1       'another bit to transmit?
    txjmp1                  jmp     ctsi1                 'byte done, transmit next byte
    '
    'These are used by SPIN and assembler, using DAT rather than VAR
    'so all COGs share this instance of the object
    '
    startfill
      cog                   long      0                   'cog flag/id
    
      'Dont Change the order of any of these initialized variables without modifying
      'the code to match - both spin and assembler
      'Dont make any of the initialized variables, uninitialized, only the initialized
      'variables are duplicated in hub memory
      rx_head0              long      0                   '16 longs for circular buffer head/tails
      rx_head1              long      0                           
      rx_tail0              long      0
      rx_tail1              long      0 
      tx_head0              long      0
      tx_head1              long      0
      tx_tail0              long      0
      tx_tail1              long      0
    
      'This set of variables were initialized to the correct values in Spin and loaded into this cog
      'when it started
      rxmask0               long      0                   '33 longs for per port info
      rxmask1               long      0
      txmask0               long      0
      txmask1               long      0
      ctsmask0              long      0
      ctsmask1              long      0
      rtsmask0              long      0
      rtsmask1              long      0
      rxtx_mode0            long      0
      rxtx_mode1            long      0
      bit4_ticks0           long      0
      bit4_ticks1           long      0
      bit_ticks0            long      0
      bit_ticks1            long      0
      rtssize0              long      0
      rtssize1              long      0
      rxchar0               byte      0
      rxchar1               byte      0
    
      'This set of variables were initialized to the correct values in Spin and loaded into this cog
      'when it started. They contain the hub memory address of the rx/txbuffers
      rxbuff_ptr0           long      0                   '32 longs for per port buffer hub ptr
      rxbuff_ptr1           long      0
      txbuff_ptr0           long      0
      txbuff_ptr1           long      0
      rxbuff_head_ptr0      long      0
      rxbuff_head_ptr1      long      0
      txbuff_tail_ptr0      long      0
      txbuff_tail_ptr1      long      0
    
      rx_head_ptr0          long      0
      rx_head_ptr1          long      0
      rx_tail_ptr0          long      0
      rx_tail_ptr1          long      0
      tx_head_ptr0          long      0
      tx_head_ptr1          long      0
      tx_tail_ptr0          long      0
      tx_tail_ptr1          long      0
    endfill       'used to calculate size of variables for longfill with 0
    '
    'note we are overlaying cog variables on top of these hub arrays, we need the space
    '
      rx_buffer0                                          'overlay rx variables over rxbuffer
      rxdata0               long      0                   'transmit and receive buffers
      rxbits0               long      0
      rxcnt0                long      0
      rxdata1               long      0
      rxbits1               long      0
      rxcnt1                long      0
      t1                    long      0
                            long      0
                            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
    
      rx_buffer1            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
                            long      0,0,0,0,0,0,0,0
    
      tx_buffer0                                          'overlay tx variables over txbuffer
      txdata0               long      0
      txbits0               long      0
      txcnt0                long      0
                            long      0
    
      tx_buffer1                                          'overlay tx variables over txbuffer
      txdata1               long      0
      txbits1               long      0
      txcnt1                long      0
                            long      0
    
      bit_ticks_ptr0        long      0-0
      bit_ticks_ptr1        long      0-0
    'values to patch the code
      doifc2ifnc            long      $003c0000           'patch condition if_c to if_nc using xor
      doif_z_or_c           long      $00380000           'patch condition if_z to if_z_or_c using or
      doif_z_or_nc          long      $002c0000           'patch condition if_z to if_z_or_nc using or
      domuxnc               long      $04000000           'patch muxc to muxnc using or
    '
      txbitor               long      $0401               'bits to or for transmitting
    
    'If you want multiple copys of this driver in a project, then copy the file to multiple files and change
    'version in each to be unique
      version               long      1
    '
            FIT             $1F0
    new_bit_ticks0          long      0-0
    new_bit_ticks1          long      0-0
    ''      MIT LICENSE
    {{
    '  Permission is hereby granted, free of charge, to any person obtaining
    '  a copy of this software and associated documentation files
    '  (the "Software"), to deal in the Software without restriction,
    '  including without limitation the rights to use, copy, modify, merge,
    '  publish, distribute, sublicense, and/or sell copies of the Software,
    '  and to permit persons to whom the Software is furnished to do so,
    '  subject to the following conditions:
    '
    '  The above copyright notice and this permission notice shall be included
    '  in all copies or substantial portions of the Software.
    '
    '  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    '  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    '  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    '  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    '  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    '  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    '  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    }}
    
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-01-15 13:36
    Dr_Acula wrote: »
    I found another one. Modified Tim Moore's 4 port driver so supports only two ports but with bigger buffers - big enough for an xmodem packet. (64 bytes increased to 256 bytes).
    By Juergen Buchmueller
    Dr_Acula, great find! Added to the list.
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-01-15 13:40
    Added
    Fast Inter-Propeller Communication by Bobb Fwed
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-01-15 13:52
    Added:
    XModem receive routine for use with CP/M by Mike Green
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-01-21 22:01
    Added section for other communication software and several "new" serial communication objects.
  • idbruceidbruce Posts: 6,197
    edited 2011-01-22 06:42
    Humanoido

    This is a nice post. It is good to be able to look at the available options from a glance.

    Bruce
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2011-01-22 13:03
    This was an interesting thread and useful reference about experience with multiple serial ports on the Prop:
    Another reason the prop is great!
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2011-01-22 13:20
    I had started on an Excel spreadsheet to compare the PUBs available in different serial port objects. Work in progress. Anyone is welcome to add to it and share. It can help in choosing an object, , or to find methods to borrow from one object to supplement methods missing in another, or to compare names of equivalent methods between objects.

    As it stands, it only covers fullDuplexSerial v1.2, pcFullDuplexSerial4FC, and ParallaxSerialTerminal.
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-01-22 17:10
    This was an interesting thread and useful reference about experience with multiple serial ports on the Prop
    Thanks Tracy, that is a good thread. Do you know if any code was posted related to it?
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2011-01-22 17:38
    AFAIK Baggers and Coley did not publish the code for 10 serial ports that instigated the "prop is great" thread. My own workhorse is Tim Moore's object for 4 ports (thanks!), and Tim contributed insights to the"great" thread too.
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-01-22 18:26
    AFAIK Baggers and Coley did not publish the code for 10 serial ports that instigated the "prop is great" thread. My own workhorse is Tim Moore's object for 4 ports (thanks!), and Tim contributed insights to that thread too.
    Tracy, thanks. It's good to get this positive feedback about Tim Moore's multi port object.

    Multiple serial port driver by Tim Moore
    http://obex.parallax.com/objects/340/
    Supports up to 4 serial ports with 1 COG. Also supports hardware flow control on any of the ports.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2011-01-22 19:41
    The 4 port driver works very well. It declares no VARs whatsoever, and all the buffers, pointers etc are in the DAT area. The uarts need to be initialized once, and the serial port object can be declared in several additional objects without generating additional code, and all of them will then know where to find the DATa.

    One tiny issue has to do with the spin code for outputting decimal data and has to do with the maximum negative value (NEGX). This is an issue that bumped the original fullDuplexSerial from version 1.1 to 1.2. NEGX otherwise displays as zero. In the DECL(port,value) method, think about changing
    if value < 0
             -value
             tx(port, "-")
    
    to
    x := value == NEGX
         if value < 0
             value := ||(value+x)
             tx(port,"-")
    
  • jazzedjazzed Posts: 11,803
    edited 2011-01-22 21:05
    Tracy, I think it is very useful if serial objects also include the "tv.out" method implemented at minimum as a call to "tx".

    Having serial.out would allow most serial drivers to be quickly swapped with TV/VGA drivers.
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2011-01-23 15:01
    Humanoido,

    "I'm sure Beau could give some tips on accomplishing this."

    I'd have to get my head around it again, but one thought would still be to setup a defined master and a defined slave.

    The master initially sends data while the slave receives, and then "since they are in sync" the slave becomes the transmitter on the same lines while the master listens. You could define an area of memory on each side (master and slave) that gets written to and read from. It may not be wise to share the same location for transmit or receive. The throughput would be half of the 14.5 Meg Baud, but you would in essence create a high speed bi-directional conduit between two props where data could be read or written with other cogs.
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-01-28 00:01
    Added the following:

    InterComm
    by Bruce Drummond
    http://forums.parallax.com/showthread.php?129118-Looking-for-suggestions-pertaining-to-new-object
    Prop to Prop custom message creation with parsing
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-02-01 03:50
    Added:

    Full-speed (12 Mb/s) bit-banging USB Host controller by Scanlime

    So far it supports Control, Bulk IN/OUT, and Interrupt IN transfers. There are a couple simple demos included: Device enumeration and descriptor parsing, a very simple HID demo, and an even simpler mass storage demo. As you'd expect, there is a huge list of caveats for something that pushes the limits of the Propeller and the USB spec to this extent.. It uses four cogs, requires overclocking the Prop to 96 MHz, and even though the line rate is 12 Mb/s the actual usable data throughput is significantly lower. But, this lets you talk to a lot of fun new peripherals that were previously unavailable to the Propeller. So it should be fun :)
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-02-05 08:26
    Added:

    [POC] single wire high speed serial link (updated 20101124)
    by kuroneko
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-02-07 12:36
    Added special helpful educational comments by Mike Green
    explaining the nature of serial spin vs serial assembly and
    the effects of the two combined.
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-02-08 17:34
    Added FastSerial by Peter Jakacki
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-02-08 17:45
    Removed InterComm by Bruce Drummond
    http://forums.parallax.com/showthrea...-to-new-object

    Bruce Drummond removed all his attached code from all his posts. Therefore, the link is removed from this list as well.
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-02-08 17:58
    Added HighSpeed Serial Tx (3Mbps) / Rx (2Mbps) + autobaud for FT232R/Prop GPL by Stephen Moraco
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-02-08 18:09
    Added Tweaks and Experiments by Lawson
    http://forums.parallax.com/showthread.php?114492-Prop-Baudrates
    jm_txrx_demo_tweeked.zip
    termv19b.zip

    I can get your "jm_rxserial" to receive garbage too at 2_000_000 baud and 2 stop bits. With some small tweeks though I've been able to get the code working at 1_500_000 baud and 2 stop bits. (commented out a waitcnt after the ASM byte receive loop, and boosted the RX buffer)

    The attached serial terminal is something I found on the 'net to let me send and receive binary bytes over rs232 without having to resort to programming. When I set it to a custom baud rate of 2_000_000 baud, type something into the transmit text box and hit send, garbage sometimes comes back. This terminal program won't do this when I tell it to "send file". My best guess is that whatever text is in the send box is dumped into the TX buffer of the FTDI chip in one block so the FTDI outputs RS232 bytes with no gaps. (setting 2 stop bits helps but won't fix this)
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-02-10 05:31
    Added

    FullDuplexSerial_mini.spin by Rkrasowski
  • Dave HeinDave Hein Posts: 6,347
    edited 2011-02-10 09:49
    Humanoido, you could add cserial.spin to your list. This is part of the CLIB object in the OBEX. It is yet another modified version of FDS that does not use VAR variables, but either uses buffers that are defined in DAT or buffers that are provided by the calling program, in which case it uses a handle to reference them. The bufferes can be any power of 2 in size, and the rx and tx buffers can be different sizes. There is an additional feature where an instance can be protected by a lock to make it cog-safe.
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-02-12 01:37
    Added

    Multiple Instances of Full Duplex Serial Interfacing

    and

    cserial.spin
Sign In or Register to comment.