Multiple Serial Port (8 UART – 16 Tx/Rx) Object

Share on facebook
Share on twitter
Share on linkedin
Share on email
Share on print
Table of Contents
Description

The Propeller 2 can manage multiple UARTs simultaneously and be an aggreator of many serial inputs. This driver is useful for interfacing with multiple serial devices (GPS, sensors, etc) functioning in parallel. This application uses smart pins and only one of eight cogs in the Propeller 2.

This example shows how 8 full-duplex UARTs may be configured on the Propeller 2 using 16 I/Os, on any pins 0 to 63. These UARTs may be configured in any combination of transmitters and receivers at any baud. The code provided in these examples runs on PNut, Propeller Tool for Windows, and FlexProp.

The terminal displays above are showing characters received from serial pin 63 and sending-receiving it via pins 3-2-5-4-7-6-9-8-11-10-13-12-15-14 and finally back to pin 63, with Propeller Serial Terminal and FlexProp Terminal, respectively. 

Three demonstrations are provided in the zip code below:

  • One (1) full-duplex serial port (UART) using (2) I/O (mpx_demo2.spin2)
  • Two (2) full-duplex serial ports (UARTs) using (4) I/O (mpx_demo4.spin2)
  • Eight (8) full-duplex serial ports (UARTs) using (16) I/O (mpx_demo16.spin2)

It is possible to modify the driver to support more than 16 I/Os as the P2 could configure all 64 pins to be used as serial UARTs. 

Starting the Driver

The following instruction starts a new cog with the PASM driver code as follows:

  cog := mpxcog.start(@port_control)    ' start multiport serial pasm driver in new cog

@port_control is the pointer to the port control and parameter buffers. To stop the driver cog, execute the following instruction:

  cogstop(cog - 1)                      ' stop the driver

The driver continuously scans the port_control buffer to determine which of the 16 possible pins/ports are running UARTs. For those which are, the driver checks to see if it is a transmitter pin/port and if so checks the relevant buffer for a character. If a character is in the buffer it will transmit the character. If the pin/port is a receiver, the driver will check to see if a character is available from the smart pin, and if so it will read it and put it in the relevant buffer.

The smart-pins are started/stopped using the start/openport/closeport methods.

Configuring the Pins/Ports

There are two methods (calls) that can be used to configure the pins/ports. The first configures a single full-duplex port:

pub start(p_portctl, rxxport, rxpin, rxmode, rxbaud, p_rxstart, p_rxend, txxport, txpin, txmode, txbaud, p_txstart, p_txend)

'' Start simple serial coms on rxpin and txpin (can be individually configured using openport)
'' -- p_portctl. hub addr of port_control[0-15] followed by port_params[16]
'' -- rxport.... receive  port[n]        (0-15) (-1 if not used)
'' -- rxpin..... receive  pin                   (-1 if not used)
'' -- rxmode.... %0xx1 = invert rx              (same for txmode)
''               %0x1x = invert tx
''               %01xx = open-drain/open-source tx
'' -- rxbaud.... receive  baud 
'' -- p_rxstart. hub address of start of the receive  buffer
'' -- p_rxend... hub address of end+1 of the receive  buffer

'' -- txport.... transmit port[n]        (0-15) (-1 if not used)
'' -- txpin..... transmit pin                   (-1 if not used)
'' -- txmode.... %0xx1 = invert rx              (same for txmode)
''               %0x1x = invert tx
''               %01xx = open-drain/open-source tx
'' -- txbaud.... transmit baud 
'' -- p_txstart. hub address of start of the transmit buffer
'' -- p_txend... hub address of end+1 of the transmit buffer

The second method (call) configures just a single port at a time. A transmit pin/port and a receive pin/port is possible per object:

pub openport(p_portctl, xport, xpin, xdirn, xmode, xbaud, p_xstart, p_xend) : status | spmode, baudcfg

The closeport method (call) closes the pin/port:

pub closeport(p_portctl, xport, xpin)

Methods (calls) Provided

There are additional configuration methods (calls):

pub setStripLF(n)                                       ' 0=OFF, 1=ON   optionally strip <lf> when transmitting characters
pub setEcho(n)                                          ' 0=OFF, 1=ON   optionally echo received characters to the transmitter

The following are the basic methods (calls) for the transmitter pin/port:

pub txChr(chr) | n, p, head, new                        '* xmit a character
pub txStr(p_str)                                        '* xmit a formatted string
pub txStrCR(p_str)                                      '* xmit a formatted string followed by <cr><lf>
pub txCR()                                              '* xmit <cr><lf>
pub txASCII(chr)                                        '* xmit a character (converts $00-$1F & $7F-$FF to ".")
pub txDump(addr1, addr2) | addr, addrend, i, j, mask    '* dumps hub memory as lines of 16 bytes + ASCII                    
pub txn(chr, n)                                         '* xmit a character 'n' times
pub txFlush() | p                                       '  wait until the xmit buffer and uart are empty 
                                                        '* = above methods optionally strip <lf>

