So these are some completely untested notes on how I might achieve auto-detection of peripherals and I²C devices.
The idea here is that a peripheral can be plugged into any of the 8 ports on the device. It won’t matter, because there’ll be a standard boot-up procedure, consisting of:
- Deriving an I²C bus address (possibly by sampling ADC LSB bits to generate a random address) and verifying that there are no clashes by attempting to poll the derived address a few times.
- Performing a read of the bus roll-call I²C address to enumerate the IDs of all automatically-addressed I²C devices on the bus. During this step, the GPIOs are monitored: the slave should pulse the GPIO it is connected to as it “calls out” its ID.
- Measuring ADC readings at the GPIO pins and observing power-up state (common GPIO pin in high-impedance state)
- Pulling the common GPIO pin (MISO) high and seeing which GPIO pins go high.
- Pulling the common GPIO pin (MISO) low and seeing which GPIO pins go low.
The peripherals may be connected via a number of ways:
The boot-up procedure is used to determine what is attached, by performing some simple actions and observing the GPIO pin, which thanks to the ‘4066s, also doubles as an ADC.
As for I²C addressing… I do not want to have to program a unique address into each device. The concept here is instead that each device generates its own address, waits for a clear moment on the bus, then tries polling its proposed address to see if it gets an ACK. In the case of a time-out, it waits a random length of time and tries again when the bus is clear, and after a few times, can safely assume it has the address.
This gives rise to a problem though, knowing what the addresses of the neighbours are.
The idea here is to use a roll-call address. This is common to all units implementing the auto-addressing protocol. When a device hears the roll-call address, it tries to send its ID in reply. When another device with a numerically lower ID sends at the same time, the device sees the collision and tries again on the next byte. As each calls out its ID, it pulses the interrupt pin low (if it uses one).
The result from the master’s perspective is it sees a stream of IDs sorted from numerically lowest to highest, terminated by a stream of 0xff bytes. Direct peers are able to then detect who their peers are.
Timing of all of this will be the challenge. We want to ensure everyone has a unique ID by he time the first roll-call is performed so we can move on to detecting the dumb devices (LEDs and buttons). This network feature will be a stretch-goal of the project though, so plenty of time to think about that.