cpu/esp32: allow explicit ESP32 crystal freq configuration

Some ESP32 boards (like my SparkFun ESP32 Thing) have a main clock
crystal that runs at 26MHz, not 40MHz. RIOT appears to assume 40MHz.
The mismatch causes the UART to not sync properly, resulting in
garbage written to the terminal instead of log output.

I’ve added:

* A new board configuration constant ESP32_XTAL_FREQ that defaults
  to 40, but can be overridden by a board def or at build time to
  force a specific value (i.e. 26).
* Some code spliced into system_clk_init() to check this constant and
  call rtc_clk_init() to set the correct frequency.
* A copy of the rtf_clk_init() function from the ESP-IDF sources.

Fixes #10272
This commit is contained in:
Jens Alfke 2018-10-26 12:17:42 -07:00
parent f139dfdad2
commit ce1fe776cf
4 changed files with 80 additions and 0 deletions

View File

@ -36,6 +36,23 @@
extern "C" {
#endif
/**
* @name External clock crystal frequency (MHz)
*
* Most boards use a 40MHz crystal, including all those based on Espressif's
* WROOM-32 and WROVER-32 modules. Those that don't, like the SparkFun ESP32
* Thing (26MHz), must define ESP32_XTAL_FREQ appropriately in their board
* configuration.
*
* An obvious side effect of a mismatch is that the UART won't sync and the
* development terminal will show garbage instead of log output.
* @{
*/
#ifndef ESP32_XTAL_FREQ
#define ESP32_XTAL_FREQ (40)
#endif
/** @} */
/**
* @name LED configuration (three predefined LEDs at maximum)
*

View File

@ -66,6 +66,16 @@ extern "C" {
#define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 80
#endif
/**
* ESP32 specific configuration
*
* Main clock crystal frequency (MHz). Zero means to auto-configure.
* This is configured at the board level, defaulting to 40.
*/
#ifndef CONFIG_ESP32_XTAL_FREQ
#define CONFIG_ESP32_XTAL_FREQ ESP32_XTAL_FREQ
#endif
#define CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES 100
#define CONFIG_ESP32_RTC_CLK_CAL_CYCLES 1024

View File

@ -14,6 +14,7 @@
* @brief Implementation of the CPU initialization
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @author Jens Alfke <jens@mooseyard.com>
* @}
*/
@ -88,6 +89,7 @@ extern void esp_panic_wdt_stop (void);
extern void spi_ram_init(void);
extern void spi_ram_heap_init(void);
extern uint32_t hwrand (void);
extern void bootloader_clock_configure(void);
/* forward declarations */
static void system_init(void);
@ -194,6 +196,12 @@ static void IRAM system_clk_init (void)
rtc_config_t rtc_cfg = RTC_CONFIG_DEFAULT();
rtc_init_module(rtc_cfg);
/* configure main crystal frequency if necessary */
if (CONFIG_ESP32_XTAL_FREQ != RTC_XTAL_FREQ_AUTO
&& CONFIG_ESP32_XTAL_FREQ != rtc_clk_xtal_freq_get()) {
bootloader_clock_configure();
}
/* set FAST_CLK to internal low power clock of 8 MHz */
rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M);

View File

@ -545,3 +545,48 @@ void sc_ack_send_stop(void)
NOT_SUPPORTED();
}
#endif
/*
* source: /path/to/esp-idf/components/bootloader_support/src/bootloader_clock.c
*/
void bootloader_clock_configure(void)
{
// ROM bootloader may have put a lot of text into UART0 FIFO.
// Wait for it to be printed.
// This is not needed on power on reset, when ROM bootloader is running at
// 40 MHz. But in case of TG WDT reset, CPU may still be running at >80 MHZ,
// and will be done with the bootloader much earlier than UART FIFO is empty.
uart_tx_wait_idle(0);
/* Set CPU to 80MHz. Keep other clocks unmodified. */
rtc_cpu_freq_t cpu_freq = RTC_CPU_FREQ_80M;
#ifndef RIOT_VERSION
/* On ESP32 rev 0, switching to 80MHz if clock was previously set to
* 240 MHz may cause the chip to lock up (see section 3.5 of the errata
* document). For rev. 0, switch to 240 instead if it was chosen in
* menuconfig.
*/
uint32_t chip_ver_reg = REG_READ(EFUSE_BLK0_RDATA3_REG);
if ((chip_ver_reg & EFUSE_RD_CHIP_VER_REV1_M) == 0 &&
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ == 240) {
cpu_freq = RTC_CPU_FREQ_240M;
}
#endif
rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
clk_cfg.cpu_freq = cpu_freq;
clk_cfg.slow_freq = rtc_clk_slow_freq_get();
clk_cfg.fast_freq = rtc_clk_fast_freq_get();
rtc_clk_init(clk_cfg);
/* As a slight optimization, if 32k XTAL was enabled in sdkconfig, we enable
* it here. Usually it needs some time to start up, so we amortize at least
* part of the start up time by enabling 32k XTAL early.
* App startup code will wait until the oscillator has started up.
*/
#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
if (!rtc_clk_32k_enabled()) {
rtc_clk_32k_bootstrap(CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES);
}
#endif
}