I agree. Bus arbitration is not part of standard uart or spi.
I have set up my own "home network" based on uC's with uart and RS485 drivers and collision detection does indeed not work. Even with about a meter of cable in between, each RS485 driver just reads it's own data back.
Collision avoidance does work, and is what I apply. I have my network setup as a multi master bus and packetized the data (16 bit adresses, 16 bit CRC and some extra bits in the header. When a node wants to send data, the send routine first monitors the RS485 line for a time that is longer then a byte. So if any other node is sending, it detects this and backs off for some time. If nobody is sending, then it enables the RS485 driver and starts sending as quick as possible This way there is around a 100ns period in which there is an opportunity for more then one node to grab the bus, and thus cause a collision. (This may increase for long cable runs as the delay on the cables may become a factor). This works "well enough", but it's not error free. I once did a test by sending over a million packets in around half an hour, and in that time I had nodes backing off a few times (so that part worked), but I also had 3 or 4 damaged packets.
CAN transceivers do have a "dominant" and "passive" state, and with that you can do reliable collision detection. I did not use CAN back then, because I don't like the weird addressing scheme and the small packet size. But you can use CAN transceivers connected to an UART. But a UART does not have collision detection hardware, and thus it would require extra hardware to do this. For example with an XOR port on the CAN transceiver, a filter, and maybe a bit more (Have not thought about details).
My system also does (mostly) automatic resends of packets if no answer is received within a certain timeframe. This mitigates the effect of lost packets, but it also introduces the problem that the response can be damaged, resulting in two valid packets received by the "remote node". Whether this is acceptable depends on how data is formatted. With "turn a relay on" it's not a problem, but with "toggle a relay on/off" it is a bigger problem.
Another software mechanism is to have a node to handles the arbitration. You can implement something like token ring, in which a special packet is passed around, and the node who last received the packet (microphone?) may speak. But this also requires a mechanism for when that special packet is lost. (It can for example respawn after a set amount of time).
A multi master bus is also by definition half duplex. This requires a way to connect RxD and TxD of a uart together (for example with the RS485 driver chip). When the TxD is always active, different nodes can be separated by diodes on the Txd line. This transforms it into a wired or (Or better: wired AND, as TxD is high in idle state) Some uC's have built in options to combine RxD and TxD of the uart into a single signal. (Also look up LIN bus).
--------------------
SPI is another monster.
If you have a multi drop bus, then you don't know which one is master, and who is the slave. So which line is MISO and which is MOSI? And how do you want to handle the slave select line(s)? Usually SPI leaves a lot of options open (such as clock and data polarity). As it happened I had a chat with one of those AI bots last week about setting up a multi master bus with SPI for STM32. And apparently it can work when you do the programming carefully. The (finally suggested) setup was:
- Ignore MISO. The bus uses effectively only half duplex.
- Everybody shares the slave Select line.
- Everybody is slave by default.
- When a node wishes to become a master, it first checks for the idle SS line. (Backs off if the bus is busy).
- If the bus is free, it grabs the bus by pulling SS low. (It's possible two nodes grab the bus at the same time!)
- When SS is low, it waits a bit of time depending on "node priority".
- During this time (A bunch of us) it polls the SCK and MOSI lines in a tight loop.
- If activity is detected, the node backs off, (also releases SS, the "other master" keeps SS active during the transaction).
- If no other master is detected in this time, the node starts sending.
This scheme is "pretty good", but still not completely fool proof. So adding checksums and resend mechanisms is still advisable.
If you're interested in networking, I also recommend the Tanenbaum book about networking / internet. With a more elaborate network waiting for a response for each packet introduces far to much latency. Therefore the "master" sends multiple packets in a row, and then later sorts out which packets got received and which have to be resend. This also introduces an extra problem of packets getting received out of order.
I2C is also an interesting bus. The specification supports multi master node (And Philips / NXP has nice application notes about the protocol). In practice many implementations of I2C are not complete, and multi master is not always implemented, or leads to faults. I don't have enough experience to know more about details here.