@@ -295,6 +295,125 @@ static bool _uartDetachBus_RTS(void *busptr) {
295295  return  _uartDetachPins (bus -> num , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE , bus -> _rtsPin );
296296}
297297
298+ static  bool  _uartTrySetIomuxPin (uart_port_t  uart_num , int  io_num , uint32_t  idx ) {
299+   // Store a pointer to the default pin, to optimize access to its fields. 
300+   const  uart_periph_sig_t  * upin  =  & uart_periph_signal [uart_num ].pins [idx ];
301+ 
302+   // In theory, if default_gpio is -1, iomux_func should also be -1, but let's be safe and test both. 
303+   if  (upin -> iomux_func  ==  -1  ||  upin -> default_gpio  ==  -1  ||  upin -> default_gpio  !=  io_num ) {
304+     return  false;
305+   }
306+ 
307+   // Assign the correct function to the GPIO. 
308+   assert (upin -> iomux_func  !=  -1 );
309+   if  (uart_num  <  SOC_UART_HP_NUM ) {
310+     gpio_iomux_out (io_num , upin -> iomux_func , false);
311+     // If the pin is input, we also have to redirect the signal, in order to bypass the GPIO matrix. 
312+     if  (upin -> input ) {
313+       gpio_iomux_in (io_num , upin -> signal );
314+     }
315+   }
316+ #if  (SOC_UART_LP_NUM  >= 1 ) &&  (SOC_RTCIO_PIN_COUNT  >= 1 )
317+   else  {
318+     if  (upin -> input ) {
319+       rtc_gpio_set_direction (io_num , RTC_GPIO_MODE_INPUT_ONLY );
320+     } else  {
321+       rtc_gpio_set_direction (io_num , RTC_GPIO_MODE_OUTPUT_ONLY );
322+     }
323+     rtc_gpio_init (io_num );
324+     rtc_gpio_iomux_func_sel (io_num , upin -> iomux_func );
325+   }
326+ #endif 
327+   return  true;
328+ }
329+ 
330+ static  esp_err_t  _uartInternalSetPin (uart_port_t  uart_num , int  tx_io_num , int  rx_io_num , int  rts_io_num , int  cts_io_num ) {
331+   // Since an IO cannot route peripheral signals via IOMUX and GPIO matrix at the same time, 
332+   // if tx and rx share the same IO, both signals need to be routed to IOs through GPIO matrix 
333+   bool  tx_rx_same_io  =  (tx_io_num  ==  rx_io_num );
334+ 
335+   // In the following statements, if the io_num is negative, no need to configure anything. 
336+   if  (tx_io_num  >= 0 ) {
337+ #if  CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND  ||  CONFIG_PM_SLP_DISABLE_GPIO 
338+     // In such case, IOs are going to switch to sleep configuration (isolate) when entering sleep for power saving reason 
339+     // But TX IO in isolate state could write garbled data to the other end 
340+     // Therefore, we should disable the switch of the TX pin to sleep configuration 
341+     gpio_sleep_sel_dis (tx_io_num );
342+ #endif 
343+     if  (tx_rx_same_io  ||  !_uartTrySetIomuxPin (uart_num , tx_io_num , SOC_UART_TX_PIN_IDX )) {
344+       if  (uart_num  <  SOC_UART_HP_NUM ) {
345+         gpio_func_sel (tx_io_num , PIN_FUNC_GPIO );
346+         esp_rom_gpio_connect_out_signal (tx_io_num , UART_PERIPH_SIGNAL (uart_num , SOC_UART_TX_PIN_IDX ), 0 , 0 );
347+         // output enable is set inside esp_rom_gpio_connect_out_signal func after the signal is connected 
348+         // (output enabled too early may cause unnecessary level change at the pad) 
349+       }
350+ #if  SOC_LP_GPIO_MATRIX_SUPPORTED 
351+       else  {
352+         rtc_gpio_init (tx_io_num );  // set as a LP_GPIO pin 
353+         lp_gpio_connect_out_signal (tx_io_num , UART_PERIPH_SIGNAL (uart_num , SOC_UART_TX_PIN_IDX ), 0 , 0 );
354+         // output enable is set inside lp_gpio_connect_out_signal func after the signal is connected 
355+       }
356+ #endif 
357+     }
358+   }
359+ 
360+   if  (rx_io_num  >= 0 ) {
361+ #if  CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND  ||  CONFIG_PM_SLP_DISABLE_GPIO 
362+     // In such case, IOs are going to switch to sleep configuration (isolate) when entering sleep for power saving reason 
363+     // But RX IO in isolate state could receive garbled data into FIFO, which is not desired 
364+     // Therefore, we should disable the switch of the RX pin to sleep configuration 
365+     gpio_sleep_sel_dis (rx_io_num );
366+ #endif 
367+     if  (tx_rx_same_io  ||  !_uartTrySetIomuxPin (uart_num , rx_io_num , SOC_UART_RX_PIN_IDX )) {
368+       if  (uart_num  <  SOC_UART_HP_NUM ) {
369+         gpio_input_enable (rx_io_num );
370+         esp_rom_gpio_connect_in_signal (rx_io_num , UART_PERIPH_SIGNAL (uart_num , SOC_UART_RX_PIN_IDX ), 0 );
371+       }
372+ #if  SOC_LP_GPIO_MATRIX_SUPPORTED 
373+       else  {
374+         rtc_gpio_mode_t  mode  =  (tx_rx_same_io  ? RTC_GPIO_MODE_INPUT_OUTPUT  : RTC_GPIO_MODE_INPUT_ONLY );
375+         rtc_gpio_set_direction (rx_io_num , mode );
376+         if  (!tx_rx_same_io ) {        // set the same pin again as a LP_GPIO will overwrite connected out_signal, not desired, so skip 
377+           rtc_gpio_init (rx_io_num );  // set as a LP_GPIO pin 
378+         }
379+         lp_gpio_connect_in_signal (rx_io_num , UART_PERIPH_SIGNAL (uart_num , SOC_UART_RX_PIN_IDX ), 0 );
380+       }
381+ #endif 
382+     }
383+   }
384+ 
385+   if  (rts_io_num  >= 0  &&  !_uartTrySetIomuxPin (uart_num , rts_io_num , SOC_UART_RTS_PIN_IDX )) {
386+     if  (uart_num  <  SOC_UART_HP_NUM ) {
387+       gpio_func_sel (rts_io_num , PIN_FUNC_GPIO );
388+       esp_rom_gpio_connect_out_signal (rts_io_num , UART_PERIPH_SIGNAL (uart_num , SOC_UART_RTS_PIN_IDX ), 0 , 0 );
389+       // output enable is set inside esp_rom_gpio_connect_out_signal func after the signal is connected 
390+     }
391+ #if  SOC_LP_GPIO_MATRIX_SUPPORTED 
392+     else  {
393+       rtc_gpio_init (rts_io_num );  // set as a LP_GPIO pin 
394+       lp_gpio_connect_out_signal (rts_io_num , UART_PERIPH_SIGNAL (uart_num , SOC_UART_RTS_PIN_IDX ), 0 , 0 );
395+       // output enable is set inside lp_gpio_connect_out_signal func after the signal is connected 
396+     }
397+ #endif 
398+   }
399+ 
400+   if  (cts_io_num  >= 0  &&  !_uartTrySetIomuxPin (uart_num , cts_io_num , SOC_UART_CTS_PIN_IDX )) {
401+     if  (uart_num  <  SOC_UART_HP_NUM ) {
402+       gpio_pullup_en (cts_io_num );
403+       gpio_input_enable (cts_io_num );
404+       esp_rom_gpio_connect_in_signal (cts_io_num , UART_PERIPH_SIGNAL (uart_num , SOC_UART_CTS_PIN_IDX ), 0 );
405+     }
406+ #if  SOC_LP_GPIO_MATRIX_SUPPORTED 
407+     else  {
408+       rtc_gpio_set_direction (cts_io_num , RTC_GPIO_MODE_INPUT_ONLY );
409+       rtc_gpio_init (cts_io_num );  // set as a LP_GPIO pin 
410+       lp_gpio_connect_in_signal (cts_io_num , UART_PERIPH_SIGNAL (uart_num , SOC_UART_CTS_PIN_IDX ), 0 );
411+     }
412+ #endif 
413+   }
414+   return  ESP_OK ;
415+ }
416+ 
298417// Attach function for UART 
299418// connects the IO Pad, set Paripheral Manager and internal UART structure data 
300419static  bool  _uartAttachPins (uint8_t  uart_num , int8_t  rxPin , int8_t  txPin , int8_t  ctsPin , int8_t  rtsPin ) {
@@ -307,7 +426,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
307426  //log_v("attaching UART%d pins: prev,new RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num, 
308427  //        uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); 
309428
310-   // IDF uart_set_pin () checks if the pin is used within LP UART and if it is a valid RTC IO pin 
429+   // IDF _uartInternalSetPin () checks if the pin is used within LP UART and if it is a valid RTC IO pin 
311430  // No need for Arduino Layer to check it again 
312431  bool  retCode  =  true;
313432  if  (rxPin  >= 0 ) {
@@ -316,7 +435,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
316435      perimanClearPinBus (rxPin );
317436    }
318437    // connect RX Pad 
319-     bool  ret  =  ESP_OK  ==  uart_set_pin (uart -> num , UART_PIN_NO_CHANGE , rxPin , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE );
438+     bool  ret  =  ESP_OK  ==  _uartInternalSetPin (uart -> num , UART_PIN_NO_CHANGE , rxPin , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE );
320439#if  SOC_UART_LP_NUM  >= 1 
321440    if  (ret  &&  uart_num  >= SOC_UART_HP_NUM ) {  // it is a LP UART NUM 
322441      ret  &= lp_uart_config_io (uart -> num , rxPin , RTC_GPIO_MODE_INPUT_ONLY , SOC_UART_RX_PIN_IDX );
@@ -339,7 +458,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
339458      perimanClearPinBus (txPin );
340459    }
341460    // connect TX Pad 
342-     bool  ret  =  ESP_OK  ==  uart_set_pin (uart -> num , txPin , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE );
461+     bool  ret  =  ESP_OK  ==  _uartInternalSetPin (uart -> num , txPin , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE );
343462#if  SOC_UART_LP_NUM  >= 1 
344463    if  (ret  &&  uart_num  >= SOC_UART_HP_NUM ) {  // it is a LP UART NUM 
345464      ret  &= lp_uart_config_io (uart -> num , txPin , RTC_GPIO_MODE_OUTPUT_ONLY , SOC_UART_TX_PIN_IDX );
@@ -362,7 +481,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
362481      perimanClearPinBus (ctsPin );
363482    }
364483    // connect CTS Pad 
365-     bool  ret  =  ESP_OK  ==  uart_set_pin (uart -> num , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE , ctsPin );
484+     bool  ret  =  ESP_OK  ==  _uartInternalSetPin (uart -> num , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE , ctsPin );
366485#if  SOC_UART_LP_NUM  >= 1 
367486    if  (ret  &&  uart_num  >= SOC_UART_HP_NUM ) {  // it is a LP UART NUM 
368487      ret  &= lp_uart_config_io (uart -> num , ctsPin , RTC_GPIO_MODE_INPUT_ONLY , SOC_UART_CTS_PIN_IDX );
@@ -385,7 +504,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
385504      perimanClearPinBus (rtsPin );
386505    }
387506    // connect RTS Pad 
388-     bool  ret  =  ESP_OK  ==  uart_set_pin (uart -> num , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE , rtsPin , UART_PIN_NO_CHANGE );
507+     bool  ret  =  ESP_OK  ==  _uartInternalSetPin (uart -> num , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE , rtsPin , UART_PIN_NO_CHANGE );
389508#if  SOC_UART_LP_NUM  >= 1 
390509    if  (ret  &&  uart_num  >= SOC_UART_HP_NUM ) {  // it is a LP UART NUM 
391510      ret  &= lp_uart_config_io (uart -> num , rtsPin , RTC_GPIO_MODE_OUTPUT_ONLY , SOC_UART_RTS_PIN_IDX );
@@ -1398,11 +1517,13 @@ void uart_internal_loopback(uint8_t uartNum, int8_t rxPin) {
13981517    log_e ("UART%d is not supported for loopback or RX pin %d is invalid." , uartNum , rxPin );
13991518    return ;
14001519  }
1520+ #if  0   // leave this code here for future reference and need 
14011521  // forces rxPin to use GPIO Matrix and setup the pin to receive UART TX Signal - IDF 5.4.1 Change with uart_release_pin() 
14021522  gpio_func_sel ((gpio_num_t )rxPin , PIN_FUNC_GPIO );
14031523  gpio_pullup_en ((gpio_num_t )rxPin );
14041524  gpio_input_enable ((gpio_num_t )rxPin );
14051525  esp_rom_gpio_connect_in_signal (rxPin , uart_periph_signal [uartNum ].pins [SOC_UART_RX_PIN_IDX ].signal , false);
1526+ #endif 
14061527  esp_rom_gpio_connect_out_signal (rxPin , uart_periph_signal [uartNum ].pins [SOC_UART_TX_PIN_IDX ].signal , false, false);
14071528}
14081529
0 commit comments