-
-
Notifications
You must be signed in to change notification settings - Fork 725
Incorrect I2C SCL frequency #259
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
Comments
do you have also checked if other frequencys are ok? (e.g. 1MHz? ) |
The SAMD21 datasheet states that for standard I2C fast mode plus at 1MHz, "requires a nominal high to low SCL ratio 1:2". This involves setting the BAUDLOW bitfield in the BAUD register. In this case the SCL frequency is determined by the formula: SCL_Frequency = SystemCoreClock (48MHz) / (10 + BAUDLOW + BAUD + (SystemCoreClock (48Mhz) * T(rise))) As it currently stands the Wire library doesn't take this into account. |
@Adminius |
Fixed via #287. |
I have a similar problem with my MKRzero board. Does somebody know a different way to set a I2C clock? |
The issue is that the I2C's BAUD register is only 8-bits wide and can therefore only store values between 0 and 255. As this BAUD value is used to divide the 48MHz system clock as described in the formula above, it's not possible to get low I2C frequencies using the Wire.setClock() function. The only way to get a lower frequency is to clock the I2C SERCOM (Serial Communications) module with a slower generic clock (GCLK), instead of the default 48MHz on GCLK0. This involves setting up a slower GCLK and attaching it as the clock source of I2C SERCOM. A slower GCLK however will cause the whole SERCOM module, including registers access and synchronization to run slower. |
Hi patryk02, Here's some code that'll run the I2C at 10kHz:
On the MKRZero just change the "sercom3" and "SERCOM3" references to "sercom0" and "SERCOM0". I tested the code on my Arduino Zero. |
Hi,
I want to thank you for the response and for the example.
BR
Patryk
…On Thu, Sep 6, 2018 at 5:31 PM MartinL1 ***@***.***> wrote:
Hi patryk02,
Here's some code that'll run the I2C at 10kHz:
// Sketch to run the I2C at 10kHz
#include <Wire.h>
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
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 * 10000) - 1; // Set the I2C clock rate to 10kHz
sercom3.enableWIRE(); // Enable the I2C SERCOM
}
void loop()
{
Wire.beginTransmission(0x68); // Send command to MPU6050
Wire.write(0x75); // Set sub address to the WHO_AM_I register
Wire.endTransmission(false); // Transfer request
Wire.requestFrom(0x68, 1); // Read the WHO_AM_I register
SerialUSB.println(Wire.read(), HEX); // Send the result to the console
delay(1000); // Wait 1 second
}
On the MKRZero just change the "sercom3" and "SERCOM3" references to
"sercom0" and "SERCOM0". I tested the code on my Arduino Zero.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#259 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AMzbVB_IFmjJrGcn8tjOzKZ2VPoq1SuBks5uYT_qgaJpZM4PLnTJ>
.
|
Matrix portal draft
Hi @martinl1 |
I observed that the I2C SCL clock in fast mode (400kHz) is only running at 357kHz, despite using 2k2 pull-up resistors that provide a relatively fast rise time.
After some investigation it turns out that the SERCOM::InitMasterWire() function (in the file SERCOM.cpp) is using the incorrect formula for the BAUD register.
The current fomula appears to be taken from Section 25 SERCOM - Serial Communication Interface in the SAMD21 datasheet:
BAUD = SystemCoreClock (48MHz) / (2 * baud rate) - 1
...however, the correct formula should be the one from Section 28 SERCOM - Inter-Integrated Circuit:
BAUD = SystemCoreClock (48MHz) / (2 * SCL_Frequency) - 5 - (SystemCoreClock (48MHz) * T(rise) / 2)
...where T(rise) is the time taken for the pull-up resistor to pull the SCL line high, (and will very much depend on the resistor values used).
Using 2k2 pull-up resistors I measured the rise time as 90ns, therefore the BAUD value in this instance should be:
BAUD = 48MHz / (2 * 400000) - 5 - (48MHz * 90ns / 2) = 52.84
Using a BAUD value around 52 or 53 gives a SCL frequency close to 400kHz.
The text was updated successfully, but these errors were encountered: