Skip to content
  • Home
  • Account
  • Restricted content
  • OBEX
  • Chips Tips
  • Logout
  • Shop
  • QuickBytes
Propeller OBEX
  • OBEX
  • Forum
Login
Propeller OBEX

Propeller 2

  • Configuring Visual Studio Code for Programming the P2 on Mac, Windows, and Linux
  • Breakout Board Options for P2 Edge Modules
  • Solar Panel Monitoring Demo (Intro to Using Video 3 of 3)
  • Wireless Programming with the ESP8266 WX Module
  • Brushless DC Motor Control Demo
  • Colorful Terminal Output with ANSI Escape Sequences
  • XBee RF Transparent and API Mode Demo
  • DS3231 Real Time Clock I2C Demo
  • Multiple Servo Control (up to 64) Object
  • Multiple Serial Port (8 UART – 16 Tx/Rx) Object
  • Goertzel Operation with Ultrasonic Transducers
  • Web Page Control of WS2811 LEDs Using the IoT Gateway on Raspberry Pi
  • 320×240 LCD Driver for ILI9341 Controller and XPT2046 Touch Screen
  • Digital Sample ADC to DAC + Analog Frequency to DAC
  • Using Smart Pins to Measure Frequency Output of TSL235R Light-to-Frequency Sensor
  • Ping))) Ultrasonic Distance Sensor with Graphical Debug Demo
  • Simple Analog Input
  • P2 Edge 16 MB Flash Reader and Explorer Utility
  • LED Matrix used as an I/O Test Utility
  • Arlo Conversion to P2 with the Universal Motor Controller
  • Five Buttons On One Pin
  • P2 RTC Add-on Board Demo
  • Simple Video Driver – Using Images (Intro to Using Video 2 of 3)
  • Starting Your P2 Project with a Spin2 Template
  • E-Ink Display Demo
  • MAX7219 LED Display SPI Demo
  • DHT11, DHT22, CM2302 Humidity and Temperature Sensor Object
  • NMEA GPS String Parsing
  • Floating Point Math: DEBUG and Terminal Display Example
  • LEDs – Beyond the Basics
  • Quadrature Encoder Object
  • P2 RTC Add-on with GPS Module
  • DVI/VGA Text Driver Demo
  • PCF8574 I2C LCD Demo
  • Simple Sound Engine Demo
  • 1-Wire Driver with DS18B20 Temperature Sensor Demo
  • Send Email from the Propeller 2 Using the IoT Gateway on Raspberry Pi
  • I2C Device Bus Scanner Utility
  • 32-Channel ADC Object
  • Tetris
  • Video Hardware with Character Map Demo (Intro to Using Video 1 of 3)
  • WS2811, WS2812, WS2812b, WS2813, SK6812x NeoPixel Object
View Categories
  • Home
  • Docs
  • Quick Bytes
  • Propeller 2
  • Multiple Serial Port (8 UART – 16 Tx/Rx) Object

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

Reading Time: 7 min read

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)
Parts Used #
  • P2 Edge Module
  • P2 Edge Breadboard
  • - or -
  • Propeller 2 Evaluation Board
Source Code #
  • mpx_multi_serial_demo.zip
Programming Language #
  • Spin 2 and PASM
Tools and Operating System #
  • PNut_v35c.exe for Windows
  • Propeller Tool for Windows
  • FlexProp for Windows, Mac, Linux
Additional Resources #
  • Propeller 2 Spin Documentation
  • Parallax Discussion Forum Thread
Document Author #
  • Ray Rodrick (Cluso99)
Source Code Author #
  • Ray Rodrick (Cluso99)
  • Jon McPhalen
Protocols, Smart Pins
Was this useful ?

Share This Article :

  • Facebook
  • X
  • LinkedIn
Still stuck? How can we help?

Still stuck? How can we help?

Updated on September 29, 2026
Multiple Servo Control (up to 64) ObjectGoertzel Operation with Ultrasonic Transducers
Table of Contents
  • Description
  • Parts Used
  • Source Code
  • Programming Language
  • Tools and Operating System
  • Additional Resources
  • Document Author
  • Source Code Author

Copyright © 2026 - Parallax Inc.
599 Menlo Drive | Rocklin, CA 95765 | USA