Browse Source

fix set `UART_FORCE_XOFF` can't stop new Tx request issue

Li Shuai 5 năm trước cách đây
mục cha
commit
a43de3a44b

+ 14 - 24
components/esp_system/sleep_modes.c

@@ -232,20 +232,17 @@ static void IRAM_ATTR flush_uarts(void)
 static void IRAM_ATTR suspend_uarts(void)
 {
     for (int i = 0; i < SOC_UART_NUM; ++i) {
-#ifdef CONFIG_IDF_TARGET_ESP32
-        /* Note: Set `UART_FORCE_XOFF` can't stop new Tx request. */
-        REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF);
-        while (REG_GET_FIELD(UART_STATUS_REG(i), UART_ST_UTX_OUT) != 0) {
-            ;
-        }
-#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
-        if (periph_ll_periph_enabled(PERIPH_UART0_MODULE + i)) {
-            REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XON);
-            REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_SW_FLOW_CON_EN | UART_FORCE_XOFF);
-            while (REG_GET_FIELD(UART_FSM_STATUS_REG(i), UART_ST_UTX_OUT) != 0) {
-                ;
-            }
-        }
+#ifndef CONFIG_IDF_TARGET_ESP32
+        if (!periph_ll_periph_enabled(PERIPH_UART0_MODULE + i)) continue;
+#endif
+        uart_ll_force_xoff(i);
+#if SOC_UART_SUPPORT_FSM_TX_WAIT_SEND
+        uint32_t uart_fsm = 0;
+        do {
+            uart_fsm = uart_ll_get_fsm_status(i);
+        } while (!(uart_fsm == UART_FSM_IDLE || uart_fsm == UART_FSM_TX_WAIT_SEND));
+#else
+        while (uart_ll_get_fsm_status(i) != 0) {}
 #endif
     }
 }
@@ -253,17 +250,10 @@ static void IRAM_ATTR suspend_uarts(void)
 static void IRAM_ATTR resume_uarts(void)
 {
     for (int i = 0; i < SOC_UART_NUM; ++i) {
-#ifdef CONFIG_IDF_TARGET_ESP32
-        REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF);
-        REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XON);
-        REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XON);
-#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
-        if (periph_ll_periph_enabled(PERIPH_UART0_MODULE + i)) {
-            REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF);
-            REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XON);
-            REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_SW_FLOW_CON_EN | UART_FORCE_XON);
-        }
+#ifndef CONFIG_IDF_TARGET_ESP32
+        if (!periph_ll_periph_enabled(PERIPH_UART0_MODULE + i)) continue;
 #endif
+        uart_ll_force_xon(i);
     }
 }
 

+ 39 - 0
components/hal/esp32/include/hal/uart_ll.h

@@ -894,6 +894,45 @@ static inline uint16_t uart_ll_max_tout_thrd(uart_dev_t *hw)
     return tout_thrd;
 }
 
+/**
+ * @brief  Force UART xoff.
+ *
+ * @param  uart_num UART port number, the max port number is (UART_NUM_MAX -1).
+ *
+ * @return None.
+ */
+static inline void uart_ll_force_xoff(uart_port_t uart_num)
+{
+    /* Note: Set `UART_FORCE_XOFF` can't stop new Tx request. */
+    REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XOFF);
+}
+
+/**
+ * @brief  Force UART xon.
+ *
+ * @param  uart_num UART port number, the max port number is (UART_NUM_MAX -1).
+ *
+ * @return None.
+ */
+static inline void uart_ll_force_xon(uart_port_t uart_num)
+{
+    REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XOFF);
+    REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
+    REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
+}
+
+/**
+ * @brief  Get UART final state machine status.
+ *
+ * @param  uart_num UART port number, the max port number is (UART_NUM_MAX -1).
+ *
+ * @return UART module FSM status.
+ */
+static inline uint32_t uart_ll_get_fsm_status(uart_port_t uart_num)
+{
+    return REG_GET_FIELD(UART_STATUS_REG(uart_num), UART_ST_UTX_OUT);
+}
+
 #undef UART_LL_TOUT_REF_FACTOR_DEFAULT
 
 #ifdef __cplusplus

+ 41 - 0
components/hal/esp32c3/include/hal/uart_ll.h

@@ -884,6 +884,47 @@ static inline uint16_t uart_ll_max_tout_thrd(uart_dev_t *hw)
     return UART_RX_TOUT_THRHD_V;
 }
 
+/**
+ * @brief  Force UART xoff.
+ *
+ * @param  uart_num UART port number, the max port number is (UART_NUM_MAX -1).
+ *
+ * @return None.
+ */
+static inline void uart_ll_force_xoff(uart_port_t uart_num)
+{
+    REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
+    REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XOFF);
+    REG_SET_BIT(UART_ID_REG(uart_num), UART_UPDATE);
+}
+
+/**
+ * @brief  Force UART xon.
+ *
+ * @param  uart_num UART port number, the max port number is (UART_NUM_MAX -1).
+ *
+ * @return None.
+ */
+static inline void uart_ll_force_xon(uart_port_t uart_num)
+{
+    REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XOFF);
+    REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
+    REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XON);
+    REG_SET_BIT(UART_ID_REG(uart_num), UART_UPDATE);
+}
+
+/**
+ * @brief  Get UART final state machine status.
+ *
+ * @param  uart_num UART port number, the max port number is (UART_NUM_MAX -1).
+ *
+ * @return UART module FSM status.
+ */
+static inline uint32_t uart_ll_get_fsm_status(uart_port_t uart_num)
+{
+    return REG_GET_FIELD(UART_FSM_STATUS_REG(uart_num), UART_ST_UTX_OUT);
+}
+
 #ifdef __cplusplus
 }
 #endif

+ 39 - 0
components/hal/esp32s2/include/hal/uart_ll.h

@@ -826,6 +826,45 @@ static inline uint16_t uart_ll_max_tout_thrd(uart_dev_t *hw)
     return UART_RX_TOUT_THRHD_V;
 }
 
+/**
+ * @brief  Force UART xoff.
+ *
+ * @param  uart_num UART port number, the max port number is (UART_NUM_MAX -1).
+ *
+ * @return None.
+ */
+static inline void uart_ll_force_xoff(uart_port_t uart_num)
+{
+    REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
+    REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XOFF);
+}
+
+/**
+ * @brief  Force UART xon.
+ *
+ * @param  uart_num UART port number, the max port number is (UART_NUM_MAX -1).
+ *
+ * @return None.
+ */
+static inline void uart_ll_force_xon(uart_port_t uart_num)
+{
+    REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XOFF);
+    REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
+    REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XON);
+}
+
+/**
+ * @brief  Get UART final state machine status.
+ *
+ * @param  uart_num UART port number, the max port number is (UART_NUM_MAX -1).
+ *
+ * @return UART module FSM status.
+ */
+static inline uint32_t uart_ll_get_fsm_status(uart_port_t uart_num)
+{
+    return REG_GET_FIELD(UART_FSM_STATUS_REG(uart_num), UART_ST_UTX_OUT);
+}
+
 #ifdef __cplusplus
 }
 #endif

+ 39 - 0
components/hal/esp32s3/include/hal/uart_ll.h

@@ -852,6 +852,45 @@ static inline uint16_t uart_ll_max_tout_thrd(uart_dev_t *hw)
     return UART_RX_TOUT_THRHD_V;
 }
 
+/**
+ * @brief  Force UART xoff.
+ *
+ * @param  uart_num UART port number, the max port number is (UART_NUM_MAX -1).
+ *
+ * @return None.
+ */
+static inline void uart_ll_force_xoff(uart_port_t uart_num)
+{
+    REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
+    REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XOFF);
+}
+
+/**
+ * @brief  Force UART xon.
+ *
+ * @param  uart_num UART port number, the max port number is (UART_NUM_MAX -1).
+ *
+ * @return None.
+ */
+static inline void uart_ll_force_xon(uart_port_t uart_num)
+{
+    REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XOFF);
+    REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
+    REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XON);
+}
+
+/**
+ * @brief  Get UART final state machine status.
+ *
+ * @param  uart_num UART port number, the max port number is (UART_NUM_MAX -1).
+ *
+ * @return UART module FSM status.
+ */
+static inline uint32_t uart_ll_get_fsm_status(uart_port_t uart_num)
+{
+    return REG_GET_FIELD(UART_FSM_STATUS_REG(uart_num), UART_ST_UTX_OUT);
+}
+
 #ifdef __cplusplus
 }
 #endif

+ 5 - 0
components/soc/esp32c3/include/soc/uart_caps.h

@@ -27,6 +27,11 @@ extern "C" {
 // ESP32-C3 have 2 UART
 #define SOC_UART_NUM           (2)
 
+// UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled
+#define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND   (1)
+#define UART_FSM_IDLE                       (0x0)
+#define UART_FSM_TX_WAIT_SEND               (0xf)
+
 #ifdef __cplusplus
 }
 #endif