-
Notifications
You must be signed in to change notification settings - Fork 13.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue2524 allow clocks below 100KHz #6934
Conversation
…nused slave STOP function
…nused slave STOP function
…nused slave STOP function
BTW, here's a variation on the Master_Writer example so you can knob the bus clock from the serial terminal. Enter your desired speed followed by enter, and it changes the Wire.setClock(freq) immediately. It also displays the half-cycle period and how many loops busywait() will execute. #include <Wire.h>
#include <ESP8266WiFi.h>
#include <PolledTimeout.h>
#define SDA_PIN 4
#define SCL_PIN 5
const int16_t I2C_MASTER = 0x42;
const int16_t I2C_SLAVE = 0x08;
String i2c_clock = ""; // stores the frequency request
void setup() {
Serial.begin(74880); // start serial for output
Serial.println();
Serial.println("Starting...");
Wire.begin(SDA_PIN, SCL_PIN, I2C_MASTER); // join i2c bus (address optional for master)
Wire.setClock(100000L);
WiFi.persistent(false);
WiFi.mode(WIFI_OFF);
delay(100);
WiFi.forceSleepBegin();
yield();
}
byte x = 0;
void loop() {
using periodic = esp8266::polledTimeout::periodicMs;
static periodic nextPing(100);
if (nextPing) {
Wire.beginTransmission(I2C_SLAVE); // transmit to device #8
Wire.write("x is "); // sends five bytes
Wire.write(x); // sends one byte
Wire.endTransmission(); // stop transmitting
// Serial.println (x);
x++;
}
if (Serial.available()) {
i2c_clock = Serial.readStringUntil('\n'); // enter the I2C bus speed in the serial monitor
Serial.print("bus clock = ");
Serial.println(i2c_clock);
unsigned int freq = (i2c_clock.toInt());
unsigned int period_nS = (500000000/freq); // half-cycle period in ns
Serial.print("period = ");
Serial.print(period_nS);
Serial.println("ns");
#if F_CPU == FCPU80
unsigned int twi_dcount = (1000*(period_nS - 1120)) / 62500; // (half cycle period - overhead) / busywait loop time
#else
unsigned int twi_dcount = (1000*(period_nS - 560)) / 31250; // (half cycle period - overhead) / busywait loop time
#endif
Serial.print("busywait = ");
Serial.print(twi_dcount);
Serial.println(" loops");
Serial.println();
Wire.setClock(freq);
}
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@devyte - [review integer ranges for overflow, minor constness ]
edit: divide by zero if they feed it 0Hz, uint32_t overflow below 233Hz
edit2: there's no overflow, my test program above was mixing ints and unsigned ints (corrected). The real code was correct. I knew I'd checked my math twice to insure I stayed within an unsigned int!
Might want to limit the lower end even further, as a single byte read or write is ~78ms at 250Hz.
(start, 7 bits address, read/write, ack, 8 bits data, ack, stop). Maybe somewhere around 500Hz to 1KHz would be a better lower limit. I don't expect any more than a few people trying to run it lower than 10KHz, normally. There were some radio PLLs that needed ~ 10KHz bus clock back in the '80s, but that's ancient history.
I think a 1KHz lower limit is ok, I somehow can't picture I2C at such a low clock speed lol. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work here. Only minor changes before merge.
Corrects the fixed I2C bus clock selections and allows slower bus clocks down to ridiculously low bus speeds if you need that. Originally prompted by Earle's comment in #2524 about computing the bus clock timing.
Additionally, the dead Twi::stop was removed. The compiler was removing it in slave compiles anyways, as it wasn't called by any of the functions except for one oversight in the slave state machine. Slaves can't issue STOP commands. Although the Twi::stop was listed as an exposed function, it wasn't linked from Wire.h, so it was optimized out.