mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-18 12:52:44 +01:00
cpu/esp32/i2c_hw: assert added for unsupported I2C clock speeds
The former correction factors were determined by measuring the resulting clocks without a device connected to the bus. However, when testing the changes for low CPU clock frequencies, it was figured out that the clocks not only depend on configured register values _i2c_hw[dev].regs->scl_low_period.period _i2c_hw[dev].regs->scl_high_period.period but also on the bus capacity. Obviously, the register values are not absolute times in APB clock cycles, but rather times that start as soon as the corresponding level is reached. In this case, the higher the bus capacity, the longer the period would be. This means that the clock speed cannot be precisely controlled via the correction factors anyway. For this reason, and because the I2C implementation in ESP-IDF also does not use correction factors, they were removed.
This commit is contained in:
parent
0b4fb5a9ea
commit
470208e685
@ -47,6 +47,7 @@
|
||||
#include "cpu.h"
|
||||
#include "log.h"
|
||||
#include "mutex.h"
|
||||
#include "macros/units.h"
|
||||
#include "periph_conf.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/i2c.h"
|
||||
@ -69,9 +70,6 @@
|
||||
|
||||
#if defined(I2C0_SPEED) || defined(I2C1_SPEED)
|
||||
|
||||
#undef I2C_CLK_FREQ
|
||||
#define I2C_CLK_FREQ rtc_clk_apb_freq_get() /* APB_CLK is used */
|
||||
|
||||
/* operation codes used for commands */
|
||||
#define I2C_CMD_RSTART 0
|
||||
#define I2C_CMD_WRITE 1
|
||||
@ -147,12 +145,9 @@ void i2c_init(i2c_t dev)
|
||||
{
|
||||
assert(dev < I2C_NUMOF);
|
||||
|
||||
if (i2c_config[dev].speed == I2C_SPEED_FAST_PLUS ||
|
||||
i2c_config[dev].speed == I2C_SPEED_HIGH) {
|
||||
LOG_TAG_INFO("i2c", "I2C_SPEED_FAST_PLUS and I2C_SPEED_HIGH "
|
||||
"are not supported\n");
|
||||
return;
|
||||
}
|
||||
/* According to the Technical Reference Manual, only FAST mode is supported,
|
||||
* but FAST PLUS mode seems to work also. */
|
||||
assert(i2c_config[dev].speed <= I2C_SPEED_FAST_PLUS);
|
||||
|
||||
mutex_init(&_i2c_bus[dev].lock);
|
||||
|
||||
@ -182,38 +177,64 @@ void i2c_init(i2c_t dev)
|
||||
|
||||
/* determine the half period of clock in APB clock cycles */
|
||||
uint32_t half_period = 0;
|
||||
uint32_t apb_clk = rtc_clk_apb_freq_get();
|
||||
|
||||
switch (_i2c_bus[dev].speed) {
|
||||
case I2C_SPEED_LOW:
|
||||
/* 10 kbps (period 100 us) */
|
||||
half_period = (I2C_CLK_FREQ / 10000) >> 1;
|
||||
break;
|
||||
if (apb_clk == MHZ(2)) {
|
||||
/* CPU clock frequency of 2 MHz requires special handling */
|
||||
switch (_i2c_bus[dev].speed) {
|
||||
case I2C_SPEED_LOW:
|
||||
/* 10 kbps (period 100 us) */
|
||||
half_period = 95;
|
||||
break;
|
||||
|
||||
case I2C_SPEED_NORMAL:
|
||||
/* 100 kbps (period 10 us) */
|
||||
half_period = (I2C_CLK_FREQ / 100000) >> 1;
|
||||
half_period = half_period * 95 / 100; /* correction factor */
|
||||
break;
|
||||
case I2C_SPEED_NORMAL:
|
||||
/* 100 kbps (period 10 us) */
|
||||
/* NOTE: Correct value for half_period would be 6 to produce a
|
||||
* 100 kHz clock. However, a value of at least 18 is
|
||||
* necessary to work correctly which corresponds to a
|
||||
* I2C clock speed of 30 kHz.
|
||||
*/
|
||||
half_period = 18;
|
||||
break;
|
||||
|
||||
case I2C_SPEED_FAST:
|
||||
/* 400 kbps (period 2.5 us) */
|
||||
half_period = (I2C_CLK_FREQ / 400000) >> 1;
|
||||
half_period = half_period * 82 / 100; /* correction factor */
|
||||
break;
|
||||
default:
|
||||
LOG_TAG_ERROR("i2c", "I2C clock speed not supported in "
|
||||
"hardware with CPU clock 2 MHz, use the "
|
||||
"software implementation instead\n");
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (_i2c_bus[dev].speed) {
|
||||
case I2C_SPEED_LOW:
|
||||
/* 10 kbps (period 100 us) */
|
||||
half_period = (apb_clk / 10000) >> 1;
|
||||
break;
|
||||
|
||||
case I2C_SPEED_FAST_PLUS:
|
||||
/* 1 Mbps (period 1 us) not working */
|
||||
half_period = (I2C_CLK_FREQ / 1000000) >> 1;
|
||||
break;
|
||||
case I2C_SPEED_NORMAL:
|
||||
/* 100 kbps (period 10 us) */
|
||||
half_period = (apb_clk / 100000) >> 1;
|
||||
break;
|
||||
|
||||
case I2C_SPEED_HIGH:
|
||||
/* 3.4 Mbps (period 0.3 us) not working */
|
||||
half_period = (I2C_CLK_FREQ / 3400000) >> 1;
|
||||
break;
|
||||
case I2C_SPEED_FAST:
|
||||
/* 400 kbps (period 2.5 us) */
|
||||
half_period = (apb_clk / 400000) >> 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_TAG_ERROR("i2c", "Invalid speed value in %s\n", __func__);
|
||||
return;
|
||||
case I2C_SPEED_FAST_PLUS:
|
||||
/* 1 Mbps (period 1 us) */
|
||||
half_period = (apb_clk / 1000000) >> 1;
|
||||
break;
|
||||
|
||||
case I2C_SPEED_HIGH:
|
||||
/* 3.4 Mbps (period 0.3 us) not working */
|
||||
half_period = (apb_clk / 3400000) >> 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_TAG_ERROR("i2c", "Invalid speed value in %s\n", __func__);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* set an timeout which is at least 16 times of half cycle */
|
||||
|
Loading…
Reference in New Issue
Block a user