While working on a multiple CAN transceiver project for a test automation suite, I decided the most cost effective architecture for a single interface with lots of CAN nodes was to use multiple super-cheap MCUs with one CAN interface each and a shared bus.  Since the most ubiquitous communication interface on inexpensive MCUs happened to be a UART, I decided to build a shared UART bus with a FTDI USB/UART bridge at the head end.

The downstream host-to-many direction was implemented by tying the FTDI’s UART transmit line to all the MCU’s receive line through a single buffer/driver to eliminate fan-out concerns.  Arbitration is not needed here as an address scheme in the protocol defines which MCU is being addressed by the host.  All MCUs see the same broadcast data from the host, but act only on packets with their node id.

The upstream many-to-host direction needs more control.  Each MCU’s UART transmit line is tied to a common net through a tri-stateable buffer – again for fan-out concerns with so many capacitive loads on the same wire.  An arbitration mechanism is needed to keep each node from talking over the other.  This could be solved by having the host schedule a time window where each node could relay back a frame (or nothing) – eg a polling scheme.  However this is a bit inefficient.  It occurred to me a simple fixed priority arbiter could be made out of a SPLD like a 22v10.


My requirement was to create a cascade-able fixed priority arbiter out of a common logic device.  Most logic devices are either combinatoric or registered logic but not both.  The most common devices that include both are V series SPLDs like 16v8s and 22v10s.  I chose the later due to a higher pin count – meaning more nodes could be supported w/o cascading.

The design has specific 10 outputs – 9 grant lines to slave nodes and 1 request line to an upstream master arbiter.  The design has 10 specific inputs – 9 request lines from slave nodes and 1 grant line from an upstream master arbiter.  If cascade support is not needed, the upstream request line can be tied to the upstream grant line.  This design, implemented on a 22v10, can act as all arbitration nodes at each level in a multi-tier scheme.  The design has 2 common inputs – an asynchronous reset to ensure all flip-flops are in a deterministic state at the start of operation and a clock input to pace grant evaluation and prevent racing.  The clock input can be any frequency and determines the minimum grant response to any request.

In a cascading system, all arbiters can use the same clock.  The cascade chain can be infinitely long, but the minimum grant time is 1 clock for a single device, 2 clocks for a two tier cascade, 3 clocks for a three tier cascade, and so on.  All resets should be tied together for a multiple device cascade.


The following CUPL code is the complete implementation of the arbiter:

Pin  1 = CLK;
Pin  2 = !R0;
Pin  3 = !R1;
Pin  4 = !R2;
Pin  5 = !R3;
Pin  6 = !R4;
Pin  7 = !R5;
Pin  8 = !R6;
Pin  9 = !R7;
Pin 10 = !R8;
Pin 11 = !GE;
Pin 13 = !RESET;

Pin 14 = !RE;
Pin 15 = !G8;
Pin 16 = !G7;
Pin 17 = !G6;
Pin 18 = !G5;
Pin 19 = !G4;
Pin 20 = !G3;
Pin 21 = !G2;
Pin 22 = !G1;
Pin 23 = !G0;

G0.d = GE & R0 & (G0 # (!G1 & !G2 & !G3 & !G4 & !G5 & !G6 & !G7 & !G8));
G1.d = GE & R1 & (G1 # (!G0 & !G2 & !G3 & !G4 & !G5 & !G6 & !G7 & !G8 & !R0));
G2.d = GE & R2 & (G2 # (!G0 & !G1 & !G3 & !G4 & !G5 & !G6 & !G7 & !G8 & !R0 & !R1));
G3.d = GE & R3 & (G3 # (!G0 & !G1 & !G2 & !G4 & !G5 & !G6 & !G7 & !G8 & !R0 & !R1 & !R2));
G4.d = GE & R4 & (G4 # (!G0 & !G1 & !G2 & !G3 & !G5 & !G6 & !G7 & !G8 & !R0 & !R1 & !R2 & !R3));
G5.d = GE & R5 & (G5 # (!G0 & !G1 & !G2 & !G3 & !G4 & !G6 & !G7 & !G8 & !R0 & !R1 & !R2 & !R3 & !R4));
G6.d = GE & R6 & (G6 # (!G0 & !G1 & !G2 & !G3 & !G4 & !G5 & !G7 & !G8 & !R0 & !R1 & !R2 & !R3 & !R4 & !R5));
G7.d = GE & R7 & (G7 # (!G0 & !G1 & !G2 & !G3 & !G4 & !G5 & !G6 & !G8 & !R0 & !R1 & !R2 & !R3 & !R4 & !R5 & !R6));
G8.d = GE & R8 & (G8 # (!G0 & !G1 & !G2 & !G3 & !G4 & !G5 & !G6 & !G7 & !R0 & !R1 & !R2 & !R3 & !R4 & !R5 & !R6 & !R7));

RE = R0 # R1 # R2 # R3 # R4 # R5 # R6 # R7 # R8;

[G8..0].ar = RESET;
[G8..0].sp = 'b'0;
[G8..0].ck = CLK; = RESET;
GA.sp = 'b'0; = CLK;


Each slave must assert it’s request signal (active low) and then monitor for it’s grant signal to indicate active (low) before communicating on the bus.  While granted, no other slave can interrupt a current grant so long as the slave holding the grant maintains it’s request signal.  Once a slave releases it’s request signal, it must wait at least one arbitration clock pulse duration before attempting to re-assert the request signal as the grant may still reflect the previous state evaluation until the next arbitration clock.  For cascaded systems, it is advisable slaves wait <n> arbitration clock periods between requests where <n> is the tier count.

A system master must ensure a reset assertion on power up to prevent in-deterministic transients.  This can be done by a designated reset master or a power supervision reset chip like a MCP130.


This code is (c) Alan Hightower – and release under the GPLv2 license.  Please be respectful and carry it forward.