No it is the correct order. If I request 2.8M rate, and I am using a 60M bus, it would require a divider of 21.43 (as an integer calc it is a divide ratio of 21). However there is no divide ratio of 21, there is only 20 or 22. The algorithm errs on the lower ratio (higher freq) side as the throughput rate is severely limited at the high end (this could be done either way, either rounding up or down). So in this case it would choose 20, yielding a 3M setting. So requesting 2.8M in this case will yield a 3M rate.
That's all theoretical rates. On a logic analyzer the rates run a little slow IIRC due to overhead. And in a throughput sense it is much lower, especially at the high end. At high freq the throughput becomes dominated by the "gaps" between bytes, which are caused by peripheral and ISR processing latency (I2C traffic does not have an unbroken clock, there is usually a turnaround delay after the ACK cycle) . I don't have any logic analyzer plots yet to pair up against the settings.
From that description, I would say that the code is wrong and should be corrected/changed.
setClock() should set the raw i2c SCL clock rate on the bus.
All the specs in datasheeets for i2c bit rates are based on a maximum SCL clock bit rate not a desired/theoretical/measured actual data rate of user data transfers.
The data rate that the users application code "sees" is not what what is most important as there are several sources of overhead in i2c, some of which cannot be anticipated.
i..e start/stop signals, library overhead, and the slave can even do clock stretching to literally stop the clock or slow it down to any rate it wants.
For example, when an i2c slave device says it supports a 400000 clock, that means it can support a SCL clock rate of up to 400000, and so the Wire s/w needs to guarantee that the SCL clock rate does not ever exceed the requested SCL bit rate.
i.e. if the users application asks for a SCL bit rate of 400000, the master should never exceed 400000 hz on the SCL clock.
From the description of the way the code is currently working, a requested SCL bit rate can be exceeded, so the slave can end up being pushed beyond its specs, particularly when the sketch is asking to set the SCL clock rate to the slaves maximum clock rate and the s/w rounds to using the next higher clock available.
While it is likely that many slaves can be clocked at a rate beyond their specs, I think it is not a good practice to knowingly and intentionally do so.
Yeah, not being able to support a requested value does suck; however, whenever doing things like delays or clocks, the code should always error on the conservative side to ensure functional limits are not ever exceeded.
And that means when faced with having to use a something that is different than what was asked for, the code must always select using the more conservative choice.
So for delays and clock rates, it means using longer delays, or slower clocks.
It can't go the other way around as then the application never knows what to ask for that guarantees that the result is not exceeding a critical maximum rate or minimum delay.
My openGLCD library has to deal with same kind of issue as well.
There are places where small delays are needed to meet certain timing requirements.
There are certain environments, where the code may need a 140ns delay, but it isn't possible, so the code is forced to use delays that are longer, in some cases MUCH longer like 1us or even longer.
The longer needed delays means that performance takes a hit,
but that is the way it needs to work, so that the code always "just works" with no surprises or flakiness in any environment.
If doing it the other way, there are environments, where things stop working correctly, or get very flaky.
As a general rule,
I think code should first "just work" in all environments, then after that it is achieved, it can choose to optimize performance when possible.
So my very strong suggestion, is to make sure that the Wire code always selects a SCL clock rate that is the highest rate possible that never exceeds the requested rate.
Anything else, will eventually come back around with subtle issues/errors that can potentially be difficult to track down as they may only show up in very specific environments.
BTW, a logic analyzer is the only way to verify this kind of low level timing since it is the low level bit clock timing that matters.
For this measurement, a slave is not needed - and in fact should not be used, to ensure that no slave clock stretching is done during the measurements.
--- bill
Last edited: