diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index 8dd163fe33..c3ddf0e10a 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -23,6 +23,8 @@ #include "rom/spi_flash.h" #include "rom/crc.h" #include "rom/rtc.h" +#include "rom/uart.h" +#include "rom/gpio.h" #include "soc/soc.h" #include "soc/cpu.h" @@ -31,6 +33,8 @@ #include "soc/efuse_reg.h" #include "soc/rtc_cntl_reg.h" #include "soc/timer_group_reg.h" +#include "soc/gpio_reg.h" +#include "soc/gpio_sig_map.h" #include "sdkconfig.h" #include "esp_image_format.h" @@ -62,7 +66,7 @@ void set_cache_and_start_app(uint32_t drom_addr, uint32_t irom_size, uint32_t entry_addr); static void update_flash_config(const esp_image_header_t* pfhdr); - +static void uart_console_configure(void); void IRAM_ATTR call_start_cpu0() { @@ -224,6 +228,7 @@ static bool ota_select_valid(const esp_ota_select_entry_t *s) void bootloader_main() { + uart_console_configure(); ESP_LOGI(TAG, "Espressif ESP32 2nd stage bootloader v. %s", BOOT_VERSION); esp_image_header_t fhdr; @@ -616,3 +621,63 @@ void print_flash_info(const esp_image_header_t* phdr) ESP_LOGI(TAG, "SPI Flash Size : %s", str ); #endif } + +static uint32_t get_apb_freq(void) +{ + // Get the value of APB clock from RTC memory. + // The value is initialized in ROM code, and updated by librtc.a + // when APB clock is changed. + // This value is stored in RTC_CNTL_STORE5_REG as follows: + // RTC_CNTL_STORE5_REG = (freq >> 12) | ((freq >> 12) << 16) + uint32_t apb_freq_reg = REG_READ(RTC_CNTL_STORE5_REG); + uint32_t apb_freq_l = apb_freq_reg & 0xffff; + uint32_t apb_freq_h = apb_freq_reg >> 16; + if (apb_freq_l == apb_freq_h && apb_freq_l != 0) { + return apb_freq_l << 12; + } else { + // fallback value + return APB_CLK_FREQ_ROM; + } +} + +static void uart_console_configure(void) +{ +#if CONFIG_CONSOLE_UART_NONE + ets_install_putc1(NULL); + ets_install_putc2(NULL); +#else // CONFIG_CONSOLE_UART_NONE + uartAttach(); + ets_install_uart_printf(); + +#if CONFIG_CONSOLE_UART_CUSTOM + // Some constants to make the following code less upper-case + const int uart_num = CONFIG_CONSOLE_UART_NUM; + const int uart_baud = CONFIG_CONSOLE_UART_BAUDRATE; + const int uart_tx_gpio = CONFIG_CONSOLE_UART_TX_GPIO; + const int uart_rx_gpio = CONFIG_CONSOLE_UART_RX_GPIO; + // ROM bootloader may have put a lot of text into UART0 FIFO. + // Wait for it to be printed. + uart_tx_wait_idle(0); + // Switch to the new UART (this just changes UART number used for + // ets_printf in ROM code). + uart_tx_switch(uart_num); + // Set new baud rate + uart_div_modify(uart_num, (((uint64_t) get_apb_freq()) << 4) / uart_baud); + // If console is attached to UART1 or if non-default pins are used, + // need to reconfigure pins using GPIO matrix + if (uart_num != 0 || uart_tx_gpio != 1 || uart_rx_gpio != 3) { + // Change pin mode for GPIO1/3 from UART to GPIO + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_GPIO3); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_GPIO1); + // Route GPIO signals to/from pins + // (arrays should be optimized away by the compiler) + const uint32_t tx_idx_list[3] = { U0TXD_OUT_IDX, U1TXD_OUT_IDX, U2TXD_OUT_IDX }; + const uint32_t rx_idx_list[3] = { U0RXD_IN_IDX, U1RXD_IN_IDX, U2RXD_IN_IDX }; + const uint32_t tx_idx = tx_idx_list[uart_num]; + const uint32_t rx_idx = rx_idx_list[uart_num]; + gpio_matrix_out(uart_tx_gpio, tx_idx, 0, 0); + gpio_matrix_in(uart_rx_gpio, rx_idx, 0); + } +#endif // CONFIG_CONSOLE_UART_CUSTOM +#endif // CONFIG_CONSOLE_UART_NONE +} diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 8300b444c5..79e0b37413 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -138,6 +138,64 @@ config NEWLIB_STDOUT_ADDCR is usually done by an added CR character. Enabling this will make the standard output code automatically add a CR character before a LF. +choice CONSOLE_UART + prompt "UART for console output" + default CONSOLE_UART_DEFAULT + help + Select whether to use UART for console output (through stdout and stderr). + - Default is to use UART0 on pins GPIO1(TX) and GPIO3(RX). + - If "Custom" is selected, UART0 or UART1 can be chosen, + and any pins can be selected. + - If "None" is selected, there will be no console output on any UART, except + for initial output from ROM bootloader. This output can be further suppressed by + bootstrapping GPIO13 pin to low logic level. + +config CONSOLE_UART_DEFAULT + bool "Default: UART0, TX=GPIO1, RX=GPIO3" +config CONSOLE_UART_CUSTOM + bool "Custom" +config CONSOLE_UART_NONE + bool "None" +endchoice + +choice CONSOLE_UART_NUM + prompt "UART peripheral to use for console output (0-1)" + depends on CONSOLE_UART_CUSTOM + default CONSOLE_UART_CUSTOM_NUM_0 + help + Due of a ROM bug, UART2 is not supported for console output + via ets_printf. + +config CONSOLE_UART_CUSTOM_NUM_0 + bool "UART0" +config CONSOLE_UART_CUSTOM_NUM_1 + bool "UART1" +endchoice + +config CONSOLE_UART_NUM + int + default 0 if CONSOLE_UART_DEFAULT || CONSOLE_UART_NONE + default 0 if CONSOLE_UART_CUSTOM_NUM_0 + default 1 if CONSOLE_UART_CUSTOM_NUM_1 + +config CONSOLE_UART_TX_GPIO + int "UART TX on GPIO#" + depends on CONSOLE_UART_CUSTOM + range 0 33 + default 19 + +config CONSOLE_UART_RX_GPIO + int "UART RX on GPIO#" + depends on CONSOLE_UART_CUSTOM + range 0 39 + default 21 + +config CONSOLE_UART_BAUDRATE + int "UART console baud rate" + depends on !CONSOLE_UART_NONE + default 115200 + range 1200 4000000 + config ULP_COPROC_ENABLED bool "Enable Ultra Low Power (ULP) Coprocessor" default "n" diff --git a/components/esp32/cpu_freq.c b/components/esp32/cpu_freq.c index c68dd4f078..0e9dc23044 100644 --- a/components/esp32/cpu_freq.c +++ b/components/esp32/cpu_freq.c @@ -33,7 +33,7 @@ void esp_set_cpu_freq(void) // freq will be changed to 40MHz in rtc_init_lite, // wait uart tx finish, otherwise some uart output will be lost - uart_tx_wait_idle(0); + uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM); rtc_init_lite(XTAL_AUTO); cpu_freq_t freq = CPU_80M; @@ -54,7 +54,7 @@ void esp_set_cpu_freq(void) // freq will be changed to freq in rtc_set_cpu_freq, // wait uart tx finish, otherwise some uart output will be lost - uart_tx_wait_idle(0); + uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM); rtc_set_cpu_freq(freq); ets_update_cpu_frequency(freq_mhz); diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 1641ab3f0a..81c748c11f 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -54,6 +54,9 @@ #include "esp_coexist.h" #include "trax.h" +#define STRINGIFY(s) STRINGIFY2(s) +#define STRINGIFY2(s) #s + void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))); void start_cpu0_default(void) IRAM_ATTR; #if !CONFIG_FREERTOS_UNICORE @@ -97,9 +100,6 @@ void IRAM_ATTR call_start_cpu0() "wsr %0, vecbase\n" \ ::"r"(&_init_start)); - uartAttach(); - ets_install_uart_printf(); - memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */ @@ -145,6 +145,15 @@ void IRAM_ATTR call_start_cpu1() cpu_configure_region_protection(); +#if CONFIG_CONSOLE_UART_NONE + ets_install_putc1(NULL); + ets_install_putc2(NULL); +#else // CONFIG_CONSOLE_UART_NONE + uartAttach(); + ets_install_uart_printf(); + uart_tx_switch(CONFIG_CONSOLE_UART_NUM); +#endif + ESP_EARLY_LOGI(TAG, "App cpu up."); app_cpu_started = 1; start_cpu1(); @@ -164,7 +173,7 @@ void start_cpu0_default(void) trax_start_trace(TRAX_DOWNCOUNT_WORDS); #endif esp_set_cpu_freq(); // set CPU frequency configured in menuconfig - uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200); + uart_div_modify(CONFIG_CONSOLE_UART_NUM, (APB_CLK_FREQ << 4) / CONFIG_CONSOLE_UART_BAUDRATE); #if CONFIG_BROWNOUT_DET esp_brownout_init(); #endif @@ -177,10 +186,16 @@ void start_cpu0_default(void) esp_setup_time_syscalls(); esp_vfs_dev_uart_register(); esp_reent_init(_GLOBAL_REENT); - const char* default_uart_dev = "/dev/uart/0"; +#ifndef CONFIG_CONSOLE_UART_NONE + const char* default_uart_dev = "/dev/uart/" STRINGIFY(CONFIG_CONSOLE_UART_NUM); _GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r"); _GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w"); _GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w"); +#else + _GLOBAL_REENT->_stdin = (FILE*) &__sf_fake_stdin; + _GLOBAL_REENT->_stdout = (FILE*) &__sf_fake_stdout; + _GLOBAL_REENT->_stderr = (FILE*) &__sf_fake_stderr; +#endif do_global_ctors(); #if !CONFIG_FREERTOS_UNICORE esp_crosscore_int_init();