adafruit / seesaw

I2C friend to expand capabilities of other chips.
Other
76 stars 34 forks source link

RFC: Support for a shared IRQ line #71

Open CraigBurden opened 5 months ago

CraigBurden commented 5 months ago

Firstly I recently came across this project and have been thinking of something similar for a while, it is really great!

One feature I have been thinking about for quite a while and I see that isn't supported is this spec is support for shared IRQ lines. Of course this would only allow for shared IRQ lines when all devices on that line are Seesaw devices, but I think that would be really useful for daisy chaining scenarios. Of course there are ways to share an IRQ line currently but they require the host to scan each device on the bus to find the one that issued the request, this adds a lot of latency when there are many devices.

My pitch for how this could be implemented comes in three main parts:

  1. The IRQ pins should be open-drain and a pull-up should be used. This allows all devices on the shared line to signal without causing damage to each other
  2. An implementation of a I²C broadcast message. This is a message that all devices on the bus listen to and respond only if specific conditions are met.
  3. Interrupt priorities, each device has an associated priority that helps to remove contention on the IRQ line

The basic concept is that any device on the bus can issue an IRQ by pulling the IRQ line down. The host of the bus then sends out a broadcast message that asks "Who said that?", the issuer immediately responds with it's device address and perhaps it's interrupt register content. It can then deassert the IRQ line as the host has been notified, the host may of course still take some action like reading a value, but we want to free the IRQ line to allow for other devices to assert.

Another detail is that devices on the bus only assert the IRQ line if it isn't already asserted. This ensures that the signal is not lost. If two or more devices need to indicate at the same time, as soon as one IRQ is dealt with, the line would deassert and the other devices would be waiting to assert it. This is where the priority comes in, if a device wants to issue an IRQ while another is active on the bus, it waits until the line deasserts and then delays a period according to it's delay before asserting, assuming the bus is still deasserted. This allows for higher priority devices to jump the line if needed. Of course those delays can be very short, I²C bus speeds are typically 100kHz or 400kHz (just as a comparison of acceptable signal propagation delays in OD buses) so we can reasonably allow for delays of 2-10µS. You could make the delay multiplier variable (or based on the bus speed) to allow slowing the arbitration time if the bus is very slow.

One other thing that the broadcast could add to the ecosystem is a discovery message, new devices are discovered by scanning the whole address space. Having a broadcast message that asks "Is there anyone new out there", followed by an assertion of the IRQ (to allow arbitration of the responses) from devices that haven't already been discovered (this could be determined by the state of a flag), this would make this discovery process very quick and easy. One other cool thing here is that if we allowed Seesaw devices to change their device address on command, this can be used to deal with devices that share addresses. If a new device responds to the discovery message that shares an address with another, the host can change it as part of the broadcast interaction.

I realise this is open-source and so I am not asking for someone to just go build this because I want it. I will happily build this and PR it, but I am looking for comments and discussion.

Is this something that others would find useful? Is this a decent solution to the problem? What would you change or improve?