08/21/2014 at 01:35 •
One of the design issues of the intelligent shield bus is how to send interrupts from a shield. I like event based programming and think that shields should be able to create events, they should not need to be polled.
Adding interrupt signals to the bus is not a good solution. It would be much nicer if we could just use the I2C bus itself. And we can. By using the Multi-master mode. In Multi-master mode several nodes can write to the bus at the same time, and use Bus Arbitration to find out that this is happening and determine which node gets to keep writing to the bus.
It may complicate our terminology when shields, as well as the CPU board, can be bus masters. But we really need the functionality.
One complication, the node that lost the bus arbitration may actually be the intended destination for the transfer that won. So a node may have to interrupt writing to the bus and instead start reading from it. Fortunately at least some AVR processors has support for this. And it turns out that the default Arduino Wire library actually seems to implement this support. If the AVR is in Master Transmitter or Master Receive mode, loses arbitration, finds out that the address on the bus is its own slave address (or the general call address) it will actually move to Slave Receive or Slave Transmitter automatically. Nice.
However one thing the Wire library does is that it considers a lost bus arbitration to be an error condition, and aborts writing to the bus. This is not what we want. Instead we should instruct the AVR to wait for a STOP condition and then retry sending data. Unless we are addressed, then we need to handle the incoming call before we try to write to the bus.
Bus arbitration is not an error, but a normal condition of having multiple masters on the bus.
08/21/2014 at 01:14 •
SMBus already uses a dynamic address resolution, and SMBus is based on I2C. So maybe we could just use their algorithm?
SMBus relies on slave bus arbitration. Bus arbitration on I2C works by the node both writing to the bus, and listening to the bus. If several nodes write to the bus 0 always trumps 1. So if a node writes a 1 but reads a 0 it knows that several nodes are writing at the same time. It also loses arbitration and needs to shut up. In the dynamic address resolution of SMBus each node that needs an address writes its unique id. Since the UIDs differ the nodes must lose arbitration until only one is left. That node gets an address, and then the process repeats until all nodes have gotten an address.
However most AVR processors with I2C (or TWI) support do not support bus arbitration in slave mode. They only support bus arbitration in master mode. Which seem to make it impossible to implement the SMBus address resolution protocol on an AVR based Arduino. At least using the builtin TWI support, there is probably a way if you build a software I2C implementation.
Another factor is that the SMBus standard requires a unique id for each node. Something which may make it harder to create firmware, since each shield would need its UID added in the flashing process.
So I think there are three ways to design a dynamic address resolution algorithm, that can be implemented on an AVR based Arduino:
1) A UID based approach, that uses bus arbitration in master mode
2) A random number based approach, that uses bus arbitration in master mode
3) An shield enable signal, that is connected between each shield, so we can enable each shield in order
I do not like the first approach because of the need to add a separate step when flashing the shield firmware
I am not sure how easy it is to get a good enough random number on an AVR processor. If it is easy then we should look into this approach.
Now I like the third approach best. The drawback is that it will not be as easy to build a board with through-hole connectors. However it will be easy using surface-mount components. Another advantage is that we will find the physical layout of the shields. We will know in which order the shields are stacked, and may use that order when programming.