mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #17413 from gschorcht/cpu/esp32/support_clocks_2_and_40_MHz
cpu/esp32: support CPU clocks 2 MHz and 40 MHz
This commit is contained in:
commit
2c3e077bca
@ -851,7 +851,7 @@ Beside the I2C hardware implementation, a I2C bit-banging protocol software impl
|
||||
used. This implementation allows bus speeds up to 1 Mbps (`I2C_SPEED_FAST_PLUS`). It can be
|
||||
activated by adding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
USEMODULE += esp_i2c_hw
|
||||
USEMODULE += esp_i2c_sw
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
to application's makefile. The Disadvantage of the software implementation is that it uses busy
|
||||
waiting.
|
||||
|
@ -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 */
|
||||
|
@ -105,18 +105,23 @@ static _i2c_bus_t _i2c_bus[I2C_NUMOF] = {};
|
||||
#pragma GCC optimize ("O2")
|
||||
|
||||
#ifdef MCU_ESP32
|
||||
static const uint32_t _i2c_delays[][3] =
|
||||
static const uint32_t _i2c_delays[][5] =
|
||||
{
|
||||
/* values specify one half-period and are only valid for -O2 option */
|
||||
/* value = [period - 0.25 us (240 MHz) / 0.5us(160MHz) / 1.0us(80MHz)] */
|
||||
/* * cycles per second / 2 */
|
||||
/* 1 us = 16 cycles (80 MHz) / 32 cycles (160 MHz) / 48 cycles (240) */
|
||||
/* values for 80, 160, 240 MHz */
|
||||
[I2C_SPEED_LOW] = {790, 1590, 2390}, /* 10 kbps (period 100 us) */
|
||||
[I2C_SPEED_NORMAL] = { 70, 150, 230}, /* 100 kbps (period 10 us) */
|
||||
[I2C_SPEED_FAST] = { 11, 31, 51}, /* 400 kbps (period 2.5 us) */
|
||||
[I2C_SPEED_FAST_PLUS] = { 0, 7, 15}, /* 1 Mbps (period 1 us) */
|
||||
[I2C_SPEED_HIGH] = { 0, 0, 0} /* 3.4 Mbps (period 0.3 us) not working */
|
||||
/* max clock speeds 2 MHz CPU clock: 19 kHz */
|
||||
/* 40 MHz CPU clock: 308 kHz */
|
||||
/* 80 MHz CPU clock: 516 kHz */
|
||||
/* 160 MHz CPU clock: 727 kHz */
|
||||
/* 240 MHz CPU clock: 784 kHz */
|
||||
/* values for 80, 160, 240, 2, 40 MHz */
|
||||
[I2C_SPEED_LOW] = {790, 1590, 2390, 10, 390 }, /* 10 kbps (period 100 us) */
|
||||
[I2C_SPEED_NORMAL] = { 70, 150, 230, 0, 30 }, /* 100 kbps (period 10 us) */
|
||||
[I2C_SPEED_FAST] = { 11, 31, 51, 0, 0 }, /* 400 kbps (period 2.5 us) */
|
||||
[I2C_SPEED_FAST_PLUS] = { 0, 0, 0, 0, 0 }, /* 1 Mbps (period 1 us) */
|
||||
[I2C_SPEED_HIGH] = { 0, 0, 0, 0, 0 } /* 3.4 Mbps (period 0.3 us) not working */
|
||||
};
|
||||
#else /* MCU_ESP32 */
|
||||
static const uint32_t _i2c_delays[][2] =
|
||||
@ -158,10 +163,8 @@ void i2c_init(i2c_t dev)
|
||||
assert(dev < I2C_NUMOF_MAX);
|
||||
assert(dev < I2C_NUMOF);
|
||||
|
||||
if (i2c_config[dev].speed == I2C_SPEED_HIGH) {
|
||||
LOG_TAG_INFO("i2c", "I2C_SPEED_HIGH is not supported\n");
|
||||
return;
|
||||
}
|
||||
/* clock speeds up to 1 MHz are supported */
|
||||
assert(i2c_config[dev].speed <= I2C_SPEED_FAST_PLUS);
|
||||
|
||||
mutex_init(&_i2c_bus[dev].lock);
|
||||
|
||||
@ -179,6 +182,8 @@ void i2c_init(i2c_t dev)
|
||||
case 160: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][1]; break;
|
||||
#ifdef MCU_ESP32
|
||||
case 240: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][2]; break;
|
||||
case 2: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][3]; break;
|
||||
case 40: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][4]; break;
|
||||
#endif
|
||||
default : LOG_TAG_INFO("i2c", "I2C software implementation is not "
|
||||
"supported for this CPU frequency: %d MHz\n",
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "cpu.h"
|
||||
#include "mutex.h"
|
||||
#include "periph/spi.h"
|
||||
#include "macros/units.h"
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "gpio_arch.h"
|
||||
@ -43,6 +44,7 @@
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_struct.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/spi_struct.h"
|
||||
|
||||
@ -333,6 +335,23 @@ void IRAM_ATTR spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t cl
|
||||
uint32_t spi_clkdiv_pre;
|
||||
uint32_t spi_clkcnt_N;
|
||||
|
||||
#ifdef MCU_ESP32
|
||||
uint32_t apb_clk = rtc_clk_apb_freq_get();
|
||||
spi_clkcnt_N = 2;
|
||||
switch (clk) {
|
||||
case SPI_CLK_10MHZ: spi_clkdiv_pre = apb_clk / MHZ(10) / 2;
|
||||
break;
|
||||
case SPI_CLK_5MHZ: spi_clkdiv_pre = apb_clk / MHZ(5) / 2;
|
||||
break;
|
||||
case SPI_CLK_1MHZ: spi_clkdiv_pre = apb_clk / MHZ(1) / 2;
|
||||
break;
|
||||
case SPI_CLK_400KHZ: spi_clkdiv_pre = apb_clk / KHZ(400) / 2;
|
||||
break;
|
||||
case SPI_CLK_100KHZ: /* fallthrough intentionally */
|
||||
default: spi_clkdiv_pre = apb_clk / KHZ(100) / 2;
|
||||
}
|
||||
assert(spi_clkdiv_pre > 0);
|
||||
#else
|
||||
switch (clk) {
|
||||
case SPI_CLK_10MHZ: spi_clkdiv_pre = 2; /* predivides 80 MHz to 40 MHz */
|
||||
spi_clkcnt_N = 4; /* 4 cycles results into 10 MHz */
|
||||
@ -352,6 +371,7 @@ void IRAM_ATTR spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t cl
|
||||
default: spi_clkdiv_pre = 20; /* predivides 80 MHz to 4 MHz */
|
||||
spi_clkcnt_N = 40; /* 20 cycles results into 100 kHz */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* register values are set to deviders-1 */
|
||||
spi_clkdiv_pre--;
|
||||
|
Loading…
Reference in New Issue
Block a user