The following are the basic methods (calls) for the receiver pin/port:

pub rxChr() : chr | p, head, tail, new                  '* recv a character
pub rxStr(p_str) | addr, chr                            '* recv a 0 terminated string (<cr> terminates entry)
pub rxCheck() : chr | p                                 '  checks rx buffer and returns -1 (True) if no chars available, else returns a char
PUB rxPeek() : stat | p                                 '  checks rx buffer and returns -1 (True) if no chars available, else 0 (False)
pub rxAvail() : count | p                               '  checks rx buffer and returns the number of characters in the buffer, 0 = none
pub rxTime(ms) : chr | mstix, t                         '* waist up to ms for a character, returns -1 (True) if no chars available, else returns a char
pub rxTix(tix) : chr | t                                '* waits up to clock-ticks for a char, returns -1 (True) if no chars available, else returns a char
pub rxFlush()                                           '  flushes (clears) the rx buffer
                                                        '* = above methods optionally echo the received char to the transmitter (if enabled)

In addition to the above transmit methods, the following unformatted string methods (calls) are provided:

pub str(p_str)                                          '* xmit an un-formatted string
pub substr(p_str, len) | chr                            '* xmit an un-formatted string with a maximum length
pub padstr(p_str, width, pad)                           '* xmit an un-formatted string of 'width' characters padded using the 'pad' character
                                                        '  -- width:  positive is right alignment, negative is left alignment 
                                                        '* = above methods optionally strip <lf>

In addition to the above transmit methods, the following formatted string methods (calls) are provided:

pub fstr0(p_str)                                        '* xmit a formatted string
pub fstr1(p_str, arg1)                                  '* xmit a formatted string with 1 variable
pub fstr2(p_str, arg1, arg2)                            '* xmit a formatted string with 2 variables
pub fstr3(p_str, arg1, arg2, arg3)                      '* xmit a formatted string with 3 variables
pub fstr4(p_str, arg1, arg2, arg3, arg4)                '* xmit a formatted string with 4 variables
pub fstr5(p_str, arg1, arg2, arg3, arg4, arg5)          '* xmit a formatted string with 5 variables
pub fstr6(p_str, arg1, arg2, arg3, arg4, arg5, arg6)    '* xmit a formatted string with 6 variables
pub format(p_str, p_args) | idx, c, asc, field, digits  '* xmit a formatted string with n variables
                                                        '* = above methods optionally strip <lf>

In addition to the above transmit methods, the following methods (calls) to convert values are provided:

                                                        '  xmit 'value' converted to a number using...
pub fmt_number(value, base, digits, width, pad)         '  -- decimal/hex/octal/quarternary/binary
pub dec(value)                                          '  -- decimal
pub fdec(value, digits)                                 '  -- decimal and...
pub jdec(value, digits, width, pad)                     '  -- decimal and...
pub dpdec(value, dp)                                    '  -- decimal and...
pub jdpdec(value, dp, width, pad)                       '  -- decimal and...
pub hex(value)                                          '  -- hex
pub fhex(value, digits)                                 '  -- hex and...
pub jhex(value, digits, width, pad)                     '  -- hex and...
pub oct(value)                                          '  -- octal
pub foct(value, digits)                                 '  -- octal and...
pub joct(value, digits, width, pad)                     '  -- octal and...
pub qrt(value)                                          '  -- quarternary
pub fqrt(value, digits)                                 '  -- quarternary and...
pub jqrt(value, digits, width, pad)                     '  -- quarternary and...
pub bin(value)                                          '  -- binary
pub fbin(value, digits)                                 '  -- binary and...
pub jbin(value, digits, width, pad)                     '  -- binary and...
                                                        ' where... digits: number of digits
                                                        '          dp:     number of decimals
                                                        '          width:  positive is right alignment, negative is left alignment
                                                        '          pad:    'pad' character

Buffers (in hub memory)

The calling program must provide the following contiguous buffers in hub memory:

port_control    byte      0[16]                                 '\ control (always 16 ports) %atpppppp where...
                                                                '| --  a: 1 = port active, t: 1 = tx, 0 = rx, pppppp: = port pin
port_params     long      0[4*MAX_PORTS]                        '| max (16 ports) of 4 longs...   (note: (no need to fill/reserve unused ports))
                                                                '/ --  port[n]: p_head, p_tail, p_start, p_end

In addition to the above buffers, the following buffer(s) must be provided in hub memory for each pin/port:

  byte  ??BUF?[??BUF?_SIZE]                                     ' buffer of desired length, one for each pin/port (maximum of 16)
Programming Language
Tools and Operating System
Document Author
Source Code Author
Table of Contents
5 1 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments