@@ -58,6 +58,7 @@ struct uart_struct_t {
5858 uint16_t _rx_buffer_size , _tx_buffer_size ; // UART RX and TX buffer sizes
5959 bool _inverted ; // UART inverted signal
6060 uint8_t _rxfifo_full_thrhd ; // UART RX FIFO full threshold
61+ int8_t _uart_clock_source ; // UART Clock Source used when it is started using uartBegin()
6162};
6263
6364#if CONFIG_DISABLE_HAL_LOCKS
@@ -66,21 +67,21 @@ struct uart_struct_t {
6667#define UART_MUTEX_UNLOCK ()
6768
6869static uart_t _uart_bus_array [] = {
69- {0 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 },
70+ {0 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 , -1 },
7071#if SOC_UART_NUM > 1
71- {1 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 },
72+ {1 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 , -1 },
7273#endif
7374#if SOC_UART_NUM > 2
74- {2 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 },
75+ {2 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 , -1 },
7576#endif
7677#if SOC_UART_NUM > 3
77- {3 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 },
78+ {3 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 , -1 },
7879#endif
7980#if SOC_UART_NUM > 4
80- {4 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 },
81+ {4 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 , -1 },
8182#endif
8283#if SOC_UART_NUM > 5
83- {5 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 },
84+ {5 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 , -1 },
8485#endif
8586};
8687
@@ -95,21 +96,21 @@ static uart_t _uart_bus_array[] = {
9596 xSemaphoreGive(uart->lock)
9697
9798static uart_t _uart_bus_array [] = {
98- {NULL , 0 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 },
99+ {NULL , 0 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 , -1 },
99100#if SOC_UART_NUM > 1
100- {NULL , 1 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 },
101+ {NULL , 1 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 , -1 },
101102#endif
102103#if SOC_UART_NUM > 2
103- {NULL , 2 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 },
104+ {NULL , 2 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 , -1 },
104105#endif
105106#if SOC_UART_NUM > 3
106- {NULL , 3 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 },
107+ {NULL , 3 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 , -1 },
107108#endif
108109#if SOC_UART_NUM > 4
109- {NULL , 4 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 },
110+ {NULL , 4 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 , -1 },
110111#endif
111112#if SOC_UART_NUM > 5
112- {NULL , 5 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 },
113+ {NULL , 5 , false, 0 , NULL , -1 , -1 , -1 , -1 , 0 , 0 , 0 , 0 , false, 0 , -1 },
113114#endif
114115};
115116
@@ -664,30 +665,40 @@ uart_t *uartBegin(
664665 rxfifo_full_thrhd = uart_config .rx_flow_ctrl_thresh ; // makes sure that it will be set correctly in the struct
665666 uart_config .baud_rate = baudrate ;
666667#if SOC_UART_LP_NUM >= 1
667- if (uart_nr >= SOC_UART_HP_NUM ) { // it is a LP UART NUM
668- uart_config .lp_source_clk = LP_UART_SCLK_DEFAULT ; // use default LP clock
669- log_v ("Setting UART%d to use LP clock" , uart_nr );
668+ if (uart_nr >= SOC_UART_HP_NUM ) { // it is a LP UART NUM
669+ if (uart -> _uart_clock_source > 0 ) {
670+ uart_config .lp_source_clk = (soc_periph_lp_uart_clk_src_t )uart -> _uart_clock_source ; // use user defined LP UART clock
671+ log_v ("Setting UART%d to user defined LP clock source (%d) " , uart_nr , uart -> _uart_clock_source );
672+ } else {
673+ uart_config .lp_source_clk = LP_UART_SCLK_DEFAULT ; // use default LP clock
674+ log_v ("Setting UART%d to Default LP clock source" , uart_nr );
675+ }
670676 } else
671- #endif
677+ #endif // SOC_UART_LP_NUM >= 1
672678 {
673- // there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored
674- // therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue.
679+ if (uart -> _uart_clock_source >= 0 ) {
680+ uart_config .source_clk = (soc_module_clk_t )uart -> _uart_clock_source ; // use user defined HP UART clock
681+ log_v ("Setting UART%d to user defined HP clock source (%d) " , uart_nr , uart -> _uart_clock_source );
682+ } else {
683+ // there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored
684+ // therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue.
675685#if SOC_UART_SUPPORT_XTAL_CLK
676- uart_config .source_clk = UART_SCLK_XTAL ; // valid for C2, S3, C3, C6, H2 and P4
677- log_v ("Setting UART%d to use XTAL clock" , uart_nr );
686+ uart_config .source_clk = UART_SCLK_XTAL ; // valid for C2, S3, C3, C6, H2 and P4
687+ log_v ("Setting UART%d to use XTAL clock" , uart_nr );
678688#elif SOC_UART_SUPPORT_REF_TICK
679- if (baudrate <= REF_TICK_BAUDRATE_LIMIT ) {
680- uart_config .source_clk = UART_SCLK_REF_TICK ; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps
681- log_v ("Setting UART%d to use REF_TICK clock" , uart_nr );
682- } else {
683- uart_config .source_clk = UART_SCLK_APB ; // baudrate may change with the APB Frequency!
684- log_v ("Setting UART%d to use APB clock" , uart_nr );
685- }
689+ if (baudrate <= REF_TICK_BAUDRATE_LIMIT ) {
690+ uart_config .source_clk = UART_SCLK_REF_TICK ; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps
691+ log_v ("Setting UART%d to use REF_TICK clock" , uart_nr );
692+ } else {
693+ uart_config .source_clk = UART_SCLK_APB ; // baudrate may change with the APB Frequency!
694+ log_v ("Setting UART%d to use APB clock" , uart_nr );
695+ }
686696#else
687- // 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
688- uart_config .source_clk = UART_SCLK_DEFAULT ; // baudrate may change with the APB Frequency!
689- log_v ("Setting UART%d to use DEFAULT clock" , uart_nr );
690- #endif
697+ // 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
698+ uart_config .source_clk = UART_SCLK_DEFAULT ; // baudrate may change with the APB Frequency!
699+ log_v ("Setting UART%d to use DEFAULT clock" , uart_nr );
700+ #endif // SOC_UART_SUPPORT_XTAL_CLK
701+ }
691702 }
692703
693704 UART_MUTEX_LOCK ();
@@ -716,6 +727,14 @@ uart_t *uartBegin(
716727 uart -> _tx_buffer_size = tx_buffer_size ;
717728 uart -> has_peek = false;
718729 uart -> peek_byte = 0 ;
730+ #if SOC_UART_LP_NUM >= 1
731+ if (uart_nr >= SOC_UART_HP_NUM ) {
732+ uart -> _uart_clock_source = uart_config .lp_source_clk ;
733+ } else
734+ #endif
735+ {
736+ uart -> _uart_clock_source = uart_config .source_clk ;
737+ }
719738 }
720739 UART_MUTEX_UNLOCK ();
721740
@@ -975,22 +994,52 @@ bool uartSetBaudRate(uart_t *uart, uint32_t baud_rate) {
975994 return false;
976995 }
977996 bool retCode = true;
978- UART_MUTEX_LOCK ();
979- #if SOC_UART_SUPPORT_XTAL_CLK // ESP32-S3, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-H2 and ESP32-P4
980- soc_module_clk_t newClkSrc = UART_SCLK_XTAL ;
997+ soc_module_clk_t newClkSrc = UART_SCLK_DEFAULT ;
998+ int8_t previousClkSrc = uart -> _uart_clock_source ;
981999#if SOC_UART_LP_NUM >= 1
9821000 if (uart -> num >= SOC_UART_HP_NUM ) { // it is a LP UART NUM
983- newClkSrc = LP_UART_SCLK_DEFAULT ; // use default LP clock
1001+ if (uart -> _uart_clock_source > 0 ) {
1002+ newClkSrc = (soc_periph_lp_uart_clk_src_t )uart -> _uart_clock_source ; // use user defined LP UART clock
1003+ log_v ("Setting UART%d to user defined LP clock source (%d) " , uart -> num , newClkSrc );
1004+ } else {
1005+ newClkSrc = LP_UART_SCLK_DEFAULT ; // use default LP clock
1006+ log_v ("Setting UART%d to Default LP clock source" , uart -> num );
1007+ }
1008+ } else
1009+ #endif // SOC_UART_LP_NUM >= 1
1010+ {
1011+ if (uart -> _uart_clock_source >= 0 ) {
1012+ newClkSrc = (soc_module_clk_t )uart -> _uart_clock_source ; // use user defined HP UART clock
1013+ log_v ("Setting UART%d to use HP clock source (%d) " , uart -> num , newClkSrc );
1014+ } else {
1015+ // there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored
1016+ // therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue.
1017+ #if SOC_UART_SUPPORT_XTAL_CLK
1018+ newClkSrc = UART_SCLK_XTAL ; // valid for C2, S3, C3, C6, H2 and P4
1019+ log_v ("Setting UART%d to use XTAL clock" , uart -> num );
1020+ #elif SOC_UART_SUPPORT_REF_TICK
1021+ if (baud_rate <= REF_TICK_BAUDRATE_LIMIT ) {
1022+ newClkSrc = UART_SCLK_REF_TICK ; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps
1023+ log_v ("Setting UART%d to use REF_TICK clock" , uart -> num );
1024+ } else {
1025+ newClkSrc = UART_SCLK_APB ; // baudrate may change with the APB Frequency!
1026+ log_v ("Setting UART%d to use APB clock" , uart -> num );
1027+ }
1028+ #else
1029+ // 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
1030+ // using newClkSrc = UART_SCLK_DEFAULT as defined in the variable declaration
1031+ log_v ("Setting UART%d to use DEFAULT clock" , uart -> num );
1032+ #endif // SOC_UART_SUPPORT_XTAL_CLK
1033+ }
9841034 }
985- #endif
986- // ESP32-P4 demands an atomic operation for setting the clock source
987- HP_UART_SRC_CLK_ATOMIC () {
988- uart_ll_set_sclk (UART_LL_GET_HW (uart -> num ), newClkSrc );
1035+ UART_MUTEX_LOCK ();
1036+ // if necessary, set the correct UART Clock Source before changing the baudrate
1037+ if (previousClkSrc < 0 || previousClkSrc != newClkSrc ) {
1038+ HP_UART_SRC_CLK_ATOMIC () {
1039+ uart_ll_set_sclk (UART_LL_GET_HW (uart -> num ), newClkSrc );
1040+ }
1041+ uart -> _uart_clock_source = newClkSrc ;
9891042 }
990- #else // ESP32, ESP32-S2
991- soc_module_clk_t newClkSrc = baud_rate <= REF_TICK_BAUDRATE_LIMIT ? SOC_MOD_CLK_REF_TICK : SOC_MOD_CLK_APB ;
992- uart_ll_set_sclk (UART_LL_GET_HW (uart -> num ), newClkSrc );
993- #endif
9941043 if (uart_set_baudrate (uart -> num , baud_rate ) == ESP_OK ) {
9951044 log_v ("Setting UART%d baud rate to %ld." , uart -> num , baud_rate );
9961045 uart -> _baudrate = baud_rate ;
@@ -1084,6 +1133,31 @@ bool uartSetMode(uart_t *uart, uart_mode_t mode) {
10841133 return retCode ;
10851134}
10861135
1136+ // this function will set the uart clock source
1137+ // it must be called before uartBegin(), otherwise it won't change any thing.
1138+ bool uartSetClockSource (uint8_t uartNum , uart_sclk_t clkSrc ) {
1139+ if (uartNum >= SOC_UART_NUM ) {
1140+ log_e ("UART%d is invalid. This device has %d UARTs, from 0 to %d." , uartNum , SOC_UART_NUM , SOC_UART_NUM - 1 );
1141+ return false;
1142+ }
1143+ uart_t * uart = & _uart_bus_array [uartNum ];
1144+ #if SOC_UART_LP_NUM >= 1
1145+ if (uart -> num >= SOC_UART_HP_NUM ) {
1146+ switch (clkSrc ) {
1147+ case UART_SCLK_XTAL : uart -> _uart_clock_source = LP_UART_SCLK_XTAL_D2 ; break ;
1148+ case UART_SCLK_RTC : uart -> _uart_clock_source = LP_UART_SCLK_LP_FAST ; break ;
1149+ case UART_SCLK_DEFAULT :
1150+ default : uart -> _uart_clock_source = LP_UART_SCLK_DEFAULT ;
1151+ }
1152+ } else
1153+ #endif
1154+ {
1155+ uart -> _uart_clock_source = clkSrc ;
1156+ }
1157+ //log_i("UART%d set clock source to %d", uart->num, uart->_uart_clock_source);
1158+ return true;
1159+ }
1160+
10871161void uartSetDebug (uart_t * uart ) {
10881162 // LP UART is not supported for debug
10891163 if (uart == NULL || uart -> num >= SOC_UART_HP_NUM ) {
0 commit comments