monome / crow

Crow speaks and listens and remembers bits of text. A scriptable USB-CV-II machine
GNU General Public License v3.0
162 stars 34 forks source link

add high-reliability mode for i2c #457

Closed trentgill closed 1 year ago

trentgill commented 2 years ago

this adds a new function ii.fastmode(state) to crow's lua system. a truthy value will set to fast (ie. the current normal) speed communication. while a falsey value will use slower timings with a much wider window on the rising edge of all clocks. this slow-mode (aka stable-mode) is now the default selection.

the motivation here is that a change in version 3.0 slightly increased the speed of communication (closer to the 400kHz limit of i2c fast mode), and we saw some reports of slightly less reliable i2c systems.

i2c communication speed is limited by the rise-time of the i2c lines. this rise time is a function of 1) how much pullup current is supplied to the lines 2) how many devices are attached to the network 3) total length of cables in the network.

Both 2) and 3) increase the effective capacitance of the network. This capacitance forms an effective 1pole lowpass filter with the pullup current resistors. The greater the capacitance, the lower the filter cutoff, and thus the slower the rising of the lines. This filter primarily affects the low-to-high transition of the i2c lines, and the fall-time can be ignored.

My 2 extreme test cases are a best-case, and a worst-case scenario:

best case: 2 crow modules, connected with <1" path, both with 40k pullup resistors to +3v3 and dedicated 2.2k pullup resistors on a busboard. Effective pullup current is ~1.5mA per line.

worst case: 2 crow modules, connected with 35" cable, with pullups disabled on 1 crow, and 40k enabled on the other. Pullup current is ~83uA (roughly 18 times less than the ideal).

In the worst case, the typical values would always fail on the first transmission, but reliably works with stable-mode timings. Communicating at roughly 55kHz clock speed. The lines were measured to reach around 2.3V on each rising edge (this is the 0.7xVdd requirement).

In the best case, either stable or fast mode works fine. Stable mode will reach speeds of 137kHz (nb. how the i2c driver auto-compensates). Fast mode reaches around 350kHz (slightly slower than the 400kHz limit of the spec). While the speed could be increased here, the slightly reduced speed results in higher voltage being reached on each rising edge (~2.5V) which was compromised to get the last 50kHz speed increase.

//

While the above was not tested with a great many other modules (though a White Whale was added to the bus to confirm it didn't dramatically influence capacitance [it didn't]), the observed behaviour suggests this should help with stability of some bus configurations.

A small subset of people who were really pushing the throughput limit of the i2c bus may find their scripts overload the bus now (though this feels incredibly unlikely). In that case they can place ii.fastmode(true) in their init function. This will almost certainly not be needed by anyone, but is kept here just in case someone wants to really push the maximum rate on the bus.

The key benefit is that setups that have crow as the only device providing pullup current may be able to operate a stable bus with more than 1 other module. Currently, it's hard to guarantee that crow can support more than 1 module because the amount of capacitance added by different implementations of i2c is highly variable. By changing to stable-mode by default, i hope we can dramatically reduce the number of i2c-stability related questions / issues / support requests throughout the eco-system.

trentgill commented 2 years ago

@tehn indeed we should post a beta release. i've seen a number of issues with the new features (related to running out of RAM), so would love to push out a point release with a lot of the small fixes (but not the big new features).

i've been testing things with TT and seeing a lot of issues with i2c communication so i'm going to investigate that before merging these changes. haven't done regression testing yet to see if the issue is these changes or just general buggyness.