
Jesus Echavarria has developed a dual USB-Serial converter for debugging serial and I2C communications:
Hi all! After a couple of months with a lot of work, I come here again with the last board I develop before Christmas. It’s a dual USB serial and I2C converter based on two MCP2221 Microchip 2.0 USB-Serial bridges. I develop it as a need on my work with the last project I’m involved. I need to monitor a serial communication between two devices. With only one converter, I must choose between RX and TX lines to monitoring the traffic. With this solution, I can listen at the same time TX and RX lines, so the monitoring is more easy. And with a software like Docklight (you can download a free evaluation copy here), you can choose the monitoring option to display both channels. After the break you can find all the technical info of the board!
More details at Echavarria’s project page.

I did something similar, to debug the comms between the ESP8266 and the atmega32u4 on a cactus micro rev2 board. But I just hooked up two USB serial adapters with probes, I didn’t bother making a board for it :-)
I also wrote a trivial python program to read both serial ports and output them interleaved.
#!/usr/bin/python3
import serial, time, sys, threading
from colorama import Fore, Style, init as colorama_init
colorama_init()
# lock to serialize console output
lock = threading.Lock()
class Highlight:
def __init__(self, clazz, color):
self.color = color
self.clazz = clazz
def __enter__(self):
print(self.color, end=””)
def __exit__(self, type, value, traceback):
if self.clazz == Fore:
print(Fore.RESET, end=””)
else:
assert self.clazz == Style
print(Style.RESET_ALL, end=””)
sys.stdout.flush()
if len(sys.argv) != 3 and len(sys.argv) != 4:
sys.stderr.write(“Usage: %s []\n” % (sys.argv[0]))
exit(1)
def read_serial(port, baud, color):
ser = serial.Serial()
ser.port = port
ser.baudrate = baud
ser.bytesize = serial.EIGHTBITS #number of bits per bytes
ser.parity = serial.PARITY_NONE #set parity check: no parity
ser.stopbits = serial.STOPBITS_ONE #number of stop bits
#ser.timeout = None #block read
ser.timeout = 0 # non blocking read
ser.xonxoff = False #disable software flow control
ser.rtscts = False #disable hardware (RTS/CTS) flow control
ser.dsrdtr = False #disable hardware (DSR/DTR) flow control
ser.writeTimeout = 2 #timeout for write
try:
ser.open()
except Exception as e:
print(“error open serial port: ” + str(e))
exit()
if ser.isOpen():
try:
while True:
c = ser.read(size=1024)
with lock:
if len(c) > 0:
print(color)
sys.stdout.buffer.write(c)
ser.close()
except Exception as e1:
print (“error communicating…: ” + str(e1))
else:
print(“cannot open serial port “)
exit()
# Create two threads as follows
try:
t = threading.Thread(target=read_serial, args=(sys.argv[2], sys.argv[1], Fore.GREEN ))
t.daemon = True # thread dies when main thread (only non-daemon thread) exits.
t.start()
if len(sys.argv) == 4:
t = threading.Thread(target=read_serial, args=(sys.argv[3], sys.argv[1], Fore.RED ))
t.daemon = True # thread dies when main thread (only non-daemon thread) exits.
t.start()
except:
print(“Error: unable to start thread”)
try:
while True:
pass
except KeyboardInterrupt:
exit()
Sorry about the indentation, here is a gist!
https://gist.github.com/RoganDawes/1042a316a9d320d5e2ff