Skip to content

Commit fa45092

Browse files
committed
Merge pull request #1505 from stevew817/feature/new/fast_i2c
[Silicon Labs] Allow faster I2C baudrates
2 parents 170003c + 22c246c commit fa45092

File tree

1 file changed

+27
-1
lines changed
  • libraries/mbed/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32

1 file changed

+27
-1
lines changed

libraries/mbed/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/i2c_api.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl)
107107
I2CName i2c_scl = (I2CName) pinmap_peripheral(scl, PinMap_I2C_SCL);
108108
obj->i2c.i2c = (I2C_TypeDef*) pinmap_merge(i2c_sda, i2c_scl);
109109
MBED_ASSERT(((int) obj->i2c.i2c) != NC);
110+
111+
/* You need both SDA and SCL for I2C, so configuring one of them to NC is illegal */
112+
MBED_ASSERT((uint32_t)sda != (uint32_t)NC);
113+
MBED_ASSERT((uint32_t)scl != (uint32_t)NC);
110114

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

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

@@ -192,7 +198,23 @@ void i2c_frequency(i2c_t *obj, int hz)
192198
{
193199
/* Set frequency. As the second argument is 0,
194200
* HFPER clock frequency is used as reference freq */
195-
I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, hz, i2cClockHLRStandard);
201+
if (hz <= 0) return;
202+
/* In I2C Normal mode (50% duty), we can go up to 100kHz */
203+
if (hz <= 100000) {
204+
I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, hz, i2cClockHLRStandard);
205+
}
206+
/* In I2C Fast mode (6:3 ratio), we can go up to 400kHz */
207+
else if (hz <= 400000) {
208+
I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, hz, i2cClockHLRAsymetric);
209+
}
210+
/* In I2C Fast+ mode (11:6 ratio), we can go up to 1 MHz */
211+
else if (hz <= 1000000) {
212+
I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, hz, i2cClockHLRFast);
213+
}
214+
/* Cap requested frequency at 1MHz */
215+
else {
216+
I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, 1000000, i2cClockHLRFast);
217+
}
196218
}
197219

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

0 commit comments

Comments
 (0)