2
\$\begingroup\$

Suppose I have 9 microcontrollers each on their own PCB, connected in a square grid. Is there a way I can get a single node to communicate to all the other nodes, be able to address them individually, but with no explicit setup for addressing?

For example, the master node broadcasts over the bus "Hello! I am the master!". The master node is initially designated as master by toggling a switch.

The slave nodes generate a unique ID based on their serial number and broadcast over the bus "Hello! I am serial XXXXX".

The master node can then 'discover' all of these slave nodes, and send instructions to each of them individually.

I was initially leaning towards CAN bus as it is theoretically possible to do this, but the problem is topology and termination. CAN requires a bus topology with minimal stubs, and termination resistors at either end. In my application, I do not know which node will be at the end as they are in a grid, or even which board specifically connects to which other board.

Is there some kind of protocol that allows for this?

\$\endgroup\$
16
  • \$\begingroup\$ "Daisy chain" topology usually means that processor A connects to processor B which is connected to processor C -- the CAN bus is correctly named in that there is a pair of wires that are common to all nodes. \$\endgroup\$
    – TimWescott
    Sep 24 '20 at 20:02
  • 1
    \$\begingroup\$ To clarify: do you want the processor in some specific position to be the master, or do you want to designate a master as, for instance, by switching a switch on the "master" board? Please edit your question. Thanks. \$\endgroup\$
    – TimWescott
    Sep 24 '20 at 20:04
  • \$\begingroup\$ @TimWescott thanks, corrected. \$\endgroup\$
    – aleksk
    Sep 24 '20 at 20:06
  • 1
    \$\begingroup\$ SMBUS is a variant of I2C whereby address conflicts are automatically resolved/assigned by the master. So address free is definitely possible. \$\endgroup\$ Sep 24 '20 at 20:31
  • 1
    \$\begingroup\$ You have addresses in the form of the serial numbers, if those are too long you can get them all, sort, and hand out ordinal member numbers to use as a shorthand from there on. Even without serial numbers you could have some sort of random delay and announce your claim kind of thing, with collision resolution. \$\endgroup\$ Sep 24 '20 at 20:35
2
\$\begingroup\$

I mentioned SMBus in the comments, which is a variation of I2C. As far as I can tell, the only part of this that you need over a standard I2C protocol is the portion known as the ARP - Address Resolution Protocol. This part basically allows for address conflicts to be resolved automatically by dynamically reassigning a device to some other address if a conflict is detected.

Section 6.6 (page 48) of the SMBus 3.0 spec goes into detail on how this works. The full process is kind of complicated, as SMBus is designed to do a lot of things, cope with new devices appearing on the fly (hot plug), and having devices with fixed addresses.

You could either follow that document and implement a fully fledged SMBus (or see if you can find one in your favourite programming language), or create something inspired by the process.


If your system is simply N similar microcontrollers, one which is a master, and the others are slaves, I can envisage an inspired process which works as described below. Essentially to work, the master would keep a list of known slave addresses (ones which it has assigned), and keep a pool of reserved addresses which it can assign to new devices. The slaves have a unique identifier, and a register which keeps track of what their address is, and whether the address has been assigned yet.

  1. After reset, the master clears its list of known addresses, and the slaves all revert back to some constant default address (all devices go to the same default), and set a register to indicate to themself that they have no assigned address yet.

  2. The master sends a special read command to the default address, which tells all slaves listening on that address that address resolution is about to take place.

  3. Any device which has not yet been assigned an address will immediately acknowledge the read and start replying with their unique identifier.

    • If there is no acknowledge, the master knows there are no more devices without an address. Go to step 7.

    • If an acknowledge is received, the master continues its read to receive the UUID of any slave that is responding. If there are multiple devices, they will all start talking at once, this is not an issue. Go to step 4.

  4. As the slave device starts sending out its UUID, it must simultaneously be reading the SDA signal to check for bus contention. I2C hardware typically does this anyway if multi-master is supported. Many MCUs include a flag in their I2C implementation which detects and reports the contention

    If a slave detects bus contention whilst trying to send its UUID, it must immediately stop transmitting. Otherwise it keeps sending its ID.

    Eventually as the read continues, a full UUID will be read back by the master - only one slave device will be left at the end of the read, because bus contention is automatically resolved by giving priority to whichever slave has the UUID with most zero bits at the start (I2C is open drain, so a conflict will always result in a zero being sent). This also has the advantage that if you have the same devices in the system, they will end up with the same address each time.

  5. Once the master has read a UUID back, it then sends a write command to the default address which echos back the UUID and sends a new slave address from the reserved pool. The slave with that UUID detects it is being talked to, acknowledges the master, and then changes its address to the provided address. Upon acknowledge, the master also stores the address and UUID in its table of known devices.

  6. Go back to step 2.

  7. Once all devices have been assigned address, the master now has a complete lookup table of all addresses its given out, and the UUID of the device at that address. Each slave device has a unique I2C address.

  8. You can now use a simple I2C protocol to talk to each device using their assigned address, as if they simply had a fixed address. The address can be looked up in the masters UUID to slave address map.

If devices are likely to be hot plugged, or added later, or might reset unexpectedly, then you can perform ARP again. Any new device or device that crashed and reset will respond and either be reassigned the same address (if the UUID matches a value in the masters lookup table) or assigned a new address from the pool (if a new UUID). You can either periodically check for new devices at an interval of your choosing (good for hotplug) or rescan only if a previously known device stops responding (good to detect a reset).

If the master is likely to be reset without the slaves being reset, you will need an additional command in your arsenal. I2C features a broadcast address 0x00, to which every slave must listen to (usually this is write only). After a reset, the master can issue a write command to this address which instructs all slave devices on the bus to forget their previously assigned addresses and revert to the default address. The ARP process can now reassign all addresses that the master forgot.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you for the very detailed and complete response. This sounds like it will be the way to go. I will be supporting hot plugging and an interval based ARP scan seems to be the way to go. I found an STM microcontroller with an SMBus stack which seems to fit the bill. Here is a link to an application note for your curiosity: st.com/resource/en/application_note/… \$\endgroup\$
    – aleksk
    Sep 25 '20 at 5:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.