Merge pull request #14226 from benpicco/cpu/sam0_common/i2c_arbitrary_freqs
cpu/sam0_common: i2c: fix BAUD handling & cleanup
This commit is contained in:
commit
d7dbbb71ac
@ -402,6 +402,15 @@ typedef enum {
|
||||
|
||||
/**
|
||||
* @brief I2C device configuration
|
||||
* The frequency f() of the clock `gclk_src` must fulfill the condition
|
||||
*
|
||||
* 4 * speed ≤ f(gclk_src) ≤ 512 * speed
|
||||
*
|
||||
* if speed ≤ 1 MHz and
|
||||
*
|
||||
* 12 * speed ≤ f(gclk_src) ≤ 520 * speed
|
||||
*
|
||||
* if speed > 1 MHz
|
||||
*/
|
||||
typedef struct {
|
||||
SercomI2cm *dev; /**< pointer to the used I2C device */
|
||||
|
||||
@ -80,6 +80,9 @@ void i2c_init(i2c_t dev)
|
||||
|
||||
assert(dev < I2C_NUMOF);
|
||||
|
||||
const uint32_t fSCL = i2c_config[dev].speed;
|
||||
const uint32_t fGCLK = sam0_gclk_freq(i2c_config[dev].gclk_src);
|
||||
|
||||
/* Initialize mutex */
|
||||
mutex_init(&locks[dev]);
|
||||
/* DISABLE I2C MASTER */
|
||||
@ -122,30 +125,31 @@ void i2c_init(i2c_t dev)
|
||||
/* Enable Smart Mode (ACK is sent when DATA.DATA is read) */
|
||||
bus(dev)->CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN;
|
||||
|
||||
/* Find and set baudrate. Read speed configuration. Set transfer
|
||||
* speed: SERCOM_I2CM_CTRLA_SPEED(0): Standard-mode (Sm) up to 100
|
||||
* kHz and Fast-mode (Fm) up to 400 kHz */
|
||||
switch (i2c_config[dev].speed) {
|
||||
case I2C_SPEED_NORMAL:
|
||||
case I2C_SPEED_FAST:
|
||||
bus(dev)->CTRLA.reg |= SERCOM_I2CM_CTRLA_SPEED(0);
|
||||
break;
|
||||
case I2C_SPEED_HIGH:
|
||||
/* Set SPEED */
|
||||
if (fSCL > I2C_SPEED_FAST_PLUS) {
|
||||
bus(dev)->CTRLA.reg |= SERCOM_I2CM_CTRLA_SPEED(2);
|
||||
break;
|
||||
default:
|
||||
DEBUG("BAD BAUDRATE\n");
|
||||
return;
|
||||
} else if (fSCL > I2C_SPEED_FAST) {
|
||||
bus(dev)->CTRLA.reg |= SERCOM_I2CM_CTRLA_SPEED(1);
|
||||
} else {
|
||||
bus(dev)->CTRLA.reg |= SERCOM_I2CM_CTRLA_SPEED(0);
|
||||
}
|
||||
|
||||
/* Get the baudrate */
|
||||
tmp_baud = (int32_t)(((sam0_gclk_freq(i2c_config[dev].gclk_src) +
|
||||
(2 * (i2c_config[dev].speed)) - 1) /
|
||||
(2 * (i2c_config[dev].speed))) -
|
||||
(i2c_config[dev].speed == I2C_SPEED_HIGH ? 1 : 5));
|
||||
/* fSCL = fGCLK / (10 + 2 * BAUD) -> BAUD = fGCLK / (2 * fSCL) - 5 */
|
||||
/* fSCL = fGCLK / (2 + 2 * HSBAUD) -> HSBAUD = fGCLK / (2 * fSCL) - 1 */
|
||||
tmp_baud = (fGCLK + (2 * fSCL) - 1) /* round up */
|
||||
/ (2 * fSCL)
|
||||
- (fSCL > I2C_SPEED_FAST_PLUS ? 1 : 5);
|
||||
|
||||
/* Ensure baudrate is within limits */
|
||||
if (tmp_baud < 255 && tmp_baud > 0) {
|
||||
assert(tmp_baud < 255 && tmp_baud > 0);
|
||||
|
||||
if (fSCL > I2C_SPEED_FAST_PLUS) {
|
||||
bus(dev)->BAUD.reg = SERCOM_I2CM_BAUD_HSBAUD(tmp_baud);
|
||||
} else {
|
||||
bus(dev)->BAUD.reg = SERCOM_I2CM_BAUD_BAUD(tmp_baud);
|
||||
}
|
||||
|
||||
/* ENABLE I2C MASTER */
|
||||
_i2c_poweron(dev);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user