Skip to content

[Silicon Labs] Allow faster I2C baudrates #1505

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

Merged
merged 3 commits into from
Jan 15, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl)
I2CName i2c_scl = (I2CName) pinmap_peripheral(scl, PinMap_I2C_SCL);
obj->i2c.i2c = (I2C_TypeDef*) pinmap_merge(i2c_sda, i2c_scl);
MBED_ASSERT(((int) obj->i2c.i2c) != NC);

/* You need both SDA and SCL for I2C, so configuring one of them to NC is illegal */
MBED_ASSERT((uint32_t)sda != (uint32_t)NC);
MBED_ASSERT((uint32_t)scl != (uint32_t)NC);

/* Enable clock for the peripheral */
CMU_ClockEnable(i2c_get_clock(obj), true);
Expand All @@ -132,6 +136,8 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl)
#endif

/* Set up the pins for I2C use */
/* Note: Set up pins in higher drive strength to reduce slew rate */
/* Though this requires user knowledge, since drive strength is controlled per port, not pin */
pin_mode(scl, WiredAndPullUp);
pin_mode(sda, WiredAndPullUp);

Expand Down Expand Up @@ -192,7 +198,23 @@ void i2c_frequency(i2c_t *obj, int hz)
{
/* Set frequency. As the second argument is 0,
* HFPER clock frequency is used as reference freq */
I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, hz, i2cClockHLRStandard);
if (hz <= 0) return;
/* In I2C Normal mode (50% duty), we can go up to 100kHz */
if (hz <= 100000) {
I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, hz, i2cClockHLRStandard);
}
/* In I2C Fast mode (6:3 ratio), we can go up to 400kHz */
else if (hz <= 400000) {
I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, hz, i2cClockHLRAsymetric);
}
/* In I2C Fast+ mode (11:6 ratio), we can go up to 1 MHz */
else if (hz <= 1000000) {
I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, hz, i2cClockHLRFast);
}
/* Cap requested frequency at 1MHz */
else {
I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, 1000000, i2cClockHLRFast);
}
}

/* Creates a start condition on the I2C bus */
Expand Down Expand Up @@ -352,11 +374,15 @@ int block_and_wait_for_ack(I2C_TypeDef *i2c)
void i2c_slave_mode(i2c_t *obj, int enable_slave)
{
if(enable_slave) {
/* Reference manual note: DIV must be set to 1 during slave operation */
obj->i2c.i2c->CLKDIV = 1;
obj->i2c.i2c->CTRL |= _I2C_CTRL_SLAVE_MASK;
obj->i2c.i2c->CTRL |= _I2C_CTRL_AUTOACK_MASK; //Slave implementation assumes auto acking
} else {
obj->i2c.i2c->CTRL &= ~_I2C_CTRL_SLAVE_MASK;
obj->i2c.i2c->CTRL &= ~_I2C_CTRL_AUTOACK_MASK; //Master implementation ACKs manually
/* function is only called with enable_slave = false through i2c_init(..), so frequency is
already guaranteed to be set */
}
}

Expand Down