diff --git a/cores/esp32/HWCDC.cpp b/cores/esp32/HWCDC.cpp index 170e323a035..062317d9f53 100644 --- a/cores/esp32/HWCDC.cpp +++ b/cores/esp32/HWCDC.cpp @@ -603,6 +603,7 @@ void HWCDC::setDebugOutput(bool en) { } else { ets_install_putc2(NULL); } + ets_install_putc1(NULL); // closes UART log output } #if ARDUINO_USB_MODE && ARDUINO_USB_CDC_ON_BOOT // Hardware JTAG CDC selected diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 76135691411..6d762da21fb 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -607,6 +607,24 @@ bool HardwareSerial::setMode(SerialMode mode) { return uartSetMode(_uart, mode); } +// Sets the UART Clock Source based on the compatible SoC options +// This method must be called before starting UART using begin(), otherwise it won't have any effect. +// Clock Source Options are: +// UART_CLK_SRC_DEFAULT :: any SoC - it will set whatever IDF defines as the default UART Clock Source +// UART_CLK_SRC_APB :: ESP32, ESP32-S2, ESP32-C3 and ESP32-S3 +// UART_CLK_SRC_PLL :: ESP32-C2, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2 and ESP32-P4 +// UART_CLK_SRC_XTAL :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4 +// UART_CLK_SRC_RTC :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4 +// UART_CLK_SRC_REF_TICK :: ESP32 and ESP32-S2 +// Note: CLK_SRC_PLL Freq depends on the SoC - ESP32-C2 has 40MHz, ESP32-H2 has 48MHz and ESP32-C5, C6, C61 and P4 has 80MHz +// Note: ESP32-C6, C61, ESP32-P4 and ESP32-C5 have LP UART that will use only RTC_FAST or XTAL/2 as Clock Source +bool HardwareSerial::setClockSource(SerialClkSrc clkSrc) { + if (_uart) { + log_e("No Clock Source change was done. This function must be called before beginning UART%d.", _uart_nr); + return false; + } + return uartSetClockSource(_uart_nr, (uart_sclk_t)clkSrc); +} // minimum total RX Buffer size is the UART FIFO space (128 bytes for most SoC) + 1. IDF imposition. // LP UART has FIFO of 16 bytes size_t HardwareSerial::setRxBufferSize(size_t new_size) { diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index b1f6df17724..e974f112701 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -96,6 +96,29 @@ typedef enum { UART_PARITY_ERROR } hardwareSerial_error_t; +typedef enum { + UART_CLK_SRC_DEFAULT = UART_SCLK_DEFAULT, +#if SOC_UART_SUPPORT_APB_CLK + UART_CLK_SRC_APB = UART_SCLK_APB, +#endif +#if SOC_UART_SUPPORT_PLL_F40M_CLK + UART_CLK_SRC_PLL = UART_SCLK_PLL_F40M, +#elif SOC_UART_SUPPORT_PLL_F80M_CLK + UART_CLK_SRC_PLL = UART_SCLK_PLL_F80M, +#elif CONFIG_IDF_TARGET_ESP32H2 + UART_CLK_SRC_PLL = UART_SCLK_PLL_F48M, +#endif +#if SOC_UART_SUPPORT_XTAL_CLK + UART_CLK_SRC_XTAL = UART_SCLK_XTAL, +#endif +#if SOC_UART_SUPPORT_RTC_CLK + UART_CLK_SRC_RTC = UART_SCLK_RTC, +#endif +#if SOC_UART_SUPPORT_REF_TICK + UART_CLK_SRC_REF_TICK = UART_SCLK_REF_TICK, +#endif +} SerialClkSrc; + #ifndef ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE #ifndef CONFIG_ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE #define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE 2048 @@ -344,6 +367,17 @@ class HardwareSerial : public Stream { // UART_MODE_RS485_COLLISION_DETECT = 0x03 mode: RS485 collision detection UART mode (used for test purposes) // UART_MODE_RS485_APP_CTRL = 0x04 mode: application control RS485 UART mode (used for test purposes) bool setMode(SerialMode mode); + // Used to set the UART clock source mode. It must be set before calling begin(), otherwise it won't have any effect. + // Not all clock source are available to every SoC. The compatible option are listed here: + // UART_CLK_SRC_DEFAULT :: any SoC - it will set whatever IDF defines as the default UART Clock Source + // UART_CLK_SRC_APB :: ESP32, ESP32-S2, ESP32-C3 and ESP32-S3 + // UART_CLK_SRC_PLL :: ESP32-C2, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2 and ESP32-P4 + // UART_CLK_SRC_XTAL :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4 + // UART_CLK_SRC_RTC :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4 + // UART_CLK_SRC_REF_TICK :: ESP32 and ESP32-S2 + // Note: CLK_SRC_PLL Freq depends on the SoC - ESP32-C2 has 40MHz, ESP32-H2 has 48MHz and ESP32-C5, C6, C61 and P4 has 80MHz + // Note: ESP32-C6, C61, ESP32-P4 and ESP32-C5 have LP UART that will use only RTC_FAST or XTAL/2 as Clock Source + bool setClockSource(SerialClkSrc clkSrc); size_t setRxBufferSize(size_t new_size); size_t setTxBufferSize(size_t new_size); diff --git a/cores/esp32/USB.cpp b/cores/esp32/USB.cpp index 8fdd7a3ab71..269e9a76cb3 100644 --- a/cores/esp32/USB.cpp +++ b/cores/esp32/USB.cpp @@ -100,6 +100,7 @@ static bool tinyusb_device_suspended = false; void tud_mount_cb(void) { tinyusb_device_mounted = true; arduino_usb_event_data_t p; + p.suspend.remote_wakeup_en = 0; arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STARTED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); } @@ -107,6 +108,7 @@ void tud_mount_cb(void) { void tud_umount_cb(void) { tinyusb_device_mounted = false; arduino_usb_event_data_t p; + p.suspend.remote_wakeup_en = 0; arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); } @@ -123,6 +125,7 @@ void tud_suspend_cb(bool remote_wakeup_en) { void tud_resume_cb(void) { tinyusb_device_suspended = false; arduino_usb_event_data_t p; + p.suspend.remote_wakeup_en = 0; arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); } diff --git a/cores/esp32/USBCDC.cpp b/cores/esp32/USBCDC.cpp index 945021a79e2..c7bb4582d4f 100644 --- a/cores/esp32/USBCDC.cpp +++ b/cores/esp32/USBCDC.cpp @@ -455,6 +455,7 @@ void USBCDC::setDebugOutput(bool en) { } else { ets_install_putc2(NULL); } + ets_install_putc1(NULL); // closes UART log output } USBCDC::operator bool() const { diff --git a/cores/esp32/esp32-hal-bt.c b/cores/esp32/esp32-hal-bt.c index 5f1148bd492..1e5f73e324c 100644 --- a/cores/esp32/esp32-hal-bt.c +++ b/cores/esp32/esp32-hal-bt.c @@ -15,7 +15,7 @@ #include "esp32-hal-bt.h" #if SOC_BT_SUPPORTED -#ifdef CONFIG_BT_ENABLED +#ifdef CONFIG_BT_BLUEDROID_ENABLED #if CONFIG_IDF_TARGET_ESP32 bool btInUse() { diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c index 50e2973d27a..594acd38153 100644 --- a/cores/esp32/esp32-hal-misc.c +++ b/cores/esp32/esp32-hal-misc.c @@ -25,9 +25,9 @@ #include "esp_ota_ops.h" #endif //CONFIG_APP_ROLLBACK_ENABLE #include "esp_private/startup_internal.h" -#if defined(CONFIG_BT_ENABLED) && SOC_BT_SUPPORTED +#if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED #include "esp_bt.h" -#endif //CONFIG_BT_ENABLED +#endif //CONFIG_BT_BLUEDROID_ENABLED #include #include "soc/rtc.h" #if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4) @@ -243,7 +243,7 @@ bool verifyRollbackLater() { } #endif -#ifdef CONFIG_BT_ENABLED +#ifdef CONFIG_BT_BLUEDROID_ENABLED #if CONFIG_IDF_TARGET_ESP32 //overwritten in esp32-hal-bt.c bool btInUse() __attribute__((weak)); @@ -305,7 +305,7 @@ void initArduino() { if (err) { log_e("Failed to initialize NVS! Error: %u", err); } -#if defined(CONFIG_BT_ENABLED) && SOC_BT_SUPPORTED +#if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED if (!btInUse()) { esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); } diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 75e2da013ea..5311aff4f37 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -58,6 +58,7 @@ struct uart_struct_t { uint16_t _rx_buffer_size, _tx_buffer_size; // UART RX and TX buffer sizes bool _inverted; // UART inverted signal uint8_t _rxfifo_full_thrhd; // UART RX FIFO full threshold + int8_t _uart_clock_source; // UART Clock Source used when it is started using uartBegin() }; #if CONFIG_DISABLE_HAL_LOCKS @@ -66,21 +67,21 @@ struct uart_struct_t { #define UART_MUTEX_UNLOCK() static uart_t _uart_bus_array[] = { - {0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #if SOC_UART_NUM > 1 - {1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 2 - {2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 3 - {3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 4 - {4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 5 - {5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif }; @@ -95,21 +96,21 @@ static uart_t _uart_bus_array[] = { xSemaphoreGive(uart->lock) static uart_t _uart_bus_array[] = { - {NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #if SOC_UART_NUM > 1 - {NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 2 - {NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 3 - {NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 4 - {NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif #if SOC_UART_NUM > 5 - {NULL, 5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, + {NULL, 5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1}, #endif }; @@ -664,30 +665,40 @@ uart_t *uartBegin( rxfifo_full_thrhd = uart_config.rx_flow_ctrl_thresh; // makes sure that it will be set correctly in the struct uart_config.baud_rate = baudrate; #if SOC_UART_LP_NUM >= 1 - if (uart_nr >= SOC_UART_HP_NUM) { // it is a LP UART NUM - uart_config.lp_source_clk = LP_UART_SCLK_DEFAULT; // use default LP clock - log_v("Setting UART%d to use LP clock", uart_nr); + if (uart_nr >= SOC_UART_HP_NUM) { // it is a LP UART NUM + if (uart->_uart_clock_source > 0) { + uart_config.lp_source_clk = (soc_periph_lp_uart_clk_src_t)uart->_uart_clock_source; // use user defined LP UART clock + log_v("Setting UART%d to user defined LP clock source (%d) ", uart_nr, uart->_uart_clock_source); + } else { + uart_config.lp_source_clk = LP_UART_SCLK_DEFAULT; // use default LP clock + log_v("Setting UART%d to Default LP clock source", uart_nr); + } } else -#endif +#endif // SOC_UART_LP_NUM >= 1 { - // there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored - // therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue. + if (uart->_uart_clock_source >= 0) { + uart_config.source_clk = (soc_module_clk_t)uart->_uart_clock_source; // use user defined HP UART clock + log_v("Setting UART%d to user defined HP clock source (%d) ", uart_nr, uart->_uart_clock_source); + } else { + // there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored + // therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue. #if SOC_UART_SUPPORT_XTAL_CLK - uart_config.source_clk = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4 - log_v("Setting UART%d to use XTAL clock", uart_nr); + uart_config.source_clk = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4 + log_v("Setting UART%d to use XTAL clock", uart_nr); #elif SOC_UART_SUPPORT_REF_TICK - if (baudrate <= REF_TICK_BAUDRATE_LIMIT) { - uart_config.source_clk = UART_SCLK_REF_TICK; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps - log_v("Setting UART%d to use REF_TICK clock", uart_nr); - } else { - uart_config.source_clk = UART_SCLK_APB; // baudrate may change with the APB Frequency! - log_v("Setting UART%d to use APB clock", uart_nr); - } + if (baudrate <= REF_TICK_BAUDRATE_LIMIT) { + uart_config.source_clk = UART_SCLK_REF_TICK; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps + log_v("Setting UART%d to use REF_TICK clock", uart_nr); + } else { + uart_config.source_clk = UART_SCLK_APB; // baudrate may change with the APB Frequency! + log_v("Setting UART%d to use APB clock", uart_nr); + } #else - // Default CLK Source: CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6 - uart_config.source_clk = UART_SCLK_DEFAULT; // baudrate may change with the APB Frequency! - log_v("Setting UART%d to use DEFAULT clock", uart_nr); -#endif + // Default CLK Source: CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6|P4 + uart_config.source_clk = UART_SCLK_DEFAULT; // baudrate may change with the APB Frequency! + log_v("Setting UART%d to use DEFAULT clock", uart_nr); +#endif // SOC_UART_SUPPORT_XTAL_CLK + } } UART_MUTEX_LOCK(); @@ -716,6 +727,14 @@ uart_t *uartBegin( uart->_tx_buffer_size = tx_buffer_size; uart->has_peek = false; uart->peek_byte = 0; +#if SOC_UART_LP_NUM >= 1 + if (uart_nr >= SOC_UART_HP_NUM) { + uart->_uart_clock_source = uart_config.lp_source_clk; + } else +#endif + { + uart->_uart_clock_source = uart_config.source_clk; + } } UART_MUTEX_UNLOCK(); @@ -975,22 +994,52 @@ bool uartSetBaudRate(uart_t *uart, uint32_t baud_rate) { return false; } bool retCode = true; - UART_MUTEX_LOCK(); -#if SOC_UART_SUPPORT_XTAL_CLK // ESP32-S3, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-H2 and ESP32-P4 - soc_module_clk_t newClkSrc = UART_SCLK_XTAL; + soc_module_clk_t newClkSrc = UART_SCLK_DEFAULT; + int8_t previousClkSrc = uart->_uart_clock_source; #if SOC_UART_LP_NUM >= 1 if (uart->num >= SOC_UART_HP_NUM) { // it is a LP UART NUM - newClkSrc = LP_UART_SCLK_DEFAULT; // use default LP clock + if (uart->_uart_clock_source > 0) { + newClkSrc = (soc_periph_lp_uart_clk_src_t)uart->_uart_clock_source; // use user defined LP UART clock + log_v("Setting UART%d to user defined LP clock source (%d) ", uart->num, newClkSrc); + } else { + newClkSrc = LP_UART_SCLK_DEFAULT; // use default LP clock + log_v("Setting UART%d to Default LP clock source", uart->num); + } + } else +#endif // SOC_UART_LP_NUM >= 1 + { + if (uart->_uart_clock_source >= 0) { + newClkSrc = (soc_module_clk_t)uart->_uart_clock_source; // use user defined HP UART clock + log_v("Setting UART%d to use HP clock source (%d) ", uart->num, newClkSrc); + } else { + // there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored + // therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue. +#if SOC_UART_SUPPORT_XTAL_CLK + newClkSrc = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4 + log_v("Setting UART%d to use XTAL clock", uart->num); +#elif SOC_UART_SUPPORT_REF_TICK + if (baud_rate <= REF_TICK_BAUDRATE_LIMIT) { + newClkSrc = UART_SCLK_REF_TICK; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps + log_v("Setting UART%d to use REF_TICK clock", uart->num); + } else { + newClkSrc = UART_SCLK_APB; // baudrate may change with the APB Frequency! + log_v("Setting UART%d to use APB clock", uart->num); + } +#else + // Default CLK Source: CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6|P4 + // using newClkSrc = UART_SCLK_DEFAULT as defined in the variable declaration + log_v("Setting UART%d to use DEFAULT clock", uart->num); +#endif // SOC_UART_SUPPORT_XTAL_CLK + } } -#endif - // ESP32-P4 demands an atomic operation for setting the clock source - HP_UART_SRC_CLK_ATOMIC() { - uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc); + UART_MUTEX_LOCK(); + // if necessary, set the correct UART Clock Source before changing the baudrate + if (previousClkSrc < 0 || previousClkSrc != newClkSrc) { + HP_UART_SRC_CLK_ATOMIC() { + uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc); + } + uart->_uart_clock_source = newClkSrc; } -#else // ESP32, ESP32-S2 - soc_module_clk_t newClkSrc = baud_rate <= REF_TICK_BAUDRATE_LIMIT ? SOC_MOD_CLK_REF_TICK : SOC_MOD_CLK_APB; - uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc); -#endif if (uart_set_baudrate(uart->num, baud_rate) == ESP_OK) { log_v("Setting UART%d baud rate to %ld.", uart->num, baud_rate); uart->_baudrate = baud_rate; @@ -1084,6 +1133,31 @@ bool uartSetMode(uart_t *uart, uart_mode_t mode) { return retCode; } +// this function will set the uart clock source +// it must be called before uartBegin(), otherwise it won't change any thing. +bool uartSetClockSource(uint8_t uartNum, uart_sclk_t clkSrc) { + if (uartNum >= SOC_UART_NUM) { + log_e("UART%d is invalid. This device has %d UARTs, from 0 to %d.", uartNum, SOC_UART_NUM, SOC_UART_NUM - 1); + return false; + } + uart_t *uart = &_uart_bus_array[uartNum]; +#if SOC_UART_LP_NUM >= 1 + if (uart->num >= SOC_UART_HP_NUM) { + switch (clkSrc) { + case UART_SCLK_XTAL: uart->_uart_clock_source = LP_UART_SCLK_XTAL_D2; break; + case UART_SCLK_RTC: uart->_uart_clock_source = LP_UART_SCLK_LP_FAST; break; + case UART_SCLK_DEFAULT: + default: uart->_uart_clock_source = LP_UART_SCLK_DEFAULT; + } + } else +#endif + { + uart->_uart_clock_source = clkSrc; + } + //log_i("UART%d set clock source to %d", uart->num, uart->_uart_clock_source); + return true; +} + void uartSetDebug(uart_t *uart) { // LP UART is not supported for debug if (uart == NULL || uart->num >= SOC_UART_HP_NUM) { @@ -1112,7 +1186,7 @@ int log_printfv(const char *format, va_list arg) { return 0; } } -/* + /* // This causes dead locks with logging in specific cases and also with C++ constructors that may send logs #if !CONFIG_DISABLE_HAL_LOCKS if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){ @@ -1120,16 +1194,8 @@ int log_printfv(const char *format, va_list arg) { } #endif */ -#if (ARDUINO_USB_CDC_ON_BOOT == 1 && ARDUINO_USB_MODE == 0) || CONFIG_IDF_TARGET_ESP32C3 \ - || ((CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32P4) && ARDUINO_USB_CDC_ON_BOOT == 1) vsnprintf(temp, len + 1, format, arg); ets_printf("%s", temp); -#else - int wlen = vsnprintf(temp, len + 1, format, arg); - for (int i = 0; i < wlen; i++) { - ets_write_char_uart(temp[i]); - } -#endif /* // This causes dead locks with logging and also with constructors that may send logs #if !CONFIG_DISABLE_HAL_LOCKS diff --git a/cores/esp32/esp32-hal-uart.h b/cores/esp32/esp32-hal-uart.h index 4d686fdd23d..41b005aa151 100644 --- a/cores/esp32/esp32-hal-uart.h +++ b/cores/esp32/esp32-hal-uart.h @@ -97,6 +97,19 @@ bool uartSetHwFlowCtrlMode(uart_t *uart, uart_hw_flowcontrol_t mode, uint8_t thr // UART_MODE_RS485_APP_CTRL = 0x04 mode: application control RS485 UART mode (used for test purposes) bool uartSetMode(uart_t *uart, uart_mode_t mode); +// Used to set the UART clock source mode. It must be set before calling uartBegin(), otherwise it won't have any effect. +// Not all clock source are available to every SoC. The compatible option are listed here: +// UART_SCLK_DEFAULT :: any SoC - it will set whatever IDF defines as the default UART Clock Source +// UART_SCLK_APB :: ESP32, ESP32-S2, ESP32-C3 and ESP32-S3 +// UART_SCLK_PLL_F80M :: ESP32-C5, ESP32-C6, ESP32-C61 and ESP32-P4 +// UART_SCLK_PLL_F40M :: ESP32-C2 +// UART_SCLK_PLL_F48M :: ESP32-H2 +// UART_SCLK_XTAL :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4 +// UART_SCLK_RTC :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4 +// UART_SCLK_REF_TICK :: ESP32 and ESP32-S2 +// Note: ESP32-C6, C61, ESP32-P4 and ESP32-C5 have LP UART that will use only LP_UART_SCLK_LP_FAST (RTC_FAST) or LP_UART_SCLK_XTAL_D2 (XTAL/2) as Clock Source +bool uartSetClockSource(uint8_t uartNum, uart_sclk_t clkSrc); + void uartStartDetectBaudrate(uart_t *uart); unsigned long uartDetectBaudrate(uart_t *uart); diff --git a/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino b/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino index 17e7af290bf..5d0406aee0e 100644 --- a/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino +++ b/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino @@ -1,4 +1,4 @@ -// Copyright 2023 Espressif Systems (Shanghai) PTE LTD +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -35,14 +35,11 @@ rmt_data_t my_data[256]; rmt_data_t data[256]; -static EventGroupHandle_t events; - #define RMT_FREQ 10000000 // tick time is 100ns -#define RMT_NUM_EXCHANGED_DATA 30 +#define RMT_NUM_EXCHANGED_DATA 32 void setup() { Serial.begin(115200); - events = xEventGroupCreate(); if (!rmtInit(RMT_TX_PIN, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, RMT_FREQ)) { Serial.println("init sender failed\n"); @@ -50,25 +47,41 @@ void setup() { if (!rmtInit(RMT_RX_PIN, RMT_RX_MODE, RMT_MEM_RX, RMT_FREQ)) { Serial.println("init receiver failed\n"); } + Serial.println(); + Serial.println("RMT tick set to: 100ns"); // End of transmission shall be detected when line is idle for 2us = 20*100ns rmtSetRxMaxThreshold(RMT_RX_PIN, 20); // Disable Glitch filter rmtSetRxMinThreshold(RMT_RX_PIN, 0); - Serial.println("real tick set to: 100ns"); - Serial.printf("\nPlease connect GPIO %d to GPIO %d, now.\n", RMT_TX_PIN, RMT_RX_PIN); -} - -void loop() { - // Init data - int i; - for (i = 0; i < 255; i++) { - data[i].val = 0x80010001 + ((i % 13) << 16) + 13 - (i % 13); + // create multiple pulses with different width to be sent + for (int i = 0; i < 255; i++) { + data[i].level0 = 1; // HIGH + data[i].duration0 = 1 + 13 - (i % 13); // number of Tick on High + data[i].level1 = 0; // LOW + data[i].duration1 = 1 + (i % 13); // number of Ticks on Low my_data[i].val = 0; } data[255].val = 0; + Serial.println(); + Serial.println("===================================================================================================="); + Serial.println("Preloaded Data that will sent (time in 0.1us):"); + // Printout the received data plus the original values + for (int i = 0; i < RMT_NUM_EXCHANGED_DATA; i++) { + Serial.printf("%08lx=[%c 0x%02x|%c 0x%02x] ", data[i].val, data[i].level0 ? 'H' : 'L', data[i].duration0, data[i].level1 ? 'H' : 'L', data[i].duration1); + if (!((i + 1) % 4)) { + Serial.println(); + } + } + Serial.println("===================================================================================================="); + Serial.printf("Please connect GPIO %d to GPIO %d, now.", RMT_TX_PIN, RMT_RX_PIN); + Serial.println(); + Serial.println(); +} + +void loop() { // Start an async data read size_t rx_num_symbols = RMT_NUM_EXCHANGED_DATA; rmtReadAsync(RMT_RX_PIN, my_data, &rx_num_symbols); @@ -84,13 +97,13 @@ void loop() { Serial.printf("Got %d RMT symbols\n", rx_num_symbols); // Printout the received data plus the original values - for (i = 0; i < 60; i++) { + for (int i = 0; i < RMT_NUM_EXCHANGED_DATA; i++) { Serial.printf("%08lx=%08lx ", my_data[i].val, data[i].val); if (!((i + 1) % 4)) { - Serial.println(""); + Serial.println(); } } - Serial.println("\n"); + Serial.println(); - delay(500); + delay(2000); } diff --git a/libraries/USB/src/USBHIDConsumerControl.h b/libraries/USB/src/USBHIDConsumerControl.h index e65e529a77b..7a59c70b6b1 100644 --- a/libraries/USB/src/USBHIDConsumerControl.h +++ b/libraries/USB/src/USBHIDConsumerControl.h @@ -37,10 +37,14 @@ #define CONSUMER_CONTROL_WIRELESS_RADIO_SLIDER_SWITCH 0x00C8 // Media Control -#define CONSUMER_CONTROL_PLAY_PAUSE 0x00CD +#define CONSUMER_CONTROL_RECORD 0x00B2 +#define CONSUMER_CONTROL_FAST_FORWARD 0x00B3 +#define CONSUMER_CONTROL_REWIND 0x00B4 #define CONSUMER_CONTROL_SCAN_NEXT 0x00B5 #define CONSUMER_CONTROL_SCAN_PREVIOUS 0x00B6 #define CONSUMER_CONTROL_STOP 0x00B7 +#define CONSUMER_CONTROL_EJECT 0x00B8 +#define CONSUMER_CONTROL_PLAY_PAUSE 0x00CD #define CONSUMER_CONTROL_VOLUME 0x00E0 #define CONSUMER_CONTROL_MUTE 0x00E2 #define CONSUMER_CONTROL_BASS 0x00E3 diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp index aa994963514..3faf34fef34 100644 --- a/libraries/WiFi/src/WiFiGeneric.cpp +++ b/libraries/WiFi/src/WiFiGeneric.cpp @@ -602,9 +602,9 @@ bool WiFiGenericClass::mode(wifi_mode_t m) { #else #define WIFI_PROTOCOL_DEFAULT (WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N) #endif - uint8_t current_protocol = 0; + uint32_t current_protocol = 0; if (m & WIFI_MODE_STA) { - err = esp_wifi_get_protocol(WIFI_IF_STA, ¤t_protocol); + err = esp_wifi_get_protocol(WIFI_IF_STA, (uint8_t *)¤t_protocol); if (err == ESP_OK && current_protocol == WIFI_PROTOCOL_LR) { log_v("Disabling long range on STA"); err = esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_DEFAULT); @@ -614,7 +614,7 @@ bool WiFiGenericClass::mode(wifi_mode_t m) { } } if (m & WIFI_MODE_AP) { - err = esp_wifi_get_protocol(WIFI_IF_AP, ¤t_protocol); + err = esp_wifi_get_protocol(WIFI_IF_AP, (uint8_t *)¤t_protocol); if (err == ESP_OK && current_protocol == WIFI_PROTOCOL_LR) { log_v("Disabling long range on AP"); err = esp_wifi_set_protocol(WIFI_IF_AP, WIFI_PROTOCOL_DEFAULT); diff --git a/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino b/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino index 3eefd973dd2..e9d08d32175 100644 --- a/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino +++ b/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino @@ -85,9 +85,9 @@ void setup() { // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) zbTempSensor.setTolerance(1); - // Set power source to battery and set battery percentage to measured value (now 100% for demonstration) - // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) anytime - zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100); + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); // Add humidity cluster to the temperature sensor device with min, max and tolerance values zbTempSensor.addHumiditySensor(0, 100, 1); diff --git a/libraries/Zigbee/src/ZigbeeEP.cpp b/libraries/Zigbee/src/ZigbeeEP.cpp index 338a4107cf2..cf52a902983 100644 --- a/libraries/Zigbee/src/ZigbeeEP.cpp +++ b/libraries/Zigbee/src/ZigbeeEP.cpp @@ -73,7 +73,7 @@ bool ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) { return ret_name == ESP_OK && ret_model == ESP_OK; } -bool ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_percentage) { +bool ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_percentage, uint8_t battery_voltage) { esp_zb_attribute_list_t *basic_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); esp_err_t ret = esp_zb_cluster_update_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, (void *)&power_source); if (ret != ESP_OK) { @@ -93,6 +93,11 @@ bool ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_pe log_e("Failed to add battery percentage attribute: 0x%x: %s", ret, esp_err_to_name(ret)); return false; } + ret = esp_zb_power_config_cluster_add_attr(power_config_cluster, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID, (void *)&battery_voltage); + if (ret != ESP_OK) { + log_e("Failed to add battery voltage attribute: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } ret = esp_zb_cluster_list_add_power_config_cluster(_cluster_list, power_config_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); if (ret != ESP_OK) { log_e("Failed to add power config cluster: 0x%x: %s", ret, esp_err_to_name(ret)); @@ -125,6 +130,21 @@ bool ZigbeeEP::setBatteryPercentage(uint8_t percentage) { return true; } +bool ZigbeeEP::setBatteryVoltage(uint8_t voltage) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; + esp_zb_lock_acquire(portMAX_DELAY); + ret = esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID, &voltage, false + ); + esp_zb_lock_release(); + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set battery voltage: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + log_v("Battery voltage updated"); + return true; +} + bool ZigbeeEP::reportBatteryPercentage() { /* Send report attributes command */ esp_zb_zcl_report_attr_cmd_t report_attr_cmd; diff --git a/libraries/Zigbee/src/ZigbeeEP.h b/libraries/Zigbee/src/ZigbeeEP.h index 9bdeea5abe9..e13b3b59de9 100644 --- a/libraries/Zigbee/src/ZigbeeEP.h +++ b/libraries/Zigbee/src/ZigbeeEP.h @@ -81,9 +81,10 @@ class ZigbeeEP { char *readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr); // Set Power source and battery percentage for battery powered devices - bool setPowerSource(zb_power_source_t power_source, uint8_t percentage = 255); - bool setBatteryPercentage(uint8_t percentage); - bool reportBatteryPercentage(); + bool setPowerSource(zb_power_source_t power_source, uint8_t percentage = 0xff, uint8_t voltage = 0xff); // voltage in 100mV + bool setBatteryPercentage(uint8_t percentage); // 0-100 % + bool setBatteryVoltage(uint8_t voltage); // voltage in 100mV (example value 35 for 3.5V) + bool reportBatteryPercentage(); // battery voltage is not reportable attribute // Set time bool addTimeCluster(tm time = {}, int32_t gmt_offset = 0); // gmt offset in seconds diff --git a/variants/alfredo-nou3/pins_arduino.h b/variants/alfredo-nou3/pins_arduino.h index 88bdbea0bb1..8b5a7d51b9f 100644 --- a/variants/alfredo-nou3/pins_arduino.h +++ b/variants/alfredo-nou3/pins_arduino.h @@ -1,6 +1,7 @@ #ifndef Pins_Arduino_h #define Pins_Arduino_h +#include #define USB_VID 0xAFD0 #define USB_PID 0x0003 #define USB_MANUFACTURER "Alfredo"