I have designed an instrument that is composed of several modular boards (a main processor board and a number of peripheral boards) which can be combined in any arrangement, provided that there is always one (and only one) main processor board). The boards communicate with each other via I2C. Usually, I2C serial slave addresses (7 bits) are set in hardware for a given type of device, with perhaps 2 or 3 pins available for hard-coding unique slave addresses among a group of otherwise identical devices. In this case, the I2C serial slave address is associated with the microcontroller on each board and is entirely software-configurable.
The issue is this: at startup, I might have two (or more) identical peripheral boards in the instrument and have to be able to get unique I2C slave addresses into each one. I cannot hard-code the slave addresses in firmware for each device. Some sort of automatic unique address distribution scheme has to be implemented in the main board in order to handle this. I do have a laser-etched unique serial number available from a Dallas Semiconductor DS28E04-100 on every board, but I need a way to generate a unique 7bit I2C address for each board.
This is my first-order solution:
1) Main board initiates the algorithm by sending a broadcast write to all devices asking for a response.
2) Each peripheral sets its slave address to a temporary value (e.g. 0x7F) and attempts to send a data packet to the main board with a payload consisting of the board's unique serial number (from the DS28E04-100) and the board type identifier (hard-coded into the firmware of the peripheral). The write attempts will all collide, and the automatic I2C bus arbitration will elect a winner. All boards that lost the arbitration will continue to try again until they win and get their message through.
3) When no new I2C messages have arrived at the main board for a millisecond or two, there are no boards left trying to get their serial numbers in. The main board goes through its accumulated list of board serial numbers and assigns a unique I2C slave address to each one. It then sends a global broadcast message for each board which contains its serial number and associated I2C slave address.
4) When a peripheral board receives a global broadcast that matches its unique hardware ID, it sets its own slave address to the one contained in the message.
5) The main board then tests its delivery of slave addresses by sending non-global targeted messages to each of the slave addresses on its list, asking for an echo back of the board's unique serial number. If the returned serial number matches, then a confirmation message is sent back to the slave.
6) If it is found that the I2C bus arbitration is less-than-perfect, any lost devices can be found by restarting the process selectively for only those devices that haven't received a slave address and confirmed receipt with the main board.
----
Is there an easier way to accomplish this?


hi mouser,
don't have the timeout (unless you need it later on in the boot process)... just assign the unique id's as the messages come in. have all the slaves without a unique id participate in rounds...
(hey Brian, long time...)
The only reason I've got the timeout in there now is because one of the first things the instrument has to do after initializing itself is to report its condition to a host computer, and that includes a list of attached peripherals. So I need to be sure I've gotten everyone before I generate my report.
I suppose that the idea is to have only an I2C bus running between all your modules.
But maybe you could have some extra pins on a connector on each board (say 3, if you need no more than 7 modules) and then have you modules read those pins before deciding what it's address is. You of course would supply a different binary code on those extra pins for each module.
Not elegant, but doesn't require too much thinking, at the expense of extra bus lines.
Well, if I could afford the spare device-select lines, I would just use SPI which is faster and much easier to implement. However, in this case I am restrained to the two wires between each board.