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