Low cost simple communication between two microcontrollers
Given your available options, it appears that you do have some pins available:


SPI is full-duplex and requires 1 clock + 1 data each direction + 1 optional chip select = 3 pins
CAN is half-duplex and requires 2 data for bidirectional comms = 2 pins
USB is half-duplex and requires 2 data for bidirectional comms = 2 pins
TTL Serial is anything you want, but most people use a UART for it, requires 1 data each direction = 2 pins full duplex or 1 pin with some trickery
UART is full-duplex and requires 1 data each direction = 2 pins or 1 pin with some trickery
I2C is half-duplex and requires 1 clock + 1 data = 2 pins


So it looks like the consensus is 2 pins if you want bidirectional communication, or possibly 3 for SPI.  Given equal pin counts, I'd go for the UART if there's one available on both chips.  Assuming a 1:1 connection, you can just toss data across without regard for timing or collisions, and the hardware is really easy.

As for the stack overhead, there are many different protocols that can operate from a UART, but it's probably best in this case to define your own.  From the comms' perspective, you're just spewing out bytes and receiving them at the other end.  The hardware will sync itself to each byte automatically, but you still have to know which byte is what.  You'll have that problem regardless of which option you choose.

If you're clever with a UART (and I'm about to give you the answer), you can connect the two TX pins together with two resistors in series, then have a comparator on each end that drives the RX pin based on the local TX and the center tap of the two resistors.  This allows full-duplex on one wire.  See below for a schematic.

For ESD, add a series resistor inside both cases for each pin and put some clamping diodes on the outboard side of the resistor.  There are diodes specially made for this.









simulate this circuit &ndash; Schematic created using CircuitLab


The "low" resistors are to protect the ESD diodes.  Datasheets may or may not claim that they're unnecessary, but I'd use them anyway.  Make them just big enough to do their job; they need to look like a short compared to the "high" resistors.
The "high" resistors are to mix the two TX signals on the common wire.
The 10k and 5k resistors are to take the full-supply-range TX signal and provide the appropriate threshold for the comparators.
If the two devices are powered independently, you probably shouldn't have the "Optional Connection", leaving you with 2 wires instead of 3.  I don't see how you can communicate at all with fewer pins than this, unless you go wireless.


Here's how it works:


If both TX's are high, the common line will be high and both comparators will output high.
If both TX's are low, the common line will be low and both comparators will output low.
If one TX is high and the other low, the common line will be mid-range and each comparator will have a different threshold based on its local TX.  So the one with a high TX will have a higher threshold than the mid-range common and will output low, and the one with a low TX will have a lower threshold than the mid-range common and will output high.


So in all cases, the receiving comparator output equals the sending TX.

If you don't like the hardware complexity inside the box, then you can use a discrete pin for each direction and keep only the "high" and "low" resistors and ESD diodes - a separate copy for each pin.