I am using Adafruit Feather M0 board (F_CPU = 48MHz) to communicate with a sensor using Wire I2C. The sensor limits the SCL clock frequency to maximum 20kHz but I can't get to that speed using the Wire.setClock() function. Any suggestions on how to overcome this issue?
Using a different board will not be possible at the moment since I am working with a custom PCB.
As long as you do not exceed the speed limit of the slowest unit it should work just great. You can test it with the I2C scanner and when that does not work add pull up resistors.
The lowest frequency that I could set using Wire.setClock() was 100 kHz. I was able to overcome the issue by using a clock divider! Now I can generate 10 kHz but I still cannot detect the sensor using I2C scanner. I have added pull-up resistors for both SDA and SCL.
Here's the schematic. I tried using both the default i2c SCL and SDA and also used SERCOM2. Same issue in both cases. I do not have any other devices on the i2c bus.
Hi, I am using I2C communication to read data from a sensor but I am not able to find the sensor at the specified address or any other address (used I2C Scanner to check). I am also only reading FF when I try to read the data bytes from the sensor. I have reached out to the manufacturer regarding the issue and they couldn't find anything wrong with my firmware. Here's part of my code!
#include <Arduino.h> // required before wiring_private.h
#include <Wire.h> // required for TwoWire
#define SENSOR_ADDRESS 0x7E // device address for sensor
#define CONC_REG_ADDRESS 0xD1 // register containing concentration raw value
byte data = 0; // stores current read byte
byte ph3_concDataArray[7] = {0}; // stores read data from the register with concentration value (0xD1)
uint8_t ph3_concIndex = 0; // index for concentration data array
uint8_t ph3_concChecksum = 0; // checksum for concentration value
float ph3_concentration = 0; // concentration value after using formula
bool ph3_concVerified = false; // indicates successful concentration read
bool read_done = false; // read status
bool ph3_done = false; // actual concentration status
void setup() {
GCLK->GENDIV.reg = GCLK_GENDIV_DIV(12) | // Divide the 48MHz clock source by divisor 12: 48MHz/12=4MHz
GCLK_GENDIV_ID(3); // Select Generic Clock (GCLK) 3
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK3
GCLK_GENCTRL_SRC_DFLL48M | // Set the 48MHz clock source
GCLK_GENCTRL_ID(3); // Select GCLK3
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
Serial.begin(9600);
while (!Serial) delay(10); // will pause until serial console opens
// SerialUSB.begin(115200); // Set-up the native USB port
// while(!SerialUSB); // Wait until the native USB port is ready
Wire.begin(); // Set-up the I2C port
sercom3.disableWIRE(); // Disable the I2C SERCOM
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable GCLK3 as clock soruce to SERCOM3
GCLK_CLKCTRL_GEN_GCLK3 | // Select GCLK3
GCLK_CLKCTRL_ID_SERCOM3_CORE; // Feed the GCLK3 to SERCOM3
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
SERCOM3->I2CM.BAUD.bit.BAUD = 4000000 / (2 * 20000) - 1; // Set the I2C clock rate to 10kHz
sercom3.enableWIRE();
}
void loop() {
ph3_done = false;
while (!ph3_done) {
// Read from register 0xD1 to get concentration -----------------------------------------------------------------------------
Wire.beginTransmission(SENSOR_ADDRESS);
Wire.write(CONC_REG_ADDRESS);
Wire.endTransmission();
// Time interval requirement for reading and writing data:> =1s
delay(1500);
// request 7 bytes of data from sensor
Wire.requestFrom(SENSOR_ADDRESS, 7);
// if data available then read 7 bytes of data
if (Wire.available() >= 0) {
ph3_concIndex = 0;
ph3_concChecksum = 0;
while (ph3_concIndex < 7) {
data = Wire.read();
Serial.print(data, HEX);
ph3_concDataArray[ph3_concIndex] = data;
// calculate checksum: add-8 sum of byte[0] to byte[5]
if (ph3_concIndex < 6) {
ph3_concChecksum += data;
}
ph3_concIndex++;
// Time interval requirement for reading and writing data: >=1s
delay(1500);
}
read_done = true;
}
// Checking for data integrity
if (read_done && (ph3_concChecksum == ph3_concDataArray[6])) {
ph3_concVerified = true;
ph3_done = true;
}
read_done = false;
}
}
I found the clock divider code from github and used it to generate 20kHz clock frequency since I couldn't set the frequency that low using Wire.setClock(). If there is something wrong with that part of the code then I don't know.
Your two or more topics on the same or similar subject have been merged.
Please do not duplicate your questions as doing so wastes the time and effort of the volunteers trying to help you as they are then answering the same thing in different places.
Please create one topic only for your question and choose the forum category carefully. If you have multiple questions about the same project then please ask your questions in the one topic as the answers to one question provide useful context for the others, and also you won’t have to keep explaining your project repeatedly.
Repeated duplicate posting could result in a temporary or permanent ban from the forum.
Could you take a few moments to Learn How To Use The Forum
It will help you get the best out of the forum in the future.
Do you have a Logic Analyzer to check what is going on ?
I think you need one to solve this.
There are cheap USB Logic Analyzers and the Raspberry Pi Pico can be used as a Logic Analyzer (but I have not tried that yet). I'm fond of the LHT00SU1 in combination with PulseView/sigrok.
PulseView has a decoder, and it is easier to scroll and see the signal on a big computer screen instead of staring at small oscilloscope screen without really knowing what is going on.
The picture from the oscilloscope does not tell much. Can you split the SDA and SCL and show more ?
A sensor in 2024 that needs a I2C clock of 20kHz is not normal. Such a low speed is either with very slow hardware or a processor that deals with I2C in software. It might not be compatible with a I2C Master that uses hardware for the I2C signals. Most hardware uses 100kHz as standard speed.
I checked the official I2C specification (UM10204.pdf) and the I2C speed is defined as 0kHz to 100kHz for the standard mode.
As suggested by jremington, a software I2C library is your best option. But you still need that Logic Analyzer.