1
0
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:
Kaspar Schleiser 2021-12-18 21:58:34 +01:00 committed by GitHub
commit 2c3e077bca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 47 deletions

View File

@ -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.

View File

@ -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 */

View File

@ -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",

View File

@ -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--;