-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\r
-//\r
-// Licensed under the Apache License, Version 2.0 (the "License");\r
-// you may not use this file except in compliance with the License.\r
-// You may obtain a copy of the License at\r
-\r
-// http://www.apache.org/licenses/LICENSE-2.0\r
-//\r
-// Unless required by applicable law or agreed to in writing, software\r
-// distributed under the License is distributed on an "AS IS" BASIS,\r
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-// See the License for the specific language governing permissions and\r
-// limitations under the License.\r
-\r
-#ifndef _DRIVER_UART_H_\r
-#define _DRIVER_UART_H_\r
-\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-#include "soc/uart_reg.h"\r
-#include "soc/uart_struct.h"\r
-#include "esp_err.h"\r
-#include "driver/periph_ctrl.h"\r
-#include "freertos/FreeRTOS.h"\r
-#include "freertos/semphr.h"\r
-#include "freertos/xtensa_api.h"\r
-#include "freertos/task.h"\r
-#include "freertos/queue.h"\r
-#include "freertos/ringbuf.h"\r
-#include <esp_types.h>\r
-\r
-#define UART_FIFO_LEN (128) /*!< Length of the hardware FIFO buffers */\r
-#define UART_INTR_MASK 0x1ff /*!< mask of all UART interrupts */\r
-#define UART_LINE_INV_MASK (0x3f << 19) /*!< TBD */\r
-#define UART_BITRATE_MAX 5000000 /*!< Max bit rate supported by UART */\r
-#define UART_PIN_NO_CHANGE (-1) /*!< Constant for uart_set_pin function which indicates that UART pin should not be changed */\r
-\r
-#define UART_INVERSE_DISABLE (0x0) /*!< Disable UART signal inverse*/\r
-#define UART_INVERSE_RXD (UART_RXD_INV_M) /*!< UART RXD input inverse*/\r
-#define UART_INVERSE_CTS (UART_CTS_INV_M) /*!< UART CTS input inverse*/\r
-#define UART_INVERSE_TXD (UART_TXD_INV_M) /*!< UART TXD output inverse*/\r
-#define UART_INVERSE_RTS (UART_RTS_INV_M) /*!< UART RTS output inverse*/\r
-\r
-/**\r
- * @brief UART word length constants\r
- */\r
-typedef enum {\r
- UART_DATA_5_BITS = 0x0, /*!< word length: 5bits*/\r
- UART_DATA_6_BITS = 0x1, /*!< word length: 6bits*/\r
- UART_DATA_7_BITS = 0x2, /*!< word length: 7bits*/\r
- UART_DATA_8_BITS = 0x3, /*!< word length: 8bits*/\r
- UART_DATA_BITS_MAX = 0X4,\r
-} uart_word_length_t;\r
-\r
-/**\r
- * @brief UART stop bits number\r
- */\r
-typedef enum {\r
- UART_STOP_BITS_1 = 0x1, /*!< stop bit: 1bit*/\r
- UART_STOP_BITS_1_5 = 0x2, /*!< stop bit: 1.5bits*/\r
- UART_STOP_BITS_2 = 0x3, /*!< stop bit: 2bits*/\r
- UART_STOP_BITS_MAX = 0x4,\r
-} uart_stop_bits_t;\r
-\r
-/**\r
- * @brief UART peripheral number\r
- */\r
-typedef enum {\r
- UART_NUM_0 = 0x0, /*!< UART base address 0x3ff40000*/\r
- UART_NUM_1 = 0x1, /*!< UART base address 0x3ff50000*/\r
- UART_NUM_2 = 0x2, /*!< UART base address 0x3ff6E000*/\r
- UART_NUM_MAX,\r
-} uart_port_t;\r
-\r
-/**\r
- * @brief UART parity constants\r
- */\r
-typedef enum {\r
- UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/\r
- UART_PARITY_EVEN = 0x2, /*!< Enable UART even parity*/\r
- UART_PARITY_ODD = 0x3 /*!< Enable UART odd parity*/\r
-} uart_parity_t;\r
-\r
-/**\r
- * @brief UART hardware flow control modes\r
- */\r
-typedef enum {\r
- UART_HW_FLOWCTRL_DISABLE = 0x0, /*!< disable hardware flow control*/\r
- UART_HW_FLOWCTRL_RTS = 0x1, /*!< enable RX hardware flow control (rts)*/\r
- UART_HW_FLOWCTRL_CTS = 0x2, /*!< enable TX hardware flow control (cts)*/\r
- UART_HW_FLOWCTRL_CTS_RTS = 0x3, /*!< enable hardware flow control*/\r
- UART_HW_FLOWCTRL_MAX = 0x4,\r
-} uart_hw_flowcontrol_t;\r
-\r
-/**\r
- * @brief UART configuration parameters for uart_param_config function\r
- */\r
-typedef struct {\r
- int baud_rate; /*!< UART baudrate*/\r
- uart_word_length_t data_bits; /*!< UART byte size*/\r
- uart_parity_t parity; /*!< UART parity mode*/\r
- uart_stop_bits_t stop_bits; /*!< UART stop bits*/\r
- uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode(cts/rts)*/\r
- uint8_t rx_flow_ctrl_thresh ; /*!< UART HW RTS threshold*/\r
-} uart_config_t;\r
-\r
-/**\r
- * @brief UART interrupt configuration parameters for uart_intr_config function\r
- */\r
-typedef struct {\r
- uint32_t intr_enable_mask; /*!< UART interrupt enable mask, choose from UART_XXXX_INT_ENA_M under UART_INT_ENA_REG(i), connect with bit-or operator*/\r
- uint8_t rx_timeout_thresh; /*!< UART timeout interrupt threshold(unit: time of sending one byte)*/\r
- uint8_t txfifo_empty_intr_thresh; /*!< UART TX empty interrupt threshold.*/\r
- uint8_t rxfifo_full_thresh; /*!< UART RX full interrupt threshold.*/\r
-} uart_intr_config_t;\r
-\r
-/**\r
- * @brief UART event types used in the ringbuffer\r
- */\r
-typedef enum {\r
- UART_DATA, /*!< UART data event*/\r
- UART_BREAK, /*!< UART break event*/\r
- UART_BUFFER_FULL, /*!< UART RX buffer full event*/\r
- UART_FIFO_OVF, /*!< UART FIFO overflow event*/\r
- UART_FRAME_ERR, /*!< UART RX frame error event*/\r
- UART_PARITY_ERR, /*!< UART RX parity event*/\r
- UART_DATA_BREAK, /*!< UART TX data and break event*/\r
- UART_EVENT_MAX, /*!< UART event max index*/\r
-} uart_event_type_t;\r
-\r
-/**\r
- * @brief Event structure used in UART event queue\r
- */\r
-typedef struct {\r
- uart_event_type_t type; /*!< UART event type */\r
- size_t size; /*!< UART data size for UART_DATA event*/\r
-} uart_event_t;\r
-\r
-/**\r
- * @brief Set UART data bits.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param data_bit UART data bits\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit);\r
-\r
-/**\r
- * @brief Get UART data bits.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param data_bit Pointer to accept value of UART data bits.\r
- *\r
- * @return\r
- * - ESP_FAIL Parameter error\r
- * - ESP_OK Success, result will be put in (*data_bit)\r
- */\r
-esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit);\r
-\r
-/**\r
- * @brief Set UART stop bits.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param stop_bits UART stop bits\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Fail\r
- */\r
-esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bits);\r
-\r
-/**\r
- * @brief Set UART stop bits.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param stop_bits Pointer to accept value of UART stop bits.\r
- *\r
- * @return\r
- * - ESP_FAIL Parameter error\r
- * - ESP_OK Success, result will be put in (*stop_bit)\r
- */\r
-esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bits);\r
-\r
-/**\r
- * @brief Set UART parity.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param parity_mode the enum of uart parity configuration\r
- *\r
- * @return\r
- * - ESP_FAIL Parameter error\r
- * - ESP_OK Success\r
- */\r
-esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode);\r
-\r
-/**\r
- * @brief Get UART parity mode.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param parity_mode Pointer to accept value of UART parity mode.\r
- *\r
- * @return\r
- * - ESP_FAIL Parameter error\r
- * - ESP_OK Success, result will be put in (*parity_mode)\r
- *\r
- */\r
-esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode);\r
-\r
-/**\r
- * @brief Set UART baud rate.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param baudrate UART baud rate.\r
- *\r
- * @return\r
- * - ESP_FAIL Parameter error\r
- * - ESP_OK Success\r
- */\r
-esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baudrate);\r
-\r
-/**\r
- * @brief Get UART bit-rate.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param baudrate Pointer to accept value of UART baud rate\r
- *\r
- * @return\r
- * - ESP_FAIL Parameter error\r
- * - ESP_OK Success, result will be put in (*baudrate)\r
- *\r
- */\r
-esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate);\r
-\r
-/**\r
- * @brief Set UART line inverse mode\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param inverse_mask Choose the wires that need to be inverted.\r
- * Inverse_mask should be chosen from UART_INVERSE_RXD/UART_INVERSE_TXD/UART_INVERSE_RTS/UART_INVERSE_CTS, combine with OR operation.\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask);\r
-\r
-/**\r
- * @brief Set hardware flow control.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param flow_ctrl Hardware flow control mode\r
- * @param rx_thresh Threshold of Hardware RX flow control(0 ~ UART_FIFO_LEN).\r
- * Only when UART_HW_FLOWCTRL_RTS is set, will the rx_thresh value be set.\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh);\r
-\r
-/**\r
- * @brief Get hardware flow control mode\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param flow_ctrl Option for different flow control mode.\r
- *\r
- * @return\r
- * - ESP_FAIL Parameter error\r
- * - ESP_OK Success, result will be put in (*flow_ctrl)\r
- */\r
-esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl);\r
-\r
-/**\r
- * @brief Clear UART interrupt status\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param clr_mask Bit mask of the status that to be cleared.\r
- * enable_mask should be chosen from the fields of register UART_INT_CLR_REG.\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask);\r
-\r
-/**\r
- * @brief Set UART interrupt enable\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param enable_mask Bit mask of the enable bits.\r
- * enable_mask should be chosen from the fields of register UART_INT_ENA_REG.\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask);\r
-\r
-/**\r
- * @brief Clear UART interrupt enable bits\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param disable_mask Bit mask of the disable bits.\r
- * disable_mask should be chosen from the fields of register UART_INT_ENA_REG.\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask);\r
-\r
-\r
-/**\r
- * @brief Enable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_enable_rx_intr(uart_port_t uart_num);\r
-\r
-/**\r
- * @brief Disable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_disable_rx_intr(uart_port_t uart_num);\r
-\r
-/**\r
- * @brief Disable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_disable_tx_intr(uart_port_t uart_num);\r
-\r
-/**\r
- * @brief Enable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param enable 1: enable; 0: disable\r
- * @param thresh Threshold of TX interrupt, 0 ~ UART_FIFO_LEN\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh);\r
-\r
-/**\r
- * @brief register UART interrupt handler(ISR).\r
- *\r
- * @note UART ISR handler will be attached to the same CPU core that this function is running on.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param fn Interrupt handler function.\r
- * @param arg parameter for handler function\r
+// Copyright 2015-2016 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.
+// You may obtain a copy of the License at
+
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _DRIVER_UART_H_
+#define _DRIVER_UART_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "soc/uart_reg.h"
+#include "soc/uart_struct.h"
+#include "esp_err.h"
+#include "driver/periph_ctrl.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/xtensa_api.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/ringbuf.h"
+#include <esp_types.h>
+
+#define UART_FIFO_LEN (128) /*!< Length of the hardware FIFO buffers */
+#define UART_INTR_MASK 0x1ff /*!< mask of all UART interrupts */
+#define UART_LINE_INV_MASK (0x3f << 19) /*!< TBD */
+#define UART_BITRATE_MAX 5000000 /*!< Max bit rate supported by UART */
+#define UART_PIN_NO_CHANGE (-1) /*!< Constant for uart_set_pin function which indicates that UART pin should not be changed */
+
+#define UART_INVERSE_DISABLE (0x0) /*!< Disable UART signal inverse*/
+#define UART_INVERSE_RXD (UART_RXD_INV_M) /*!< UART RXD input inverse*/
+#define UART_INVERSE_CTS (UART_CTS_INV_M) /*!< UART CTS input inverse*/
+#define UART_INVERSE_TXD (UART_TXD_INV_M) /*!< UART TXD output inverse*/
+#define UART_INVERSE_RTS (UART_RTS_INV_M) /*!< UART RTS output inverse*/
+
+/**
+ * @brief UART word length constants
+ */
+typedef enum {
+ UART_DATA_5_BITS = 0x0, /*!< word length: 5bits*/
+ UART_DATA_6_BITS = 0x1, /*!< word length: 6bits*/
+ UART_DATA_7_BITS = 0x2, /*!< word length: 7bits*/
+ UART_DATA_8_BITS = 0x3, /*!< word length: 8bits*/
+ UART_DATA_BITS_MAX = 0X4,
+} uart_word_length_t;
+
+/**
+ * @brief UART stop bits number
+ */
+typedef enum {
+ UART_STOP_BITS_1 = 0x1, /*!< stop bit: 1bit*/
+ UART_STOP_BITS_1_5 = 0x2, /*!< stop bit: 1.5bits*/
+ UART_STOP_BITS_2 = 0x3, /*!< stop bit: 2bits*/
+ UART_STOP_BITS_MAX = 0x4,
+} uart_stop_bits_t;
+
+/**
+ * @brief UART peripheral number
+ */
+typedef enum {
+ UART_NUM_0 = 0x0, /*!< UART base address 0x3ff40000*/
+ UART_NUM_1 = 0x1, /*!< UART base address 0x3ff50000*/
+ UART_NUM_2 = 0x2, /*!< UART base address 0x3ff6E000*/
+ UART_NUM_MAX,
+} uart_port_t;
+
+/**
+ * @brief UART parity constants
+ */
+typedef enum {
+ UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/
+ UART_PARITY_EVEN = 0x2, /*!< Enable UART even parity*/
+ UART_PARITY_ODD = 0x3 /*!< Enable UART odd parity*/
+} uart_parity_t;
+
+/**
+ * @brief UART hardware flow control modes
+ */
+typedef enum {
+ UART_HW_FLOWCTRL_DISABLE = 0x0, /*!< disable hardware flow control*/
+ UART_HW_FLOWCTRL_RTS = 0x1, /*!< enable RX hardware flow control (rts)*/
+ UART_HW_FLOWCTRL_CTS = 0x2, /*!< enable TX hardware flow control (cts)*/
+ UART_HW_FLOWCTRL_CTS_RTS = 0x3, /*!< enable hardware flow control*/
+ UART_HW_FLOWCTRL_MAX = 0x4,
+} uart_hw_flowcontrol_t;
+
+/**
+ * @brief UART configuration parameters for uart_param_config function
+ */
+typedef struct {
+ int baud_rate; /*!< UART baudrate*/
+ uart_word_length_t data_bits; /*!< UART byte size*/
+ uart_parity_t parity; /*!< UART parity mode*/
+ uart_stop_bits_t stop_bits; /*!< UART stop bits*/
+ uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode(cts/rts)*/
+ uint8_t rx_flow_ctrl_thresh ; /*!< UART HW RTS threshold*/
+} uart_config_t;
+
+/**
+ * @brief UART interrupt configuration parameters for uart_intr_config function
+ */
+typedef struct {
+ uint32_t intr_enable_mask; /*!< UART interrupt enable mask, choose from UART_XXXX_INT_ENA_M under UART_INT_ENA_REG(i), connect with bit-or operator*/
+ uint8_t rx_timeout_thresh; /*!< UART timeout interrupt threshold(unit: time of sending one byte)*/
+ uint8_t txfifo_empty_intr_thresh; /*!< UART TX empty interrupt threshold.*/
+ uint8_t rxfifo_full_thresh; /*!< UART RX full interrupt threshold.*/
+} uart_intr_config_t;
+
+/**
+ * @brief UART event types used in the ringbuffer
+ */
+typedef enum {
+ UART_DATA, /*!< UART data event*/
+ UART_BREAK, /*!< UART break event*/
+ UART_BUFFER_FULL, /*!< UART RX buffer full event*/
+ UART_FIFO_OVF, /*!< UART FIFO overflow event*/
+ UART_FRAME_ERR, /*!< UART RX frame error event*/
+ UART_PARITY_ERR, /*!< UART RX parity event*/
+ UART_DATA_BREAK, /*!< UART TX data and break event*/
+ UART_EVENT_MAX, /*!< UART event max index*/
+} uart_event_type_t;
+
+/**
+ * @brief Event structure used in UART event queue
+ */
+typedef struct {
+ uart_event_type_t type; /*!< UART event type */
+ size_t size; /*!< UART data size for UART_DATA event*/
+} uart_event_t;
+
+/**
+ * @brief Set UART data bits.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param data_bit UART data bits
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit);
+
+/**
+ * @brief Get UART data bits.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param data_bit Pointer to accept value of UART data bits.
+ *
+ * @return
+ * - ESP_FAIL Parameter error
+ * - ESP_OK Success, result will be put in (*data_bit)
+ */
+esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit);
+
+/**
+ * @brief Set UART stop bits.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param stop_bits UART stop bits
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Fail
+ */
+esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bits);
+
+/**
+ * @brief Set UART stop bits.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param stop_bits Pointer to accept value of UART stop bits.
+ *
+ * @return
+ * - ESP_FAIL Parameter error
+ * - ESP_OK Success, result will be put in (*stop_bit)
+ */
+esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bits);
+
+/**
+ * @brief Set UART parity.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param parity_mode the enum of uart parity configuration
+ *
+ * @return
+ * - ESP_FAIL Parameter error
+ * - ESP_OK Success
+ */
+esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode);
+
+/**
+ * @brief Get UART parity mode.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param parity_mode Pointer to accept value of UART parity mode.
+ *
+ * @return
+ * - ESP_FAIL Parameter error
+ * - ESP_OK Success, result will be put in (*parity_mode)
+ *
+ */
+esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode);
+
+/**
+ * @brief Set UART baud rate.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param baudrate UART baud rate.
+ *
+ * @return
+ * - ESP_FAIL Parameter error
+ * - ESP_OK Success
+ */
+esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baudrate);
+
+/**
+ * @brief Get UART bit-rate.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param baudrate Pointer to accept value of UART baud rate
+ *
+ * @return
+ * - ESP_FAIL Parameter error
+ * - ESP_OK Success, result will be put in (*baudrate)
+ *
+ */
+esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate);
+
+/**
+ * @brief Set UART line inverse mode
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param inverse_mask Choose the wires that need to be inverted.
+ * Inverse_mask should be chosen from UART_INVERSE_RXD/UART_INVERSE_TXD/UART_INVERSE_RTS/UART_INVERSE_CTS, combine with OR operation.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask);
+
+/**
+ * @brief Set hardware flow control.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param flow_ctrl Hardware flow control mode
+ * @param rx_thresh Threshold of Hardware RX flow control(0 ~ UART_FIFO_LEN).
+ * Only when UART_HW_FLOWCTRL_RTS is set, will the rx_thresh value be set.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh);
+
+/**
+ * @brief Get hardware flow control mode
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param flow_ctrl Option for different flow control mode.
+ *
+ * @return
+ * - ESP_FAIL Parameter error
+ * - ESP_OK Success, result will be put in (*flow_ctrl)
+ */
+esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl);
+
+/**
+ * @brief Clear UART interrupt status
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param clr_mask Bit mask of the status that to be cleared.
+ * enable_mask should be chosen from the fields of register UART_INT_CLR_REG.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask);
+
+/**
+ * @brief Set UART interrupt enable
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param enable_mask Bit mask of the enable bits.
+ * enable_mask should be chosen from the fields of register UART_INT_ENA_REG.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask);
+
+/**
+ * @brief Clear UART interrupt enable bits
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param disable_mask Bit mask of the disable bits.
+ * disable_mask should be chosen from the fields of register UART_INT_ENA_REG.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask);
+
+
+/**
+ * @brief Enable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_enable_rx_intr(uart_port_t uart_num);
+
+/**
+ * @brief Disable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_disable_rx_intr(uart_port_t uart_num);
+
+/**
+ * @brief Disable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_disable_tx_intr(uart_port_t uart_num);
+
+/**
+ * @brief Enable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param enable 1: enable; 0: disable
+ * @param thresh Threshold of TX interrupt, 0 ~ UART_FIFO_LEN
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh);
+
+/**
+ * @brief register UART interrupt handler(ISR).
+ *
+ * @note UART ISR handler will be attached to the same CPU core that this function is running on.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param fn Interrupt handler function.
+ * @param arg parameter for handler function
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
- * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. \r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags);\r
-\r
-
-/**\r
- * @brief Free UART interrupt handler registered by uart_isr_register. Must be called on the same core as\r
- * uart_isr_register was called.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
+ * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags);
+
+
+/**
+ * @brief Free UART interrupt handler registered by uart_isr_register. Must be called on the same core as
+ * uart_isr_register was called.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
esp_err_t uart_isr_free(uart_port_t uart_num);
-\r
-/**\r
- * @brief Set UART pin number\r
- *\r
- * @note Internal signal can be output to multiple GPIO pads.\r
- * Only one GPIO pad can connect with input signal.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param tx_io_num UART TX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.\r
- * @param rx_io_num UART RX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.\r
- * @param rts_io_num UART RTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.\r
- * @param cts_io_num UART CTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num);\r
-\r
-/**\r
- * @brief UART set RTS level (before inverse)\r
- * UART rx hardware flow control should not be set.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param level 1: RTS output low(active); 0: RTS output high(block)\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_set_rts(uart_port_t uart_num, int level);\r
-\r
-/**\r
- * @brief UART set DTR level (before inverse)\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param level 1: DTR output low; 0: DTR output high\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_set_dtr(uart_port_t uart_num, int level);\r
-\r
-/**\r
-* @brief UART parameter configure\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param uart_config UART parameter settings\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config);\r
-\r
-/**\r
-* @brief UART interrupt configure\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param intr_conf UART interrupt settings\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf);\r
-\r
-/**\r
- * @brief Install UART driver.\r
- *\r
- * UART ISR handler will be attached to the same CPU core that this function is running on.\r
- * Users should know that which CPU is running and then pick a INUM that is not used by system.\r
- * We can find the information of INUM and interrupt level in soc.h.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param rx_buffer_size UART RX ring buffer size\r
- * @param tx_buffer_size UART TX ring buffer size.\r
- * If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out..\r
- * @param queue_size UART event queue size/depth.\r
- * @param uart_queue UART event queue handle, if set NULL, driver will not use an event queue.\r
+
+/**
+ * @brief Set UART pin number
+ *
+ * @note Internal signal can be output to multiple GPIO pads.
+ * Only one GPIO pad can connect with input signal.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param tx_io_num UART TX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
+ * @param rx_io_num UART RX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
+ * @param rts_io_num UART RTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
+ * @param cts_io_num UART CTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num);
+
+/**
+ * @brief UART set RTS level (before inverse)
+ * UART rx hardware flow control should not be set.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param level 1: RTS output low(active); 0: RTS output high(block)
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_set_rts(uart_port_t uart_num, int level);
+
+/**
+ * @brief UART set DTR level (before inverse)
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param level 1: DTR output low; 0: DTR output high
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_set_dtr(uart_port_t uart_num, int level);
+
+/**
+* @brief UART parameter configure
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param uart_config UART parameter settings
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config);
+
+/**
+* @brief UART interrupt configure
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param intr_conf UART interrupt settings
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf);
+
+/**
+ * @brief Install UART driver.
+ *
+ * UART ISR handler will be attached to the same CPU core that this function is running on.
+ * Users should know that which CPU is running and then pick a INUM that is not used by system.
+ * We can find the information of INUM and interrupt level in soc.h.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param rx_buffer_size UART RX ring buffer size
+ * @param tx_buffer_size UART TX ring buffer size.
+ * If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out..
+ * @param queue_size UART event queue size/depth.
+ * @param uart_queue UART event queue handle, if set NULL, driver will not use an event queue.
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, void* uart_queue, int intr_alloc_flags);\r
-\r
-/**\r
- * @brief Uninstall UART driver.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_driver_delete(uart_port_t uart_num);\r
-\r
-/**\r
- * @brief Wait UART TX FIFO empty\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param ticks_to_wait Timeout, count in RTOS ticks\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- * - ESP_ERR_TIMEOUT Timeout\r
- */\r
-esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait);\r
-\r
-/**\r
- * @brief Send data to the UART port from a given buffer and length.\r
- * \r
- * This function will not wait for the space in TX FIFO, just fill the TX FIFO and return when the FIFO is full.\r
- * @note This function should only be used when UART TX buffer is not enabled.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param buffer data buffer address\r
- * @param len data length to send\r
- *\r
- * @return\r
- * - (-1) Parameter error\r
- * - OTHERS(>=0) The number of data that pushed to the TX FIFO\r
- */\r
-int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len);\r
-\r
-/**\r
- * @brief Send data to the UART port from a given buffer and length,\r
- *\r
- * If parameter tx_buffer_size is set to zero:\r
- * This function will not return until all the data have been sent out, or at least pushed into TX FIFO.\r
- *\r
- * Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer,\r
- * then, UART ISR will move data from ring buffer to TX FIFO gradually.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param src data buffer address\r
- * @param size data length to send\r
- *\r
- * @return\r
- * - (-1) Parameter error\r
- * - OTHERS(>=0) The number of data that pushed to the TX FIFO\r
- */\r
-int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size);\r
-\r
-/**\r
- * @brief Send data to the UART port from a given buffer and length,\r
- *\r
- * If parameter tx_buffer_size is set to zero:\r
- * This function will not return until all the data and the break signal have been sent out.\r
- * After all data send out, send a break signal.\r
- *\r
- * Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer,\r
- * then, UART ISR will move data from ring buffer to TX FIFO gradually.\r
- * After all data send out, send a break signal.\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param src data buffer address\r
- * @param size data length to send\r
- * @param brk_len break signal length (unit: time of one data bit at current_baudrate)\r
- *\r
- * @return\r
- * - (-1) Parameter error\r
- * - OTHERS(>=0) The number of data that pushed to the TX FIFO\r
- */\r
-\r
-int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t size, int brk_len);\r
-\r
-/**\r
- * @brief UART read bytes from UART buffer\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param buf pointer to the buffer.\r
- * @param length data length\r
- * @param ticks_to_wait sTimeout, count in RTOS ticks\r
- *\r
- * @return\r
- * - (-1) Error\r
- * - Others return a char data from uart fifo.\r
- */\r
-int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait);\r
-\r
-/**\r
- * @brief UART ring buffer flush\r
- *\r
- * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- *\r
- * @return\r
- * - ESP_OK Success\r
- * - ESP_FAIL Parameter error\r
- */\r
-esp_err_t uart_flush(uart_port_t uart_num);\r
-\r
-/***************************EXAMPLE**********************************\r
- *\r
- *\r
- * ----------------EXAMPLE OF UART SETTING ---------------------\r
- * @code{c}\r
- * //1. Setup UART\r
- * #include "freertos/queue.h"\r
- * #define UART_INTR_NUM 17 //choose one interrupt number from soc.h\r
- * //a. Set UART parameter\r
- * int uart_num = 0; //uart port number\r
- * uart_config_t uart_config = {\r
- * .baud_rate = UART_BITRATE_115200, //baudrate\r
- * .data_bits = UART_DATA_8_BITS, //data bit mode\r
- * .parity = UART_PARITY_DISABLE, //parity mode\r
- * .stop_bits = UART_STOP_BITS_1, //stop bit mode\r
- * .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, //hardware flow control(cts/rts)\r
- * .rx_flow_ctrl_thresh = 120, //flow control threshold\r
- * };\r
- * uart_param_config(uart_num, &uart_config);\r
- * //b1. Setup UART driver(with UART queue)\r
- * QueueHandle_t uart_queue;\r
- * //parameters here are just an example, tx buffer size is 2048\r
- * uart_driver_install(uart_num, 1024 * 2, 1024 * 2, 10, &uart_queue, 0);\r
- * //b2. Setup UART driver(without UART queue)\r
- * //parameters here are just an example, tx buffer size is 0\r
- * uart_driver_install(uart_num, 1024 * 2, 0, 10, NULL, 0);\r
- *@endcode\r
- *-----------------------------------------------------------------------------*\r
- * @code{c}\r
- * //2. Set UART pin\r
- * //set UART pin, not needed if use default pins.\r
- * uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, 15, 13);\r
- * @endcode\r
- *-----------------------------------------------------------------------------*\r
- * @code{c}\r
- * //3. Read data from UART.\r
- * uint8_t data[128];\r
- * int length = 0;\r
- * length = uart_read_bytes(uart_num, data, sizeof(data), 100);\r
- * @endcode\r
- *-----------------------------------------------------------------------------*\r
- * @code{c}\r
- * //4. Write data to UART.\r
- * char* test_str = "This is a test string.\n"\r
- * uart_write_bytes(uart_num, (const char*)test_str, strlen(test_str));\r
- * @endcode\r
- *-----------------------------------------------------------------------------*\r
- * @code{c}\r
- * //5. Write data to UART, end with a break signal.\r
- * uart_write_bytes_with_break(0, "test break\n",strlen("test break\n"), 100);\r
- * @endcode\r
- *-----------------------------------------------------------------------------*\r
- * @code{c}\r
- * //6. an example of echo test with hardware flow control on UART1\r
- * void uart_loop_back_test()\r
- * {\r
- * int uart_num = 1;\r
- * uart_config_t uart_config = {\r
- * .baud_rate = 115200,\r
- * .data_bits = UART_DATA_8_BITS,\r
- * .parity = UART_PARITY_DISABLE,\r
- * .stop_bits = UART_STOP_BITS_1,\r
- * .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,\r
- * .rx_flow_ctrl_thresh = 122,\r
- * };\r
- * //Configure UART1 parameters\r
- * uart_param_config(uart_num, &uart_config);\r
- * //Set UART1 pins(TX: IO16, RX: IO17, RTS: IO18, CTS: IO19)\r
- * uart_set_pin(uart_num, 16, 17, 18, 19);\r
- * //Install UART driver( We don't need an event queue here)\r
- * uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, NULL, RINGBUF_TYPE_BYTEBUF);\r
- * uint8_t data[1000];\r
- * while(1) {\r
- * //Read data from UART\r
- * int len = uart_read_bytes(uart_num, data, sizeof(data), 10);\r
- * //Write data back to UART\r
- * uart_write_bytes(uart_num, (const char*)data, len);\r
- * }\r
- * }\r
- * @endcode\r
- *-----------------------------------------------------------------------------*\r
- * @code{c}\r
- * //7. An example of using UART event queue on UART0.\r
- * #include "freertos/queue.h"\r
- * //A queue to handle UART event.\r
- * QueueHandle_t uart0_queue;\r
- * static const char *TAG = "uart_example";\r
- * void uart_task(void *pvParameters)\r
- * {\r
- * int uart_num = (int)pvParameters;\r
- * uart_event_t event;\r
- * size_t size = 1024;\r
- * uint8_t* dtmp = (uint8_t*)malloc(size);\r
- * for(;;) {\r
- * //Waiting for UART event.\r
- * if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) {\r
- * ESP_LOGI(TAG, "uart[%d] event:", uart_num);\r
- * switch(event.type) {\r
- * memset(dtmp, 0, size);\r
- * //Event of UART receving data\r
- * case UART_DATA:\r
- * ESP_LOGI(TAG,"data, len: %d", event.size);\r
- * int len = uart_read_bytes(uart_num, dtmp, event.size, 10);\r
- * ESP_LOGI(TAG, "uart read: %d", len);\r
- uart_write_bytes(uart_num, (const char*)dtmp, len);\r
- * break;\r
- * //Event of HW FIFO overflow detected\r
- * case UART_FIFO_OVF:\r
- * ESP_LOGI(TAG, "hw fifo overflow\n");\r
- * break;\r
- * //Event of UART ring buffer full\r
- * case UART_BUFFER_FULL:\r
- * ESP_LOGI(TAG, "ring buffer full\n");\r
- * break;\r
- * //Event of UART RX break detected\r
- * case UART_BREAK:\r
- * ESP_LOGI(TAG, "uart rx break\n");\r
- * break;\r
- * //Event of UART parity check error\r
- * case UART_PARITY_ERR:\r
- * ESP_LOGI(TAG, "uart parity error\n");\r
- * break;\r
- * //Event of UART frame error\r
- * case UART_FRAME_ERR:\r
- * ESP_LOGI(TAG, "uart frame error\n");\r
- * break;\r
- * //Others\r
- * default:\r
- * ESP_LOGI(TAG, "uart event type: %d\n", event.type);\r
- * break;\r
- * }\r
- * }\r
- * }\r
- * free(dtmp);\r
- * dtmp = NULL;\r
- * vTaskDelete(NULL);\r
- * }\r
- *\r
- * void uart_queue_test()\r
- * {\r
- * int uart_num = 0;\r
- * uart_config_t uart_config = {\r
- * .baud_rate = 115200,\r
- * .data_bits = UART_DATA_8_BITS,\r
- * .parity = UART_PARITY_DISABLE,\r
- * .stop_bits = UART_STOP_BITS_1,\r
- * .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,\r
- * .rx_flow_ctrl_thresh = 122,\r
- * };\r
- * //Set UART parameters\r
- * uart_param_config(uart_num, &uart_config);\r
- * //Set UART pins,(-1: default pin, no change.)\r
- * uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);\r
- * //Set UART log level\r
- * esp_log_level_set(TAG, ESP_LOG_INFO);\r
- * //Install UART driver, and get the queue.\r
- * uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, &uart0_queue, 0);\r
- * //Create a task to handler UART event from ISR\r
- * xTaskCreate(uart_task, "uTask", 1024, (void*)uart_num, 10, NULL);\r
- * }\r
- * @endcode\r
- *\r
- ***************************END OF EXAMPLE**********************************/\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-\r
-#endif /*_DRIVER_UART_H_*/\r
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, void* uart_queue, int intr_alloc_flags);
+
+/**
+ * @brief Uninstall UART driver.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_driver_delete(uart_port_t uart_num);
+
+/**
+ * @brief Wait UART TX FIFO empty
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param ticks_to_wait Timeout, count in RTOS ticks
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ * - ESP_ERR_TIMEOUT Timeout
+ */
+esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait);
+
+/**
+ * @brief Send data to the UART port from a given buffer and length.
+ *
+ * This function will not wait for the space in TX FIFO, just fill the TX FIFO and return when the FIFO is full.
+ * @note This function should only be used when UART TX buffer is not enabled.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param buffer data buffer address
+ * @param len data length to send
+ *
+ * @return
+ * - (-1) Parameter error
+ * - OTHERS(>=0) The number of data that pushed to the TX FIFO
+ */
+int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len);
+
+/**
+ * @brief Send data to the UART port from a given buffer and length,
+ *
+ * If parameter tx_buffer_size is set to zero:
+ * This function will not return until all the data have been sent out, or at least pushed into TX FIFO.
+ *
+ * Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer,
+ * then, UART ISR will move data from ring buffer to TX FIFO gradually.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param src data buffer address
+ * @param size data length to send
+ *
+ * @return
+ * - (-1) Parameter error
+ * - OTHERS(>=0) The number of data that pushed to the TX FIFO
+ */
+int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size);
+
+/**
+ * @brief Send data to the UART port from a given buffer and length,
+ *
+ * If parameter tx_buffer_size is set to zero:
+ * This function will not return until all the data and the break signal have been sent out.
+ * After all data send out, send a break signal.
+ *
+ * Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer,
+ * then, UART ISR will move data from ring buffer to TX FIFO gradually.
+ * After all data send out, send a break signal.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param src data buffer address
+ * @param size data length to send
+ * @param brk_len break signal length (unit: time of one data bit at current_baudrate)
+ *
+ * @return
+ * - (-1) Parameter error
+ * - OTHERS(>=0) The number of data that pushed to the TX FIFO
+ */
+
+int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t size, int brk_len);
+
+/**
+ * @brief UART read bytes from UART buffer
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param buf pointer to the buffer.
+ * @param length data length
+ * @param ticks_to_wait sTimeout, count in RTOS ticks
+ *
+ * @return
+ * - (-1) Error
+ * - Others return a char data from uart fifo.
+ */
+int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait);
+
+/**
+ * @brief UART ring buffer flush
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+esp_err_t uart_flush(uart_port_t uart_num);
+
+/***************************EXAMPLE**********************************
+ *
+ *
+ * ----------------EXAMPLE OF UART SETTING ---------------------
+ * @code{c}
+ * //1. Setup UART
+ * #include "freertos/queue.h"
+ * #define UART_INTR_NUM 17 //choose one interrupt number from soc.h
+ * //a. Set UART parameter
+ * int uart_num = 0; //uart port number
+ * uart_config_t uart_config = {
+ * .baud_rate = UART_BITRATE_115200, //baudrate
+ * .data_bits = UART_DATA_8_BITS, //data bit mode
+ * .parity = UART_PARITY_DISABLE, //parity mode
+ * .stop_bits = UART_STOP_BITS_1, //stop bit mode
+ * .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, //hardware flow control(cts/rts)
+ * .rx_flow_ctrl_thresh = 120, //flow control threshold
+ * };
+ * uart_param_config(uart_num, &uart_config);
+ * //b1. Setup UART driver(with UART queue)
+ * QueueHandle_t uart_queue;
+ * //parameters here are just an example, tx buffer size is 2048
+ * uart_driver_install(uart_num, 1024 * 2, 1024 * 2, 10, &uart_queue, 0);
+ * //b2. Setup UART driver(without UART queue)
+ * //parameters here are just an example, tx buffer size is 0
+ * uart_driver_install(uart_num, 1024 * 2, 0, 10, NULL, 0);
+ *@endcode
+ *-----------------------------------------------------------------------------*
+ * @code{c}
+ * //2. Set UART pin
+ * //set UART pin, not needed if use default pins.
+ * uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, 15, 13);
+ * @endcode
+ *-----------------------------------------------------------------------------*
+ * @code{c}
+ * //3. Read data from UART.
+ * uint8_t data[128];
+ * int length = 0;
+ * length = uart_read_bytes(uart_num, data, sizeof(data), 100);
+ * @endcode
+ *-----------------------------------------------------------------------------*
+ * @code{c}
+ * //4. Write data to UART.
+ * char* test_str = "This is a test string.\n"
+ * uart_write_bytes(uart_num, (const char*)test_str, strlen(test_str));
+ * @endcode
+ *-----------------------------------------------------------------------------*
+ * @code{c}
+ * //5. Write data to UART, end with a break signal.
+ * uart_write_bytes_with_break(0, "test break\n",strlen("test break\n"), 100);
+ * @endcode
+ *-----------------------------------------------------------------------------*
+ * @code{c}
+ * //6. an example of echo test with hardware flow control on UART1
+ * void uart_loop_back_test()
+ * {
+ * int uart_num = 1;
+ * uart_config_t uart_config = {
+ * .baud_rate = 115200,
+ * .data_bits = UART_DATA_8_BITS,
+ * .parity = UART_PARITY_DISABLE,
+ * .stop_bits = UART_STOP_BITS_1,
+ * .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
+ * .rx_flow_ctrl_thresh = 122,
+ * };
+ * //Configure UART1 parameters
+ * uart_param_config(uart_num, &uart_config);
+ * //Set UART1 pins(TX: IO16, RX: IO17, RTS: IO18, CTS: IO19)
+ * uart_set_pin(uart_num, 16, 17, 18, 19);
+ * //Install UART driver( We don't need an event queue here)
+ * uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, NULL, RINGBUF_TYPE_BYTEBUF);
+ * uint8_t data[1000];
+ * while(1) {
+ * //Read data from UART
+ * int len = uart_read_bytes(uart_num, data, sizeof(data), 10);
+ * //Write data back to UART
+ * uart_write_bytes(uart_num, (const char*)data, len);
+ * }
+ * }
+ * @endcode
+ *-----------------------------------------------------------------------------*
+ * @code{c}
+ * //7. An example of using UART event queue on UART0.
+ * #include "freertos/queue.h"
+ * //A queue to handle UART event.
+ * QueueHandle_t uart0_queue;
+ * static const char *TAG = "uart_example";
+ * void uart_task(void *pvParameters)
+ * {
+ * int uart_num = (int)pvParameters;
+ * uart_event_t event;
+ * size_t size = 1024;
+ * uint8_t* dtmp = (uint8_t*)malloc(size);
+ * for(;;) {
+ * //Waiting for UART event.
+ * if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) {
+ * ESP_LOGI(TAG, "uart[%d] event:", uart_num);
+ * switch(event.type) {
+ * memset(dtmp, 0, size);
+ * //Event of UART receving data
+ * case UART_DATA:
+ * ESP_LOGI(TAG,"data, len: %d", event.size);
+ * int len = uart_read_bytes(uart_num, dtmp, event.size, 10);
+ * ESP_LOGI(TAG, "uart read: %d", len);
+ uart_write_bytes(uart_num, (const char*)dtmp, len);
+ * break;
+ * //Event of HW FIFO overflow detected
+ * case UART_FIFO_OVF:
+ * ESP_LOGI(TAG, "hw fifo overflow\n");
+ * break;
+ * //Event of UART ring buffer full
+ * case UART_BUFFER_FULL:
+ * ESP_LOGI(TAG, "ring buffer full\n");
+ * break;
+ * //Event of UART RX break detected
+ * case UART_BREAK:
+ * ESP_LOGI(TAG, "uart rx break\n");
+ * break;
+ * //Event of UART parity check error
+ * case UART_PARITY_ERR:
+ * ESP_LOGI(TAG, "uart parity error\n");
+ * break;
+ * //Event of UART frame error
+ * case UART_FRAME_ERR:
+ * ESP_LOGI(TAG, "uart frame error\n");
+ * break;
+ * //Others
+ * default:
+ * ESP_LOGI(TAG, "uart event type: %d\n", event.type);
+ * break;
+ * }
+ * }
+ * }
+ * free(dtmp);
+ * dtmp = NULL;
+ * vTaskDelete(NULL);
+ * }
+ *
+ * void uart_queue_test()
+ * {
+ * int uart_num = 0;
+ * uart_config_t uart_config = {
+ * .baud_rate = 115200,
+ * .data_bits = UART_DATA_8_BITS,
+ * .parity = UART_PARITY_DISABLE,
+ * .stop_bits = UART_STOP_BITS_1,
+ * .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
+ * .rx_flow_ctrl_thresh = 122,
+ * };
+ * //Set UART parameters
+ * uart_param_config(uart_num, &uart_config);
+ * //Set UART pins,(-1: default pin, no change.)
+ * uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
+ * //Set UART log level
+ * esp_log_level_set(TAG, ESP_LOG_INFO);
+ * //Install UART driver, and get the queue.
+ * uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, &uart0_queue, 0);
+ * //Create a task to handler UART event from ISR
+ * xTaskCreate(uart_task, "uTask", 1024, (void*)uart_num, 10, NULL);
+ * }
+ * @endcode
+ *
+ ***************************END OF EXAMPLE**********************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_DRIVER_UART_H_*/
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\r
-//\r
-// Licensed under the Apache License, Version 2.0 (the "License");\r
-// you may not use this file except in compliance with the License.\r
-// You may obtain a copy of the License at\r
-\r
-// http://www.apache.org/licenses/LICENSE-2.0\r
-//\r
-// Unless required by applicable law or agreed to in writing, software\r
-// distributed under the License is distributed on an "AS IS" BASIS,\r
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-// See the License for the specific language governing permissions and\r
-// limitations under the License.\r
-#include <string.h>\r
-#include "esp_log.h"\r
-#include "esp_err.h"\r
-#include "esp_intr.h"\r
-#include "esp_intr_alloc.h"\r
-#include "freertos/FreeRTOS.h"\r
-#include "freertos/xtensa_api.h"\r
-#include "driver/timer.h"\r
-#include "driver/periph_ctrl.h"\r
-\r
-static const char* TIMER_TAG = "timer_group";\r
-#define TIMER_CHECK(a, str, ret_val) \\r
- if (!(a)) { \\r
- ESP_LOGE(TIMER_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \\r
- return (ret_val); \\r
- }\r
-\r
-#define TIMER_GROUP_NUM_ERROR "TIMER GROUP NUM ERROR"\r
-#define TIMER_NUM_ERROR "HW TIMER NUM ERROR"\r
-#define TIMER_PARAM_ADDR_ERROR "HW TIMER PARAM ADDR ERROR"\r
-#define TIMER_COUNT_DIR_ERROR "HW TIMER COUNTER DIR ERROR"\r
-#define TIMER_AUTORELOAD_ERROR "HW TIMER AUTORELOAD ERROR"\r
-#define TIMER_SCALE_ERROR "HW TIMER SCALE ERROR"\r
-#define TIMER_ALARM_ERROR "HW TIMER ALARM ERROR"\r
-static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1};\r
-static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};\r
-\r
-#define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux);\r
-#define TIMER_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux);\r
-\r
-esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t* timer_val)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_val != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
- portENTER_CRITICAL(&timer_spinlock[group_num]);\r
- TG[group_num]->hw_timer[timer_num].update = 1;\r
- *timer_val = ((uint64_t) TG[group_num]->hw_timer[timer_num].cnt_high << 32)\r
- | (TG[group_num]->hw_timer[timer_num].cnt_low);\r
- portEXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_get_counter_time_sec(timer_group_t group_num, timer_idx_t timer_num, double* time)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(time != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
-\r
- uint64_t timer_val;\r
- esp_err_t err = timer_get_counter_value(group_num, timer_num, &timer_val);\r
- if (err == ESP_OK) {\r
- uint16_t div = TG[group_num]->hw_timer[timer_num].config.divider;\r
- *time = (double)timer_val * div / TIMER_BASE_CLK;\r
- }\r
- return err;\r
-}\r
-\r
-esp_err_t timer_set_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t load_val)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
- TG[group_num]->hw_timer[timer_num].load_high = (uint32_t) (load_val >> 32);\r
- TG[group_num]->hw_timer[timer_num].load_low = (uint32_t) load_val;\r
- TG[group_num]->hw_timer[timer_num].reload = 1;\r
- TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_start(timer_group_t group_num, timer_idx_t timer_num)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
- TG[group_num]->hw_timer[timer_num].config.enable = 1;\r
- TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_pause(timer_group_t group_num, timer_idx_t timer_num)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
- TG[group_num]->hw_timer[timer_num].config.enable = 0;\r
- TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_set_counter_mode(timer_group_t group_num, timer_idx_t timer_num, timer_count_dir_t counter_dir)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(counter_dir < TIMER_COUNT_MAX, TIMER_COUNT_DIR_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
- TG[group_num]->hw_timer[timer_num].config.increase = counter_dir;\r
- TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, timer_autoreload_t reload)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(reload < TIMER_AUTORELOAD_MAX, TIMER_AUTORELOAD_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
- TG[group_num]->hw_timer[timer_num].config.autoreload = reload;\r
- TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint16_t divider)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
- int timer_en = TG[group_num]->hw_timer[timer_num].config.enable;\r
- TG[group_num]->hw_timer[timer_num].config.enable = 0;\r
- TG[group_num]->hw_timer[timer_num].config.divider = divider;\r
- TG[group_num]->hw_timer[timer_num].config.enable = timer_en;\r
- TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_value)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
- TG[group_num]->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32);\r
- TG[group_num]->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value;\r
- TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t* alarm_value)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(alarm_value != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
- portENTER_CRITICAL(&timer_spinlock[group_num]);\r
- *alarm_value = ((uint64_t) TG[group_num]->hw_timer[timer_num].alarm_high << 32)\r
- | (TG[group_num]->hw_timer[timer_num].alarm_low);\r
- portEXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_alarm_t alarm_en)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(alarm_en < TIMER_ALARM_MAX, TIMER_ALARM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
- TG[group_num]->hw_timer[timer_num].config.alarm_en = alarm_en;\r
- TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, \r
- void (*fn)(void*), void * arg, int intr_alloc_flags, timer_isr_handle_t *handle)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(fn != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
-\r
- int intr_source = 0;\r
- uint32_t status_reg = 0;\r
- int mask = 0;\r
- switch(group_num) {\r
- case TIMER_GROUP_0:\r
- default:\r
- if((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {\r
- intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer_num;\r
- } else {\r
- intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer_num;\r
- }\r
- status_reg = TIMG_INT_ST_TIMERS_REG(0);\r
- mask = 1<<timer_num;\r
- break;\r
- case TIMER_GROUP_1:\r
- if((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {\r
- intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer_num;\r
- } else {\r
- intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer_num;\r
- }\r
- status_reg = TIMG_INT_ST_TIMERS_REG(1);\r
- mask = 1<<timer_num;\r
- break;\r
- }\r
- return esp_intr_alloc_intrstatus(intr_source, intr_alloc_flags, status_reg, mask, fn, arg, handle);\r
-}\r
-\r
-esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(config != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
-\r
- if(group_num == 0) {\r
- periph_module_enable(PERIPH_TIMG0_MODULE);\r
- } else if(group_num == 1) {\r
- periph_module_enable(PERIPH_TIMG1_MODULE);\r
- }\r
- TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
- TG[group_num]->hw_timer[timer_num].config.autoreload = config->auto_reload;\r
- TG[group_num]->hw_timer[timer_num].config.divider = config->divider;\r
- TG[group_num]->hw_timer[timer_num].config.enable = config->counter_en;\r
- TG[group_num]->hw_timer[timer_num].config.increase = config->counter_dir;\r
- TG[group_num]->hw_timer[timer_num].config.alarm_en = config->alarm_en;\r
- TG[group_num]->hw_timer[timer_num].config.level_int_en = (config->intr_type == TIMER_INTR_LEVEL ? 1 : 0);\r
- TG[group_num]->hw_timer[timer_num].config.edge_int_en = (config->intr_type == TIMER_INTR_LEVEL ? 0 : 1);\r
- TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(config != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
- config->alarm_en = TG[group_num]->hw_timer[timer_num].config.alarm_en;\r
- config->auto_reload = TG[group_num]->hw_timer[timer_num].config.autoreload;\r
- config->counter_dir = TG[group_num]->hw_timer[timer_num].config.increase;\r
- config->counter_dir = TG[group_num]->hw_timer[timer_num].config.divider;\r
- config->counter_en = TG[group_num]->hw_timer[timer_num].config.enable;\r
- if(TG[group_num]->hw_timer[timer_num].config.level_int_en) {\r
- config->intr_type =TIMER_INTR_LEVEL;\r
- }\r
- TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- portENTER_CRITICAL(&timer_spinlock[group_num]);\r
- TG[group_num]->int_ena.val |= en_mask;\r
- portEXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- portENTER_CRITICAL(&timer_spinlock[group_num]);\r
- TG[group_num]->int_ena.val &= (~disable_mask);\r
- portEXIT_CRITICAL(&timer_spinlock[group_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- return timer_group_intr_enable(group_num, BIT(timer_num));\r
-}\r
-\r
-esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num)\r
-{\r
- TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
- return timer_group_intr_disable(group_num, BIT(timer_num));\r
-}\r
-\r
-\r
+// Copyright 2015-2016 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.
+// You may obtain a copy of the License at
+
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <string.h>
+#include "esp_log.h"
+#include "esp_err.h"
+#include "esp_intr.h"
+#include "esp_intr_alloc.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/xtensa_api.h"
+#include "driver/timer.h"
+#include "driver/periph_ctrl.h"
+
+static const char* TIMER_TAG = "timer_group";
+#define TIMER_CHECK(a, str, ret_val) \
+ if (!(a)) { \
+ ESP_LOGE(TIMER_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
+ return (ret_val); \
+ }
+
+#define TIMER_GROUP_NUM_ERROR "TIMER GROUP NUM ERROR"
+#define TIMER_NUM_ERROR "HW TIMER NUM ERROR"
+#define TIMER_PARAM_ADDR_ERROR "HW TIMER PARAM ADDR ERROR"
+#define TIMER_COUNT_DIR_ERROR "HW TIMER COUNTER DIR ERROR"
+#define TIMER_AUTORELOAD_ERROR "HW TIMER AUTORELOAD ERROR"
+#define TIMER_SCALE_ERROR "HW TIMER SCALE ERROR"
+#define TIMER_ALARM_ERROR "HW TIMER ALARM ERROR"
+static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1};
+static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
+
+#define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux);
+#define TIMER_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux);
+
+esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t* timer_val)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_val != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
+ portENTER_CRITICAL(&timer_spinlock[group_num]);
+ TG[group_num]->hw_timer[timer_num].update = 1;
+ *timer_val = ((uint64_t) TG[group_num]->hw_timer[timer_num].cnt_high << 32)
+ | (TG[group_num]->hw_timer[timer_num].cnt_low);
+ portEXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_get_counter_time_sec(timer_group_t group_num, timer_idx_t timer_num, double* time)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(time != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
+
+ uint64_t timer_val;
+ esp_err_t err = timer_get_counter_value(group_num, timer_num, &timer_val);
+ if (err == ESP_OK) {
+ uint16_t div = TG[group_num]->hw_timer[timer_num].config.divider;
+ *time = (double)timer_val * div / TIMER_BASE_CLK;
+ }
+ return err;
+}
+
+esp_err_t timer_set_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t load_val)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+ TG[group_num]->hw_timer[timer_num].load_high = (uint32_t) (load_val >> 32);
+ TG[group_num]->hw_timer[timer_num].load_low = (uint32_t) load_val;
+ TG[group_num]->hw_timer[timer_num].reload = 1;
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_start(timer_group_t group_num, timer_idx_t timer_num)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+ TG[group_num]->hw_timer[timer_num].config.enable = 1;
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_pause(timer_group_t group_num, timer_idx_t timer_num)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+ TG[group_num]->hw_timer[timer_num].config.enable = 0;
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_set_counter_mode(timer_group_t group_num, timer_idx_t timer_num, timer_count_dir_t counter_dir)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(counter_dir < TIMER_COUNT_MAX, TIMER_COUNT_DIR_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+ TG[group_num]->hw_timer[timer_num].config.increase = counter_dir;
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, timer_autoreload_t reload)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(reload < TIMER_AUTORELOAD_MAX, TIMER_AUTORELOAD_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+ TG[group_num]->hw_timer[timer_num].config.autoreload = reload;
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint16_t divider)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+ int timer_en = TG[group_num]->hw_timer[timer_num].config.enable;
+ TG[group_num]->hw_timer[timer_num].config.enable = 0;
+ TG[group_num]->hw_timer[timer_num].config.divider = divider;
+ TG[group_num]->hw_timer[timer_num].config.enable = timer_en;
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_value)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+ TG[group_num]->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32);
+ TG[group_num]->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value;
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t* alarm_value)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(alarm_value != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
+ portENTER_CRITICAL(&timer_spinlock[group_num]);
+ *alarm_value = ((uint64_t) TG[group_num]->hw_timer[timer_num].alarm_high << 32)
+ | (TG[group_num]->hw_timer[timer_num].alarm_low);
+ portEXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_alarm_t alarm_en)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(alarm_en < TIMER_ALARM_MAX, TIMER_ALARM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+ TG[group_num]->hw_timer[timer_num].config.alarm_en = alarm_en;
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num,
+ void (*fn)(void*), void * arg, int intr_alloc_flags, timer_isr_handle_t *handle)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(fn != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
+
+ int intr_source = 0;
+ uint32_t status_reg = 0;
+ int mask = 0;
+ switch(group_num) {
+ case TIMER_GROUP_0:
+ default:
+ if((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {
+ intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer_num;
+ } else {
+ intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer_num;
+ }
+ status_reg = TIMG_INT_ST_TIMERS_REG(0);
+ mask = 1<<timer_num;
+ break;
+ case TIMER_GROUP_1:
+ if((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {
+ intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer_num;
+ } else {
+ intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer_num;
+ }
+ status_reg = TIMG_INT_ST_TIMERS_REG(1);
+ mask = 1<<timer_num;
+ break;
+ }
+ return esp_intr_alloc_intrstatus(intr_source, intr_alloc_flags, status_reg, mask, fn, arg, handle);
+}
+
+esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(config != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
+
+ if(group_num == 0) {
+ periph_module_enable(PERIPH_TIMG0_MODULE);
+ } else if(group_num == 1) {
+ periph_module_enable(PERIPH_TIMG1_MODULE);
+ }
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+ TG[group_num]->hw_timer[timer_num].config.autoreload = config->auto_reload;
+ TG[group_num]->hw_timer[timer_num].config.divider = config->divider;
+ TG[group_num]->hw_timer[timer_num].config.enable = config->counter_en;
+ TG[group_num]->hw_timer[timer_num].config.increase = config->counter_dir;
+ TG[group_num]->hw_timer[timer_num].config.alarm_en = config->alarm_en;
+ TG[group_num]->hw_timer[timer_num].config.level_int_en = (config->intr_type == TIMER_INTR_LEVEL ? 1 : 0);
+ TG[group_num]->hw_timer[timer_num].config.edge_int_en = (config->intr_type == TIMER_INTR_LEVEL ? 0 : 1);
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(config != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+ config->alarm_en = TG[group_num]->hw_timer[timer_num].config.alarm_en;
+ config->auto_reload = TG[group_num]->hw_timer[timer_num].config.autoreload;
+ config->counter_dir = TG[group_num]->hw_timer[timer_num].config.increase;
+ config->counter_dir = TG[group_num]->hw_timer[timer_num].config.divider;
+ config->counter_en = TG[group_num]->hw_timer[timer_num].config.enable;
+ if(TG[group_num]->hw_timer[timer_num].config.level_int_en) {
+ config->intr_type =TIMER_INTR_LEVEL;
+ }
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ portENTER_CRITICAL(&timer_spinlock[group_num]);
+ TG[group_num]->int_ena.val |= en_mask;
+ portEXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ portENTER_CRITICAL(&timer_spinlock[group_num]);
+ TG[group_num]->int_ena.val &= (~disable_mask);
+ portEXIT_CRITICAL(&timer_spinlock[group_num]);
+ return ESP_OK;
+}
+
+esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ return timer_group_intr_enable(group_num, BIT(timer_num));
+}
+
+esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num)
+{
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
+ return timer_group_intr_disable(group_num, BIT(timer_num));
+}
+
+
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\r
-//\r
-// Licensed under the Apache License, Version 2.0 (the "License");\r
-// you may not use this file except in compliance with the License.\r
-// You may obtain a copy of the License at\r
-\r
-// http://www.apache.org/licenses/LICENSE-2.0\r
-//\r
-// Unless required by applicable law or agreed to in writing, software\r
-// distributed under the License is distributed on an "AS IS" BASIS,\r
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-// See the License for the specific language governing permissions and\r
-// limitations under the License.\r
-#include <string.h>\r
-#include "esp_types.h"\r
-#include "esp_attr.h"\r
-#include "esp_intr.h"\r
-#include "esp_intr_alloc.h"\r
-#include "esp_log.h"\r
-#include "esp_err.h"\r
-#include "malloc.h"\r
-#include "freertos/FreeRTOS.h"\r
-#include "freertos/semphr.h"\r
-#include "freertos/xtensa_api.h"\r
-#include "freertos/task.h"\r
-#include "freertos/ringbuf.h"\r
-#include "soc/dport_reg.h"\r
-#include "soc/uart_struct.h"\r
-#include "driver/uart.h"\r
-#include "driver/gpio.h"\r
-\r
-static const char* UART_TAG = "uart";\r
-#define UART_CHECK(a, str, ret_val) \\r
- if (!(a)) { \\r
- ESP_LOGE(UART_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \\r
- return (ret_val); \\r
- }\r
-\r
-#define UART_EMPTY_THRESH_DEFAULT (10)\r
-#define UART_FULL_THRESH_DEFAULT (120)\r
-#define UART_TOUT_THRESH_DEFAULT (10)\r
-#define UART_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux)\r
-#define UART_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux)\r
-#define UART_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)\r
-#define UART_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)\r
-\r
-typedef struct {\r
- uart_event_type_t type; /*!< UART TX data type */\r
- struct {\r
- int brk_len;\r
- size_t size;\r
- uint8_t data[0];\r
- } tx_data;\r
-} uart_tx_data_t;\r
-\r
-typedef struct {\r
- uart_port_t uart_num; /*!< UART port number*/\r
- int queue_size; /*!< UART event queue size*/\r
- QueueHandle_t xQueueUart; /*!< UART queue handler*/\r
- intr_handle_t intr_handle; /*!< UART interrupt handle*/\r
- //rx parameters\r
- SemaphoreHandle_t rx_mux; /*!< UART RX data mutex*/\r
- int rx_buf_size; /*!< RX ring buffer size */\r
- RingbufHandle_t rx_ring_buf; /*!< RX ring buffer handler*/\r
- bool rx_buffer_full_flg; /*!< RX ring buffer full flag. */\r
- int rx_cur_remain; /*!< Data number that waiting to be read out in ring buffer item*/\r
- uint8_t* rx_ptr; /*!< pointer to the current data in ring buffer*/\r
- uint8_t* rx_head_ptr; /*!< pointer to the head of RX item*/\r
- uint8_t rx_data_buf[UART_FIFO_LEN]; /*!< Data buffer to stash FIFO data*/\r
- uint8_t rx_stash_len; /*!< stashed data length.(When using flow control, after reading out FIFO data, if we fail to push to buffer, we can just stash them.) */\r
- //tx parameters\r
- SemaphoreHandle_t tx_fifo_sem; /*!< UART TX FIFO semaphore*/\r
- SemaphoreHandle_t tx_mux; /*!< UART TX mutex*/\r
- SemaphoreHandle_t tx_done_sem; /*!< UART TX done semaphore*/\r
- SemaphoreHandle_t tx_brk_sem; /*!< UART TX send break done semaphore*/\r
- int tx_buf_size; /*!< TX ring buffer size */\r
- RingbufHandle_t tx_ring_buf; /*!< TX ring buffer handler*/\r
- bool tx_waiting_fifo; /*!< this flag indicates that some task is waiting for FIFO empty interrupt, used to send all data without any data buffer*/\r
- uint8_t* tx_ptr; /*!< TX data pointer to push to FIFO in TX buffer mode*/\r
- uart_tx_data_t* tx_head; /*!< TX data pointer to head of the current buffer in TX ring buffer*/\r
- uint32_t tx_len_tot; /*!< Total length of current item in ring buffer*/\r
- uint32_t tx_len_cur;\r
- uint8_t tx_brk_flg; /*!< Flag to indicate to send a break signal in the end of the item sending procedure */\r
- uint8_t tx_brk_len; /*!< TX break signal cycle length/number */\r
- uint8_t tx_waiting_brk; /*!< Flag to indicate that TX FIFO is ready to send break signal after FIFO is empty, do not push data into TX FIFO right now.*/\r
-} uart_obj_t;\r
-\r
-\r
-\r
-static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0};\r
-/* DRAM_ATTR is required to avoid UART array placed in flash, due to accessed from ISR */\r
-static DRAM_ATTR uart_dev_t* const UART[UART_NUM_MAX] = {&UART0, &UART1, &UART2};\r
-static portMUX_TYPE uart_spinlock[UART_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};\r
-\r
-esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((data_bit < UART_DATA_BITS_MAX), "data bit error", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- UART[uart_num]->conf0.bit_num = data_bit;\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- *(data_bit) = UART[uart_num]->conf0.bit_num;\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bit)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((stop_bit < UART_STOP_BITS_MAX), "stop bit error", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- UART[uart_num]->conf0.stop_bit_num = stop_bit;\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bit)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- (*stop_bit) = UART[uart_num]->conf0.stop_bit_num;\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- UART[uart_num]->conf0.parity = parity_mode & 0x1;\r
- UART[uart_num]->conf0.parity_en = (parity_mode >> 1) & 0x1;\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- int val = UART[uart_num]->conf0.val;\r
- if(val & UART_PARITY_EN_M) {\r
- if(val & UART_PARITY_M) {\r
- (*parity_mode) = UART_PARITY_ODD;\r
- } else {\r
- (*parity_mode) = UART_PARITY_EVEN;\r
- }\r
- } else {\r
- (*parity_mode) = UART_PARITY_DISABLE;\r
- }\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baud_rate)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((baud_rate < UART_BITRATE_MAX), "baud_rate error", ESP_FAIL);\r
- uint32_t clk_div = (((UART_CLK_FREQ) << 4) / baud_rate);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- UART[uart_num]->clk_div.div_int = clk_div >> 4;\r
- UART[uart_num]->clk_div.div_frag = clk_div & 0xf;\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- uint32_t clk_div = (UART[uart_num]->clk_div.div_int << 4) | UART[uart_num]->clk_div.div_frag;\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- (*baudrate) = ((UART_CLK_FREQ) << 4) / clk_div;\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((((inverse_mask & UART_LINE_INV_MASK) == 0) && (inverse_mask != 0)), "inverse_mask error", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- CLEAR_PERI_REG_MASK(UART_CONF0_REG(uart_num), UART_LINE_INV_MASK);\r
- SET_PERI_REG_MASK(UART_CONF0_REG(uart_num), inverse_mask);\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-//only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set.\r
-esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((rx_thresh < UART_FIFO_LEN), "rx flow thresh error", ESP_FAIL);\r
- UART_CHECK((flow_ctrl < UART_HW_FLOWCTRL_MAX), "hw_flowctrl mode error", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- if(flow_ctrl & UART_HW_FLOWCTRL_RTS) {\r
- UART[uart_num]->conf1.rx_flow_thrhd = rx_thresh;\r
- UART[uart_num]->conf1.rx_flow_en = 1;\r
- } else {\r
- UART[uart_num]->conf1.rx_flow_en = 0;\r
- }\r
- if(flow_ctrl & UART_HW_FLOWCTRL_CTS) {\r
- UART[uart_num]->conf0.tx_flow_en = 1;\r
- } else {\r
- UART[uart_num]->conf0.tx_flow_en = 0;\r
- }\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- uart_hw_flowcontrol_t val = UART_HW_FLOWCTRL_DISABLE;\r
- if(UART[uart_num]->conf1.rx_flow_en) {\r
- val |= UART_HW_FLOWCTRL_RTS;\r
- }\r
- if(UART[uart_num]->conf0.tx_flow_en) {\r
- val |= UART_HW_FLOWCTRL_CTS;\r
- }\r
- (*flow_ctrl) = val;\r
- return ESP_OK;\r
-}\r
-\r
-static esp_err_t uart_reset_fifo(uart_port_t uart_num)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- UART[uart_num]->conf0.rxfifo_rst = 1;\r
- UART[uart_num]->conf0.rxfifo_rst = 0;\r
- UART[uart_num]->conf0.txfifo_rst = 1;\r
- UART[uart_num]->conf0.txfifo_rst = 0;\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- //intr_clr register is write-only\r
- UART[uart_num]->int_clr.val = clr_mask;\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- SET_PERI_REG_MASK(UART_INT_CLR_REG(uart_num), enable_mask);\r
- SET_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), enable_mask);\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), disable_mask);\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_enable_rx_intr(uart_port_t uart_num)\r
-{\r
- uart_enable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_disable_rx_intr(uart_port_t uart_num)\r
-{\r
- uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_disable_tx_intr(uart_port_t uart_num)\r
-{\r
- uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((thresh < UART_FIFO_LEN), "empty intr threshold error", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- UART[uart_num]->int_clr.txfifo_empty = 1;\r
- UART[uart_num]->conf1.txfifo_empty_thrhd = thresh & UART_TXFIFO_EMPTY_THRHD_V;\r
- UART[uart_num]->int_ena.txfifo_empty = enable & 0x1;\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags)\r
-{\r
+// Copyright 2015-2016 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.
+// You may obtain a copy of the License at
+
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <string.h>
+#include "esp_types.h"
+#include "esp_attr.h"
+#include "esp_intr.h"
+#include "esp_intr_alloc.h"
+#include "esp_log.h"
+#include "esp_err.h"
+#include "malloc.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/xtensa_api.h"
+#include "freertos/task.h"
+#include "freertos/ringbuf.h"
+#include "soc/dport_reg.h"
+#include "soc/uart_struct.h"
+#include "driver/uart.h"
+#include "driver/gpio.h"
+
+static const char* UART_TAG = "uart";
+#define UART_CHECK(a, str, ret_val) \
+ if (!(a)) { \
+ ESP_LOGE(UART_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
+ return (ret_val); \
+ }
+
+#define UART_EMPTY_THRESH_DEFAULT (10)
+#define UART_FULL_THRESH_DEFAULT (120)
+#define UART_TOUT_THRESH_DEFAULT (10)
+#define UART_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux)
+#define UART_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux)
+#define UART_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)
+#define UART_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)
+
+typedef struct {
+ uart_event_type_t type; /*!< UART TX data type */
+ struct {
+ int brk_len;
+ size_t size;
+ uint8_t data[0];
+ } tx_data;
+} uart_tx_data_t;
+
+typedef struct {
+ uart_port_t uart_num; /*!< UART port number*/
+ int queue_size; /*!< UART event queue size*/
+ QueueHandle_t xQueueUart; /*!< UART queue handler*/
+ intr_handle_t intr_handle; /*!< UART interrupt handle*/
+ //rx parameters
+ SemaphoreHandle_t rx_mux; /*!< UART RX data mutex*/
+ int rx_buf_size; /*!< RX ring buffer size */
+ RingbufHandle_t rx_ring_buf; /*!< RX ring buffer handler*/
+ bool rx_buffer_full_flg; /*!< RX ring buffer full flag. */
+ int rx_cur_remain; /*!< Data number that waiting to be read out in ring buffer item*/
+ uint8_t* rx_ptr; /*!< pointer to the current data in ring buffer*/
+ uint8_t* rx_head_ptr; /*!< pointer to the head of RX item*/
+ uint8_t rx_data_buf[UART_FIFO_LEN]; /*!< Data buffer to stash FIFO data*/
+ uint8_t rx_stash_len; /*!< stashed data length.(When using flow control, after reading out FIFO data, if we fail to push to buffer, we can just stash them.) */
+ //tx parameters
+ SemaphoreHandle_t tx_fifo_sem; /*!< UART TX FIFO semaphore*/
+ SemaphoreHandle_t tx_mux; /*!< UART TX mutex*/
+ SemaphoreHandle_t tx_done_sem; /*!< UART TX done semaphore*/
+ SemaphoreHandle_t tx_brk_sem; /*!< UART TX send break done semaphore*/
+ int tx_buf_size; /*!< TX ring buffer size */
+ RingbufHandle_t tx_ring_buf; /*!< TX ring buffer handler*/
+ bool tx_waiting_fifo; /*!< this flag indicates that some task is waiting for FIFO empty interrupt, used to send all data without any data buffer*/
+ uint8_t* tx_ptr; /*!< TX data pointer to push to FIFO in TX buffer mode*/
+ uart_tx_data_t* tx_head; /*!< TX data pointer to head of the current buffer in TX ring buffer*/
+ uint32_t tx_len_tot; /*!< Total length of current item in ring buffer*/
+ uint32_t tx_len_cur;
+ uint8_t tx_brk_flg; /*!< Flag to indicate to send a break signal in the end of the item sending procedure */
+ uint8_t tx_brk_len; /*!< TX break signal cycle length/number */
+ uint8_t tx_waiting_brk; /*!< Flag to indicate that TX FIFO is ready to send break signal after FIFO is empty, do not push data into TX FIFO right now.*/
+} uart_obj_t;
+
+
+
+static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0};
+/* DRAM_ATTR is required to avoid UART array placed in flash, due to accessed from ISR */
+static DRAM_ATTR uart_dev_t* const UART[UART_NUM_MAX] = {&UART0, &UART1, &UART2};
+static portMUX_TYPE uart_spinlock[UART_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
+
+esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((data_bit < UART_DATA_BITS_MAX), "data bit error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ UART[uart_num]->conf0.bit_num = data_bit;
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ *(data_bit) = UART[uart_num]->conf0.bit_num;
+ return ESP_OK;
+}
+
+esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bit)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((stop_bit < UART_STOP_BITS_MAX), "stop bit error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ UART[uart_num]->conf0.stop_bit_num = stop_bit;
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bit)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ (*stop_bit) = UART[uart_num]->conf0.stop_bit_num;
+ return ESP_OK;
+}
+
+esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ UART[uart_num]->conf0.parity = parity_mode & 0x1;
+ UART[uart_num]->conf0.parity_en = (parity_mode >> 1) & 0x1;
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ int val = UART[uart_num]->conf0.val;
+ if(val & UART_PARITY_EN_M) {
+ if(val & UART_PARITY_M) {
+ (*parity_mode) = UART_PARITY_ODD;
+ } else {
+ (*parity_mode) = UART_PARITY_EVEN;
+ }
+ } else {
+ (*parity_mode) = UART_PARITY_DISABLE;
+ }
+ return ESP_OK;
+}
+
+esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baud_rate)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((baud_rate < UART_BITRATE_MAX), "baud_rate error", ESP_FAIL);
+ uint32_t clk_div = (((UART_CLK_FREQ) << 4) / baud_rate);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ UART[uart_num]->clk_div.div_int = clk_div >> 4;
+ UART[uart_num]->clk_div.div_frag = clk_div & 0xf;
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ uint32_t clk_div = (UART[uart_num]->clk_div.div_int << 4) | UART[uart_num]->clk_div.div_frag;
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ (*baudrate) = ((UART_CLK_FREQ) << 4) / clk_div;
+ return ESP_OK;
+}
+
+esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((((inverse_mask & UART_LINE_INV_MASK) == 0) && (inverse_mask != 0)), "inverse_mask error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ CLEAR_PERI_REG_MASK(UART_CONF0_REG(uart_num), UART_LINE_INV_MASK);
+ SET_PERI_REG_MASK(UART_CONF0_REG(uart_num), inverse_mask);
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+//only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set.
+esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((rx_thresh < UART_FIFO_LEN), "rx flow thresh error", ESP_FAIL);
+ UART_CHECK((flow_ctrl < UART_HW_FLOWCTRL_MAX), "hw_flowctrl mode error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ if(flow_ctrl & UART_HW_FLOWCTRL_RTS) {
+ UART[uart_num]->conf1.rx_flow_thrhd = rx_thresh;
+ UART[uart_num]->conf1.rx_flow_en = 1;
+ } else {
+ UART[uart_num]->conf1.rx_flow_en = 0;
+ }
+ if(flow_ctrl & UART_HW_FLOWCTRL_CTS) {
+ UART[uart_num]->conf0.tx_flow_en = 1;
+ } else {
+ UART[uart_num]->conf0.tx_flow_en = 0;
+ }
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ uart_hw_flowcontrol_t val = UART_HW_FLOWCTRL_DISABLE;
+ if(UART[uart_num]->conf1.rx_flow_en) {
+ val |= UART_HW_FLOWCTRL_RTS;
+ }
+ if(UART[uart_num]->conf0.tx_flow_en) {
+ val |= UART_HW_FLOWCTRL_CTS;
+ }
+ (*flow_ctrl) = val;
+ return ESP_OK;
+}
+
+static esp_err_t uart_reset_fifo(uart_port_t uart_num)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ UART[uart_num]->conf0.rxfifo_rst = 1;
+ UART[uart_num]->conf0.rxfifo_rst = 0;
+ UART[uart_num]->conf0.txfifo_rst = 1;
+ UART[uart_num]->conf0.txfifo_rst = 0;
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ //intr_clr register is write-only
+ UART[uart_num]->int_clr.val = clr_mask;
+ return ESP_OK;
+}
+
+esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ SET_PERI_REG_MASK(UART_INT_CLR_REG(uart_num), enable_mask);
+ SET_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), enable_mask);
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), disable_mask);
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+esp_err_t uart_enable_rx_intr(uart_port_t uart_num)
+{
+ uart_enable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
+ return ESP_OK;
+}
+
+esp_err_t uart_disable_rx_intr(uart_port_t uart_num)
+{
+ uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
+ return ESP_OK;
+}
+
+esp_err_t uart_disable_tx_intr(uart_port_t uart_num)
+{
+ uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA);
+ return ESP_OK;
+}
+
+esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((thresh < UART_FIFO_LEN), "empty intr threshold error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ UART[uart_num]->int_clr.txfifo_empty = 1;
+ UART[uart_num]->conf1.txfifo_empty_thrhd = thresh & UART_TXFIFO_EMPTY_THRHD_V;
+ UART[uart_num]->int_ena.txfifo_empty = enable & 0x1;
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags)
+{
int ret;
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- switch(uart_num) {\r
- case UART_NUM_1:\r
- ret=esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);\r
- break;\r
- case UART_NUM_2:\r
- ret=esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);\r
- break;\r
- case UART_NUM_0:\r
- default:\r
- ret=esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);\r
- break;\r
- }\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ret;\r
-}\r
-\r
-\r
-esp_err_t uart_isr_free(uart_port_t uart_num)\r
-{\r
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ switch(uart_num) {
+ case UART_NUM_1:
+ ret=esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);
+ break;
+ case UART_NUM_2:
+ ret=esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);
+ break;
+ case UART_NUM_0:
+ default:
+ ret=esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);
+ break;
+ }
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ret;
+}
+
+
+esp_err_t uart_isr_free(uart_port_t uart_num)
+{
esp_err_t ret;
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- if (p_uart_obj[uart_num]->intr_handle==NULL) return ESP_ERR_INVALID_ARG;\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- ret=esp_intr_free(p_uart_obj[uart_num]->intr_handle);\r
- p_uart_obj[uart_num]->intr_handle=NULL;\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ret;\r
-}\r
-\r
-//internal signal can be output to multiple GPIO pads\r
-//only one GPIO pad can connect with input signal\r
-esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((tx_io_num < 0 || (GPIO_IS_VALID_OUTPUT_GPIO(tx_io_num))), "tx_io_num error", ESP_FAIL);\r
- UART_CHECK((rx_io_num < 0 || (GPIO_IS_VALID_GPIO(rx_io_num))), "rx_io_num error", ESP_FAIL);\r
- UART_CHECK((rts_io_num < 0 || (GPIO_IS_VALID_OUTPUT_GPIO(rts_io_num))), "rts_io_num error", ESP_FAIL);\r
- UART_CHECK((cts_io_num < 0 || (GPIO_IS_VALID_GPIO(cts_io_num))), "cts_io_num error", ESP_FAIL);\r
-\r
- int tx_sig, rx_sig, rts_sig, cts_sig;\r
- switch(uart_num) {\r
- case UART_NUM_0:\r
- tx_sig = U0TXD_OUT_IDX;\r
- rx_sig = U0RXD_IN_IDX;\r
- rts_sig = U0RTS_OUT_IDX;\r
- cts_sig = U0CTS_IN_IDX;\r
- break;\r
- case UART_NUM_1:\r
- tx_sig = U1TXD_OUT_IDX;\r
- rx_sig = U1RXD_IN_IDX;\r
- rts_sig = U1RTS_OUT_IDX;\r
- cts_sig = U1CTS_IN_IDX;\r
- break;\r
- case UART_NUM_2:\r
- tx_sig = U2TXD_OUT_IDX;\r
- rx_sig = U2RXD_IN_IDX;\r
- rts_sig = U2RTS_OUT_IDX;\r
- cts_sig = U2CTS_IN_IDX;\r
- break;\r
- case UART_NUM_MAX:\r
- default:\r
- tx_sig = U0TXD_OUT_IDX;\r
- rx_sig = U0RXD_IN_IDX;\r
- rts_sig = U0RTS_OUT_IDX;\r
- cts_sig = U0CTS_IN_IDX;\r
- break;\r
- }\r
- if(tx_io_num >= 0) {\r
- PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[tx_io_num], PIN_FUNC_GPIO);\r
- gpio_set_direction(tx_io_num, GPIO_MODE_OUTPUT);\r
- gpio_matrix_out(tx_io_num, tx_sig, 0, 0);\r
- }\r
-\r
- if(rx_io_num >= 0) {\r
- PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rx_io_num], PIN_FUNC_GPIO);\r
- gpio_set_direction(rx_io_num, GPIO_MODE_INPUT);\r
- gpio_matrix_in(rx_io_num, rx_sig, 0);\r
- }\r
- if(rts_io_num >= 0) {\r
- PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rts_io_num], PIN_FUNC_GPIO);\r
- gpio_set_direction(rts_io_num, GPIO_MODE_OUTPUT);\r
- gpio_matrix_out(rts_io_num, rts_sig, 0, 0);\r
- }\r
- if(cts_io_num >= 0) {\r
- PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cts_io_num], PIN_FUNC_GPIO);\r
- gpio_set_direction(cts_io_num, GPIO_MODE_INPUT);\r
- gpio_matrix_in(cts_io_num, cts_sig, 0);\r
- }\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_set_rts(uart_port_t uart_num, int level)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((UART[uart_num]->conf1.rx_flow_en != 1), "disable hw flowctrl before using sw control", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- UART[uart_num]->conf0.sw_rts = level & 0x1;\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_set_dtr(uart_port_t uart_num, int level)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- UART[uart_num]->conf0.sw_dtr = level & 0x1;\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((uart_config), "param null", ESP_FAIL);\r
- if(uart_num == UART_NUM_0) {\r
- periph_module_enable(PERIPH_UART0_MODULE);\r
- } else if(uart_num == UART_NUM_1) {\r
- periph_module_enable(PERIPH_UART1_MODULE);\r
- } else if(uart_num == UART_NUM_2) {\r
- periph_module_enable(PERIPH_UART2_MODULE);\r
- }\r
- uart_set_hw_flow_ctrl(uart_num, uart_config->flow_ctrl, uart_config->rx_flow_ctrl_thresh);\r
- uart_set_baudrate(uart_num, uart_config->baud_rate);\r
- UART[uart_num]->conf0.val = (\r
- (uart_config->parity << UART_PARITY_S)\r
- | (uart_config->stop_bits << UART_STOP_BIT_NUM_S)\r
- | (uart_config->data_bits << UART_BIT_NUM_S)\r
- | ((uart_config->flow_ctrl & UART_HW_FLOWCTRL_CTS) ? UART_TX_FLOW_EN : 0x0)\r
- | UART_TICK_REF_ALWAYS_ON_M);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((intr_conf), "param null", ESP_FAIL);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- UART[uart_num]->int_clr.val = UART_INTR_MASK;\r
- if(intr_conf->intr_enable_mask & UART_RXFIFO_TOUT_INT_ENA_M) {\r
- UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V);\r
- UART[uart_num]->conf1.rx_tout_en = 1;\r
- } else {\r
- UART[uart_num]->conf1.rx_tout_en = 0;\r
- }\r
- if(intr_conf->intr_enable_mask & UART_RXFIFO_FULL_INT_ENA_M) {\r
- UART[uart_num]->conf1.rxfifo_full_thrhd = intr_conf->rxfifo_full_thresh;\r
- }\r
- if(intr_conf->intr_enable_mask & UART_TXFIFO_EMPTY_INT_ENA_M) {\r
- UART[uart_num]->conf1.txfifo_empty_thrhd = intr_conf->txfifo_empty_intr_thresh;\r
- }\r
- UART[uart_num]->int_ena.val = intr_conf->intr_enable_mask;\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_FAIL;\r
-}\r
-\r
-//internal isr handler for default driver code.\r
-static void IRAM_ATTR uart_rx_intr_handler_default(void *param)\r
-{\r
- uart_obj_t *p_uart = (uart_obj_t*) param;\r
- uint8_t uart_num = p_uart->uart_num;\r
- uart_dev_t* uart_reg = UART[uart_num];\r
- uint8_t buf_idx = 0;\r
- uint32_t uart_intr_status = UART[uart_num]->int_st.val;\r
- int rx_fifo_len = 0;\r
- uart_event_t uart_event;\r
- portBASE_TYPE HPTaskAwoken = 0;\r
-\r
- while(uart_intr_status != 0x0) {\r
- buf_idx = 0;\r
- uart_event.type = UART_EVENT_MAX;\r
- if(uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M) {\r
- UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_reg->int_ena.txfifo_empty = 0;\r
- uart_reg->int_clr.txfifo_empty = 1;\r
- UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- if(p_uart->tx_waiting_brk) {\r
- continue;\r
- }\r
- //TX semaphore will only be used when tx_buf_size is zero.\r
- if(p_uart->tx_waiting_fifo == true && p_uart->tx_buf_size == 0) {\r
- p_uart->tx_waiting_fifo = false;\r
- xSemaphoreGiveFromISR(p_uart->tx_fifo_sem, &HPTaskAwoken);\r
- if(HPTaskAwoken == pdTRUE) {\r
- portYIELD_FROM_ISR() ;\r
- }\r
- }\r
- else {\r
- //We don't use TX ring buffer, because the size is zero.\r
- if(p_uart->tx_buf_size == 0) {\r
- continue;\r
- }\r
- int tx_fifo_rem = UART_FIFO_LEN - UART[uart_num]->status.txfifo_cnt;\r
- bool en_tx_flg = false;\r
- //We need to put a loop here, in case all the buffer items are very short.\r
- //That would cause a watch_dog reset because empty interrupt happens so often.\r
- //Although this is a loop in ISR, this loop will execute at most 128 turns.\r
- while(tx_fifo_rem) {\r
- if(p_uart->tx_len_tot == 0 || p_uart->tx_ptr == NULL || p_uart->tx_len_cur == 0) {\r
- size_t size;\r
- p_uart->tx_head = (uart_tx_data_t*) xRingbufferReceiveFromISR(p_uart->tx_ring_buf, &size);\r
- if(p_uart->tx_head) {\r
- //The first item is the data description\r
- //Get the first item to get the data information\r
- if(p_uart->tx_len_tot == 0) {\r
- p_uart->tx_ptr = NULL;\r
- p_uart->tx_len_tot = p_uart->tx_head->tx_data.size;\r
- if(p_uart->tx_head->type == UART_DATA_BREAK) {\r
- p_uart->tx_len_tot = p_uart->tx_head->tx_data.size;\r
- p_uart->tx_brk_flg = 1;\r
- p_uart->tx_brk_len = p_uart->tx_head->tx_data.brk_len;\r
- }\r
- //We have saved the data description from the 1st item, return buffer.\r
- vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken);\r
- if(HPTaskAwoken == pdTRUE) {\r
- portYIELD_FROM_ISR() ;\r
- }\r
- }else if(p_uart->tx_ptr == NULL) {\r
- //Update the TX item pointer, we will need this to return item to buffer.\r
- p_uart->tx_ptr = (uint8_t*) p_uart->tx_head;\r
- en_tx_flg = true;\r
- p_uart->tx_len_cur = size;\r
- }\r
- }\r
- else {\r
- //Can not get data from ring buffer, return;\r
- break;\r
- }\r
- }\r
- if(p_uart->tx_len_tot > 0 && p_uart->tx_ptr && p_uart->tx_len_cur > 0) {\r
- //To fill the TX FIFO.\r
- int send_len = p_uart->tx_len_cur > tx_fifo_rem ? tx_fifo_rem : p_uart->tx_len_cur;\r
- for(buf_idx = 0; buf_idx < send_len; buf_idx++) {\r
- WRITE_PERI_REG(UART_FIFO_AHB_REG(uart_num), *(p_uart->tx_ptr++) & 0xff);\r
- }\r
- p_uart->tx_len_tot -= send_len;\r
- p_uart->tx_len_cur -= send_len;\r
- tx_fifo_rem -= send_len;\r
- if(p_uart->tx_len_cur == 0) {\r
- //Return item to ring buffer.\r
- vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken);\r
- if(HPTaskAwoken == pdTRUE) {\r
- portYIELD_FROM_ISR() ;\r
- }\r
- p_uart->tx_head = NULL;\r
- p_uart->tx_ptr = NULL;\r
- //Sending item done, now we need to send break if there is a record.\r
- //Set TX break signal after FIFO is empty\r
- if(p_uart->tx_brk_flg == 1 && p_uart->tx_len_tot == 0) {\r
- UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_reg->int_ena.tx_brk_done = 0;\r
- uart_reg->idle_conf.tx_brk_num = p_uart->tx_brk_len;\r
- uart_reg->conf0.txd_brk = 1;\r
- uart_reg->int_clr.tx_brk_done = 1;\r
- uart_reg->int_ena.tx_brk_done = 1;\r
- UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- p_uart->tx_waiting_brk = 1;\r
- } else {\r
- //enable TX empty interrupt\r
- en_tx_flg = true;\r
- }\r
- } else {\r
- //enable TX empty interrupt\r
- en_tx_flg = true;\r
- }\r
- }\r
- }\r
- if(en_tx_flg) {\r
- UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_reg->int_clr.txfifo_empty = 1;\r
- uart_reg->int_ena.txfifo_empty = 1;\r
- UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- }\r
- }\r
- }\r
- else if((uart_intr_status & UART_RXFIFO_TOUT_INT_ST_M) || (uart_intr_status & UART_RXFIFO_FULL_INT_ST_M)) {\r
- if(p_uart->rx_buffer_full_flg == false) {\r
- //Get the buffer from the FIFO\r
- rx_fifo_len = uart_reg->status.rxfifo_cnt;\r
- p_uart->rx_stash_len = rx_fifo_len;\r
- //We have to read out all data in RX FIFO to clear the interrupt signal\r
- while(buf_idx < rx_fifo_len) {\r
- p_uart->rx_data_buf[buf_idx++] = uart_reg->fifo.rw_byte;\r
- }\r
- //After Copying the Data From FIFO ,Clear intr_status\r
- UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_reg->int_clr.rxfifo_tout = 1;\r
- uart_reg->int_clr.rxfifo_full = 1;\r
- UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_event.type = UART_DATA;\r
- uart_event.size = rx_fifo_len;\r
- //If we fail to push data to ring buffer, we will have to stash the data, and send next time.\r
- //Mainly for applications that uses flow control or small ring buffer.\r
- if(pdFALSE == xRingbufferSendFromISR(p_uart->rx_ring_buf, p_uart->rx_data_buf, p_uart->rx_stash_len, &HPTaskAwoken)) {\r
- UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_reg->int_ena.rxfifo_full = 0;\r
- uart_reg->int_ena.rxfifo_tout = 0;\r
- UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- p_uart->rx_buffer_full_flg = true;\r
- uart_event.type = UART_BUFFER_FULL;\r
- } else {\r
- uart_event.type = UART_DATA;\r
- }\r
- if(HPTaskAwoken == pdTRUE) {\r
- portYIELD_FROM_ISR() ;\r
- }\r
- } else {\r
- UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_reg->int_ena.rxfifo_full = 0;\r
- uart_reg->int_ena.rxfifo_tout = 0;\r
- uart_reg->int_clr.val = UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M;\r
- UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_event.type = UART_BUFFER_FULL;\r
- }\r
- } else if(uart_intr_status & UART_RXFIFO_OVF_INT_ST_M) {\r
- UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_reg->conf0.rxfifo_rst = 1;\r
- uart_reg->conf0.rxfifo_rst = 0;\r
- uart_reg->int_clr.rxfifo_ovf = 1;\r
- UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_event.type = UART_FIFO_OVF;\r
- } else if(uart_intr_status & UART_BRK_DET_INT_ST_M) {\r
- uart_reg->int_clr.brk_det = 1;\r
- uart_event.type = UART_BREAK;\r
- } else if(uart_intr_status & UART_PARITY_ERR_INT_ST_M ) {\r
- uart_reg->int_clr.parity_err = 1;\r
- uart_event.type = UART_FRAME_ERR;\r
- } else if(uart_intr_status & UART_FRM_ERR_INT_ST_M) {\r
- uart_reg->int_clr.frm_err = 1;\r
- uart_event.type = UART_PARITY_ERR;\r
- } else if(uart_intr_status & UART_TX_BRK_DONE_INT_ST_M) {\r
- UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_reg->conf0.txd_brk = 0;\r
- uart_reg->int_ena.tx_brk_done = 0;\r
- uart_reg->int_clr.tx_brk_done = 1;\r
- if(p_uart->tx_brk_flg == 1) {\r
- uart_reg->int_ena.txfifo_empty = 1;\r
- }\r
- UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- if(p_uart->tx_brk_flg == 1) {\r
- p_uart->tx_brk_flg = 0;\r
- p_uart->tx_waiting_brk = 0;\r
- } else {\r
- xSemaphoreGiveFromISR(p_uart->tx_brk_sem, &HPTaskAwoken);\r
- if(HPTaskAwoken == pdTRUE) {\r
- portYIELD_FROM_ISR() ;\r
- }\r
- }\r
- } else if(uart_intr_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) {\r
- UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_reg->int_ena.tx_brk_idle_done = 0;\r
- uart_reg->int_clr.tx_brk_idle_done = 1;\r
- UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- } else if(uart_intr_status & UART_TX_DONE_INT_ST_M) {\r
- UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- uart_reg->int_ena.tx_done = 0;\r
- uart_reg->int_clr.tx_done = 1;\r
- UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);\r
- xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken);\r
- if(HPTaskAwoken == pdTRUE) {\r
- portYIELD_FROM_ISR() ;\r
- }\r
- }\r
- else {\r
- uart_reg->int_clr.val = uart_intr_status; /*simply clear all other intr status*/\r
- uart_event.type = UART_EVENT_MAX;\r
- }\r
-\r
- if(uart_event.type != UART_EVENT_MAX && p_uart->xQueueUart) {\r
- xQueueSendFromISR(p_uart->xQueueUart, (void * )&uart_event, &HPTaskAwoken);\r
- if(HPTaskAwoken == pdTRUE) {\r
- portYIELD_FROM_ISR() ;\r
- }\r
- }\r
- uart_intr_status = uart_reg->int_st.val;\r
- }\r
-}\r
-\r
-/**************************************************************/\r
-esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL);\r
- BaseType_t res;\r
- portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait;\r
- //Take tx_mux\r
- res = xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)ticks_to_wait);\r
- if(res == pdFALSE) {\r
- return ESP_ERR_TIMEOUT;\r
- }\r
- ticks_to_wait = ticks_end - xTaskGetTickCount();\r
- xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, 0);\r
- ticks_to_wait = ticks_end - xTaskGetTickCount();\r
- if(UART[uart_num]->status.txfifo_cnt == 0) {\r
- xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);\r
- return ESP_OK;\r
- }\r
- uart_enable_intr_mask(uart_num, UART_TX_DONE_INT_ENA_M);\r
- //take 2nd tx_done_sem, wait given from ISR\r
- res = xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, (portTickType)ticks_to_wait);\r
- if(res == pdFALSE) {\r
- uart_disable_intr_mask(uart_num, UART_TX_DONE_INT_ENA_M);\r
- xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);\r
- return ESP_ERR_TIMEOUT;\r
- }\r
- xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);\r
- return ESP_OK;\r
-}\r
-\r
-static esp_err_t uart_set_break(uart_port_t uart_num, int break_num)\r
-{\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- UART[uart_num]->idle_conf.tx_brk_num = break_num;\r
- UART[uart_num]->conf0.txd_brk = 1;\r
- UART[uart_num]->int_clr.tx_brk_done = 1;\r
- UART[uart_num]->int_ena.tx_brk_done = 1;\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- return ESP_OK;\r
-}\r
-\r
-//Fill UART tx_fifo and return a number,\r
-//This function by itself is not thread-safe, always call from within a muxed section.\r
-static int uart_fill_fifo(uart_port_t uart_num, const char* buffer, uint32_t len)\r
-{\r
- uint8_t i = 0;\r
- uint8_t tx_fifo_cnt = UART[uart_num]->status.txfifo_cnt;\r
- uint8_t tx_remain_fifo_cnt = (UART_FIFO_LEN - tx_fifo_cnt);\r
- uint8_t copy_cnt = (len >= tx_remain_fifo_cnt ? tx_remain_fifo_cnt : len);\r
- for(i = 0; i < copy_cnt; i++) {\r
- WRITE_PERI_REG(UART_FIFO_AHB_REG(uart_num), buffer[i]);\r
- }\r
- return copy_cnt;\r
-}\r
-\r
-int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));\r
- UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1));\r
- UART_CHECK(buffer, "buffer null", (-1));\r
- if(len == 0) {\r
- return 0;\r
- }\r
- xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY);\r
- int tx_len = uart_fill_fifo(uart_num, (const char*) buffer, len);\r
- xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);\r
- return tx_len;\r
-}\r
-\r
-static int uart_tx_all(uart_port_t uart_num, const char* src, size_t size, bool brk_en, int brk_len)\r
-{\r
- if(size == 0) {\r
- return 0;\r
- }\r
- size_t original_size = size;\r
-\r
- //lock for uart_tx\r
- xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY);\r
- if(p_uart_obj[uart_num]->tx_buf_size > 0) {\r
- int max_size = xRingbufferGetMaxItemSize(p_uart_obj[uart_num]->tx_ring_buf);\r
- int offset = 0;\r
- uart_tx_data_t evt;\r
- evt.tx_data.size = size;\r
- evt.tx_data.brk_len = brk_len;\r
- if(brk_en) {\r
- evt.type = UART_DATA_BREAK;\r
- } else {\r
- evt.type = UART_DATA;\r
- }\r
- xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void*) &evt, sizeof(uart_tx_data_t), portMAX_DELAY);\r
- while(size > 0) {\r
- int send_size = size > max_size / 2 ? max_size / 2 : size;\r
- xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void*) (src + offset), send_size, portMAX_DELAY);\r
- size -= send_size;\r
- offset += send_size;\r
- }\r
- xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);\r
- uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT);\r
- } else {\r
- while(size) {\r
- //semaphore for tx_fifo available\r
- if(pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_fifo_sem, (portTickType)portMAX_DELAY)) {\r
- size_t sent = uart_fill_fifo(uart_num, (char*) src, size);\r
- if(sent < size) {\r
- p_uart_obj[uart_num]->tx_waiting_fifo = true;\r
- uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT);\r
- }\r
- size -= sent;\r
- src += sent;\r
- }\r
- }\r
- if(brk_en) {\r
- uart_set_break(uart_num, brk_len);\r
- xSemaphoreTake(p_uart_obj[uart_num]->tx_brk_sem, (portTickType)portMAX_DELAY);\r
- }\r
- xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem);\r
- }\r
- xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);\r
- return original_size;\r
-}\r
-\r
-int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));\r
- UART_CHECK((p_uart_obj[uart_num] != NULL), "uart driver error", (-1));\r
- UART_CHECK(src, "buffer null", (-1));\r
- return uart_tx_all(uart_num, src, size, 0, 0);\r
-}\r
-\r
-int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t size, int brk_len)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));\r
- UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1));\r
- UART_CHECK((size > 0), "uart size error", (-1));\r
- UART_CHECK((src), "uart data null", (-1));\r
- UART_CHECK((brk_len > 0 && brk_len < 256), "break_num error", (-1));\r
- return uart_tx_all(uart_num, src, size, 1, brk_len);\r
-}\r
-\r
-int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));\r
- UART_CHECK((buf), "uart_num error", (-1));\r
- UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1));\r
- uint8_t* data = NULL;\r
- size_t size;\r
- size_t copy_len = 0;\r
- int len_tmp;\r
- if(xSemaphoreTake(p_uart_obj[uart_num]->rx_mux,(portTickType)ticks_to_wait) != pdTRUE) {\r
- return -1;\r
- }\r
- while(length) {\r
- if(p_uart_obj[uart_num]->rx_cur_remain == 0) {\r
- data = (uint8_t*) xRingbufferReceive(p_uart_obj[uart_num]->rx_ring_buf, &size, (portTickType) ticks_to_wait);\r
- if(data) {\r
- p_uart_obj[uart_num]->rx_head_ptr = data;\r
- p_uart_obj[uart_num]->rx_ptr = data;\r
- p_uart_obj[uart_num]->rx_cur_remain = size;\r
- } else {\r
- xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);\r
- return copy_len;\r
- }\r
- }\r
- if(p_uart_obj[uart_num]->rx_cur_remain > length) {\r
- len_tmp = length;\r
- } else {\r
- len_tmp = p_uart_obj[uart_num]->rx_cur_remain;\r
- }\r
- memcpy(buf + copy_len, p_uart_obj[uart_num]->rx_ptr, len_tmp);\r
- p_uart_obj[uart_num]->rx_ptr += len_tmp;\r
- p_uart_obj[uart_num]->rx_cur_remain -= len_tmp;\r
- copy_len += len_tmp;\r
- length -= len_tmp;\r
- if(p_uart_obj[uart_num]->rx_cur_remain == 0) {\r
- vRingbufferReturnItem(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_head_ptr);\r
- p_uart_obj[uart_num]->rx_head_ptr = NULL;\r
- p_uart_obj[uart_num]->rx_ptr = NULL;\r
- if(p_uart_obj[uart_num]->rx_buffer_full_flg) {\r
- BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1);\r
- if(res == pdTRUE) {\r
- p_uart_obj[uart_num]->rx_buffer_full_flg = false;\r
- uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num);\r
- }\r
- }\r
- }\r
- }\r
- xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);\r
- return copy_len;\r
-}\r
-\r
-esp_err_t uart_flush(uart_port_t uart_num)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL);\r
- uart_obj_t* p_uart = p_uart_obj[uart_num];\r
- uint8_t* data;\r
- size_t size;\r
-\r
- //rx sem protect the ring buffer read related functions\r
- xSemaphoreTake(p_uart->rx_mux, (portTickType)portMAX_DELAY);\r
- esp_intr_disable(p_uart->intr_handle);\r
- while(true) {\r
- if(p_uart->rx_head_ptr) {\r
- vRingbufferReturnItem(p_uart->rx_ring_buf, p_uart->rx_head_ptr);\r
- p_uart->rx_ptr = NULL;\r
- p_uart->rx_cur_remain = 0;\r
- p_uart->rx_head_ptr = NULL;\r
- }\r
- data = (uint8_t*) xRingbufferReceive(p_uart->rx_ring_buf, &size, (portTickType) 0);\r
- if(data == NULL) {\r
- break;\r
- }\r
- vRingbufferReturnItem(p_uart->rx_ring_buf, data);\r
- }\r
- p_uart->rx_ptr = NULL;\r
- p_uart->rx_cur_remain = 0;\r
- p_uart->rx_head_ptr = NULL;\r
- esp_intr_enable(p_uart->intr_handle);\r
- xSemaphoreGive(p_uart->rx_mux);\r
-\r
- if(p_uart->tx_buf_size > 0) {\r
- xSemaphoreTake(p_uart->tx_mux, (portTickType)portMAX_DELAY);\r
- esp_intr_disable(p_uart->intr_handle);\r
- UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
- UART[uart_num]->int_ena.txfifo_empty = 0;\r
- UART[uart_num]->int_clr.txfifo_empty = 1;\r
- UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
- do {\r
- data = (uint8_t*) xRingbufferReceive(p_uart->tx_ring_buf, &size, (portTickType) 0);\r
- if(data == NULL) {\r
- break;\r
- }\r
- vRingbufferReturnItem(p_uart->rx_ring_buf, data);\r
- } while(1);\r
- p_uart->tx_brk_flg = 0;\r
- p_uart->tx_brk_len = 0;\r
- p_uart->tx_head = NULL;\r
- p_uart->tx_len_cur = 0;\r
- p_uart->tx_len_tot = 0;\r
- p_uart->tx_ptr = NULL;\r
- p_uart->tx_waiting_brk = 0;\r
- p_uart->tx_waiting_fifo = false;\r
- esp_intr_enable(p_uart->intr_handle);\r
- xSemaphoreGive(p_uart->tx_mux);\r
- }\r
- uart_reset_fifo(uart_num);\r
- return ESP_OK;\r
-}\r
-\r
-esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, void* uart_queue, int intr_alloc_flags)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- UART_CHECK((rx_buffer_size > 0), "uart rx buffer length error", ESP_FAIL);\r
- if(p_uart_obj[uart_num] == NULL) {\r
- p_uart_obj[uart_num] = (uart_obj_t*) malloc(sizeof(uart_obj_t));\r
- if(p_uart_obj[uart_num] == NULL) {\r
- ESP_LOGE(UART_TAG, "UART driver malloc error");\r
- return ESP_FAIL;\r
- }\r
- p_uart_obj[uart_num]->uart_num = uart_num;\r
- p_uart_obj[uart_num]->tx_fifo_sem = xSemaphoreCreateBinary();\r
- xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem);\r
- p_uart_obj[uart_num]->tx_done_sem = xSemaphoreCreateBinary();\r
- p_uart_obj[uart_num]->tx_brk_sem = xSemaphoreCreateBinary();\r
- p_uart_obj[uart_num]->tx_mux = xSemaphoreCreateMutex();\r
- p_uart_obj[uart_num]->rx_mux = xSemaphoreCreateMutex();\r
- p_uart_obj[uart_num]->queue_size = queue_size;\r
- p_uart_obj[uart_num]->tx_ptr = NULL;\r
- p_uart_obj[uart_num]->tx_head = NULL;\r
- p_uart_obj[uart_num]->tx_len_tot = 0;\r
- p_uart_obj[uart_num]->tx_brk_flg = 0;\r
- p_uart_obj[uart_num]->tx_brk_len = 0;\r
- p_uart_obj[uart_num]->tx_waiting_brk = 0;\r
-\r
- if(uart_queue) {\r
- p_uart_obj[uart_num]->xQueueUart = xQueueCreate(queue_size, sizeof(uart_event_t));\r
- *((QueueHandle_t*) uart_queue) = p_uart_obj[uart_num]->xQueueUart;\r
- ESP_LOGI(UART_TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_uart_obj[uart_num]->xQueueUart));\r
- } else {\r
- p_uart_obj[uart_num]->xQueueUart = NULL;\r
- }\r
- p_uart_obj[uart_num]->rx_buffer_full_flg = false;\r
- p_uart_obj[uart_num]->tx_waiting_fifo = false;\r
- p_uart_obj[uart_num]->rx_ptr = NULL;\r
- p_uart_obj[uart_num]->rx_cur_remain = 0;\r
- p_uart_obj[uart_num]->rx_head_ptr = NULL;\r
- p_uart_obj[uart_num]->rx_ring_buf = xRingbufferCreate(rx_buffer_size, RINGBUF_TYPE_BYTEBUF);\r
- if(tx_buffer_size > 0) {\r
- p_uart_obj[uart_num]->tx_ring_buf = xRingbufferCreate(tx_buffer_size, RINGBUF_TYPE_NOSPLIT);\r
- p_uart_obj[uart_num]->tx_buf_size = tx_buffer_size;\r
- } else {\r
- p_uart_obj[uart_num]->tx_ring_buf = NULL;\r
- p_uart_obj[uart_num]->tx_buf_size = 0;\r
- }\r
- } else {\r
- ESP_LOGE(UART_TAG, "UART driver already installed");\r
- return ESP_FAIL;\r
- }\r
- uart_isr_register(uart_num, uart_rx_intr_handler_default, p_uart_obj[uart_num], intr_alloc_flags);\r
- uart_intr_config_t uart_intr = {\r
- .intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M\r
- | UART_RXFIFO_TOUT_INT_ENA_M\r
- | UART_FRM_ERR_INT_ENA_M\r
- | UART_RXFIFO_OVF_INT_ENA_M\r
- | UART_BRK_DET_INT_ENA_M\r
- | UART_PARITY_ERR_INT_ENA_M,\r
- .rxfifo_full_thresh = UART_FULL_THRESH_DEFAULT,\r
- .rx_timeout_thresh = UART_TOUT_THRESH_DEFAULT,\r
- .txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT\r
- };\r
- uart_intr_config(uart_num, &uart_intr);\r
- return ESP_OK;\r
-}\r
-\r
-//Make sure no other tasks are still using UART before you call this function\r
-esp_err_t uart_driver_delete(uart_port_t uart_num)\r
-{\r
- UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
- if(p_uart_obj[uart_num] == NULL) {\r
- ESP_LOGI(UART_TAG, "ALREADY NULL");\r
- return ESP_OK;\r
- }\r
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ if (p_uart_obj[uart_num]->intr_handle==NULL) return ESP_ERR_INVALID_ARG;
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ ret=esp_intr_free(p_uart_obj[uart_num]->intr_handle);
+ p_uart_obj[uart_num]->intr_handle=NULL;
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ret;
+}
+
+//internal signal can be output to multiple GPIO pads
+//only one GPIO pad can connect with input signal
+esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((tx_io_num < 0 || (GPIO_IS_VALID_OUTPUT_GPIO(tx_io_num))), "tx_io_num error", ESP_FAIL);
+ UART_CHECK((rx_io_num < 0 || (GPIO_IS_VALID_GPIO(rx_io_num))), "rx_io_num error", ESP_FAIL);
+ UART_CHECK((rts_io_num < 0 || (GPIO_IS_VALID_OUTPUT_GPIO(rts_io_num))), "rts_io_num error", ESP_FAIL);
+ UART_CHECK((cts_io_num < 0 || (GPIO_IS_VALID_GPIO(cts_io_num))), "cts_io_num error", ESP_FAIL);
+
+ int tx_sig, rx_sig, rts_sig, cts_sig;
+ switch(uart_num) {
+ case UART_NUM_0:
+ tx_sig = U0TXD_OUT_IDX;
+ rx_sig = U0RXD_IN_IDX;
+ rts_sig = U0RTS_OUT_IDX;
+ cts_sig = U0CTS_IN_IDX;
+ break;
+ case UART_NUM_1:
+ tx_sig = U1TXD_OUT_IDX;
+ rx_sig = U1RXD_IN_IDX;
+ rts_sig = U1RTS_OUT_IDX;
+ cts_sig = U1CTS_IN_IDX;
+ break;
+ case UART_NUM_2:
+ tx_sig = U2TXD_OUT_IDX;
+ rx_sig = U2RXD_IN_IDX;
+ rts_sig = U2RTS_OUT_IDX;
+ cts_sig = U2CTS_IN_IDX;
+ break;
+ case UART_NUM_MAX:
+ default:
+ tx_sig = U0TXD_OUT_IDX;
+ rx_sig = U0RXD_IN_IDX;
+ rts_sig = U0RTS_OUT_IDX;
+ cts_sig = U0CTS_IN_IDX;
+ break;
+ }
+ if(tx_io_num >= 0) {
+ PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[tx_io_num], PIN_FUNC_GPIO);
+ gpio_set_direction(tx_io_num, GPIO_MODE_OUTPUT);
+ gpio_matrix_out(tx_io_num, tx_sig, 0, 0);
+ }
+
+ if(rx_io_num >= 0) {
+ PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rx_io_num], PIN_FUNC_GPIO);
+ gpio_set_direction(rx_io_num, GPIO_MODE_INPUT);
+ gpio_matrix_in(rx_io_num, rx_sig, 0);
+ }
+ if(rts_io_num >= 0) {
+ PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rts_io_num], PIN_FUNC_GPIO);
+ gpio_set_direction(rts_io_num, GPIO_MODE_OUTPUT);
+ gpio_matrix_out(rts_io_num, rts_sig, 0, 0);
+ }
+ if(cts_io_num >= 0) {
+ PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cts_io_num], PIN_FUNC_GPIO);
+ gpio_set_direction(cts_io_num, GPIO_MODE_INPUT);
+ gpio_matrix_in(cts_io_num, cts_sig, 0);
+ }
+ return ESP_OK;
+}
+
+esp_err_t uart_set_rts(uart_port_t uart_num, int level)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((UART[uart_num]->conf1.rx_flow_en != 1), "disable hw flowctrl before using sw control", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ UART[uart_num]->conf0.sw_rts = level & 0x1;
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+esp_err_t uart_set_dtr(uart_port_t uart_num, int level)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ UART[uart_num]->conf0.sw_dtr = level & 0x1;
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((uart_config), "param null", ESP_FAIL);
+ if(uart_num == UART_NUM_0) {
+ periph_module_enable(PERIPH_UART0_MODULE);
+ } else if(uart_num == UART_NUM_1) {
+ periph_module_enable(PERIPH_UART1_MODULE);
+ } else if(uart_num == UART_NUM_2) {
+ periph_module_enable(PERIPH_UART2_MODULE);
+ }
+ uart_set_hw_flow_ctrl(uart_num, uart_config->flow_ctrl, uart_config->rx_flow_ctrl_thresh);
+ uart_set_baudrate(uart_num, uart_config->baud_rate);
+ UART[uart_num]->conf0.val = (
+ (uart_config->parity << UART_PARITY_S)
+ | (uart_config->stop_bits << UART_STOP_BIT_NUM_S)
+ | (uart_config->data_bits << UART_BIT_NUM_S)
+ | ((uart_config->flow_ctrl & UART_HW_FLOWCTRL_CTS) ? UART_TX_FLOW_EN : 0x0)
+ | UART_TICK_REF_ALWAYS_ON_M);
+ return ESP_OK;
+}
+
+esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((intr_conf), "param null", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ UART[uart_num]->int_clr.val = UART_INTR_MASK;
+ if(intr_conf->intr_enable_mask & UART_RXFIFO_TOUT_INT_ENA_M) {
+ UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V);
+ UART[uart_num]->conf1.rx_tout_en = 1;
+ } else {
+ UART[uart_num]->conf1.rx_tout_en = 0;
+ }
+ if(intr_conf->intr_enable_mask & UART_RXFIFO_FULL_INT_ENA_M) {
+ UART[uart_num]->conf1.rxfifo_full_thrhd = intr_conf->rxfifo_full_thresh;
+ }
+ if(intr_conf->intr_enable_mask & UART_TXFIFO_EMPTY_INT_ENA_M) {
+ UART[uart_num]->conf1.txfifo_empty_thrhd = intr_conf->txfifo_empty_intr_thresh;
+ }
+ UART[uart_num]->int_ena.val = intr_conf->intr_enable_mask;
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_FAIL;
+}
+
+//internal isr handler for default driver code.
+static void IRAM_ATTR uart_rx_intr_handler_default(void *param)
+{
+ uart_obj_t *p_uart = (uart_obj_t*) param;
+ uint8_t uart_num = p_uart->uart_num;
+ uart_dev_t* uart_reg = UART[uart_num];
+ uint8_t buf_idx = 0;
+ uint32_t uart_intr_status = UART[uart_num]->int_st.val;
+ int rx_fifo_len = 0;
+ uart_event_t uart_event;
+ portBASE_TYPE HPTaskAwoken = 0;
+
+ while(uart_intr_status != 0x0) {
+ buf_idx = 0;
+ uart_event.type = UART_EVENT_MAX;
+ if(uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M) {
+ UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_reg->int_ena.txfifo_empty = 0;
+ uart_reg->int_clr.txfifo_empty = 1;
+ UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ if(p_uart->tx_waiting_brk) {
+ continue;
+ }
+ //TX semaphore will only be used when tx_buf_size is zero.
+ if(p_uart->tx_waiting_fifo == true && p_uart->tx_buf_size == 0) {
+ p_uart->tx_waiting_fifo = false;
+ xSemaphoreGiveFromISR(p_uart->tx_fifo_sem, &HPTaskAwoken);
+ if(HPTaskAwoken == pdTRUE) {
+ portYIELD_FROM_ISR() ;
+ }
+ }
+ else {
+ //We don't use TX ring buffer, because the size is zero.
+ if(p_uart->tx_buf_size == 0) {
+ continue;
+ }
+ int tx_fifo_rem = UART_FIFO_LEN - UART[uart_num]->status.txfifo_cnt;
+ bool en_tx_flg = false;
+ //We need to put a loop here, in case all the buffer items are very short.
+ //That would cause a watch_dog reset because empty interrupt happens so often.
+ //Although this is a loop in ISR, this loop will execute at most 128 turns.
+ while(tx_fifo_rem) {
+ if(p_uart->tx_len_tot == 0 || p_uart->tx_ptr == NULL || p_uart->tx_len_cur == 0) {
+ size_t size;
+ p_uart->tx_head = (uart_tx_data_t*) xRingbufferReceiveFromISR(p_uart->tx_ring_buf, &size);
+ if(p_uart->tx_head) {
+ //The first item is the data description
+ //Get the first item to get the data information
+ if(p_uart->tx_len_tot == 0) {
+ p_uart->tx_ptr = NULL;
+ p_uart->tx_len_tot = p_uart->tx_head->tx_data.size;
+ if(p_uart->tx_head->type == UART_DATA_BREAK) {
+ p_uart->tx_len_tot = p_uart->tx_head->tx_data.size;
+ p_uart->tx_brk_flg = 1;
+ p_uart->tx_brk_len = p_uart->tx_head->tx_data.brk_len;
+ }
+ //We have saved the data description from the 1st item, return buffer.
+ vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken);
+ if(HPTaskAwoken == pdTRUE) {
+ portYIELD_FROM_ISR() ;
+ }
+ }else if(p_uart->tx_ptr == NULL) {
+ //Update the TX item pointer, we will need this to return item to buffer.
+ p_uart->tx_ptr = (uint8_t*) p_uart->tx_head;
+ en_tx_flg = true;
+ p_uart->tx_len_cur = size;
+ }
+ }
+ else {
+ //Can not get data from ring buffer, return;
+ break;
+ }
+ }
+ if(p_uart->tx_len_tot > 0 && p_uart->tx_ptr && p_uart->tx_len_cur > 0) {
+ //To fill the TX FIFO.
+ int send_len = p_uart->tx_len_cur > tx_fifo_rem ? tx_fifo_rem : p_uart->tx_len_cur;
+ for(buf_idx = 0; buf_idx < send_len; buf_idx++) {
+ WRITE_PERI_REG(UART_FIFO_AHB_REG(uart_num), *(p_uart->tx_ptr++) & 0xff);
+ }
+ p_uart->tx_len_tot -= send_len;
+ p_uart->tx_len_cur -= send_len;
+ tx_fifo_rem -= send_len;
+ if(p_uart->tx_len_cur == 0) {
+ //Return item to ring buffer.
+ vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken);
+ if(HPTaskAwoken == pdTRUE) {
+ portYIELD_FROM_ISR() ;
+ }
+ p_uart->tx_head = NULL;
+ p_uart->tx_ptr = NULL;
+ //Sending item done, now we need to send break if there is a record.
+ //Set TX break signal after FIFO is empty
+ if(p_uart->tx_brk_flg == 1 && p_uart->tx_len_tot == 0) {
+ UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_reg->int_ena.tx_brk_done = 0;
+ uart_reg->idle_conf.tx_brk_num = p_uart->tx_brk_len;
+ uart_reg->conf0.txd_brk = 1;
+ uart_reg->int_clr.tx_brk_done = 1;
+ uart_reg->int_ena.tx_brk_done = 1;
+ UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ p_uart->tx_waiting_brk = 1;
+ } else {
+ //enable TX empty interrupt
+ en_tx_flg = true;
+ }
+ } else {
+ //enable TX empty interrupt
+ en_tx_flg = true;
+ }
+ }
+ }
+ if(en_tx_flg) {
+ UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_reg->int_clr.txfifo_empty = 1;
+ uart_reg->int_ena.txfifo_empty = 1;
+ UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ }
+ }
+ }
+ else if((uart_intr_status & UART_RXFIFO_TOUT_INT_ST_M) || (uart_intr_status & UART_RXFIFO_FULL_INT_ST_M)) {
+ if(p_uart->rx_buffer_full_flg == false) {
+ //Get the buffer from the FIFO
+ rx_fifo_len = uart_reg->status.rxfifo_cnt;
+ p_uart->rx_stash_len = rx_fifo_len;
+ //We have to read out all data in RX FIFO to clear the interrupt signal
+ while(buf_idx < rx_fifo_len) {
+ p_uart->rx_data_buf[buf_idx++] = uart_reg->fifo.rw_byte;
+ }
+ //After Copying the Data From FIFO ,Clear intr_status
+ UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_reg->int_clr.rxfifo_tout = 1;
+ uart_reg->int_clr.rxfifo_full = 1;
+ UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_event.type = UART_DATA;
+ uart_event.size = rx_fifo_len;
+ //If we fail to push data to ring buffer, we will have to stash the data, and send next time.
+ //Mainly for applications that uses flow control or small ring buffer.
+ if(pdFALSE == xRingbufferSendFromISR(p_uart->rx_ring_buf, p_uart->rx_data_buf, p_uart->rx_stash_len, &HPTaskAwoken)) {
+ UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_reg->int_ena.rxfifo_full = 0;
+ uart_reg->int_ena.rxfifo_tout = 0;
+ UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ p_uart->rx_buffer_full_flg = true;
+ uart_event.type = UART_BUFFER_FULL;
+ } else {
+ uart_event.type = UART_DATA;
+ }
+ if(HPTaskAwoken == pdTRUE) {
+ portYIELD_FROM_ISR() ;
+ }
+ } else {
+ UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_reg->int_ena.rxfifo_full = 0;
+ uart_reg->int_ena.rxfifo_tout = 0;
+ uart_reg->int_clr.val = UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M;
+ UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_event.type = UART_BUFFER_FULL;
+ }
+ } else if(uart_intr_status & UART_RXFIFO_OVF_INT_ST_M) {
+ UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_reg->conf0.rxfifo_rst = 1;
+ uart_reg->conf0.rxfifo_rst = 0;
+ uart_reg->int_clr.rxfifo_ovf = 1;
+ UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_event.type = UART_FIFO_OVF;
+ } else if(uart_intr_status & UART_BRK_DET_INT_ST_M) {
+ uart_reg->int_clr.brk_det = 1;
+ uart_event.type = UART_BREAK;
+ } else if(uart_intr_status & UART_PARITY_ERR_INT_ST_M ) {
+ uart_reg->int_clr.parity_err = 1;
+ uart_event.type = UART_FRAME_ERR;
+ } else if(uart_intr_status & UART_FRM_ERR_INT_ST_M) {
+ uart_reg->int_clr.frm_err = 1;
+ uart_event.type = UART_PARITY_ERR;
+ } else if(uart_intr_status & UART_TX_BRK_DONE_INT_ST_M) {
+ UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_reg->conf0.txd_brk = 0;
+ uart_reg->int_ena.tx_brk_done = 0;
+ uart_reg->int_clr.tx_brk_done = 1;
+ if(p_uart->tx_brk_flg == 1) {
+ uart_reg->int_ena.txfifo_empty = 1;
+ }
+ UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ if(p_uart->tx_brk_flg == 1) {
+ p_uart->tx_brk_flg = 0;
+ p_uart->tx_waiting_brk = 0;
+ } else {
+ xSemaphoreGiveFromISR(p_uart->tx_brk_sem, &HPTaskAwoken);
+ if(HPTaskAwoken == pdTRUE) {
+ portYIELD_FROM_ISR() ;
+ }
+ }
+ } else if(uart_intr_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) {
+ UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_reg->int_ena.tx_brk_idle_done = 0;
+ uart_reg->int_clr.tx_brk_idle_done = 1;
+ UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ } else if(uart_intr_status & UART_TX_DONE_INT_ST_M) {
+ UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ uart_reg->int_ena.tx_done = 0;
+ uart_reg->int_clr.tx_done = 1;
+ UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+ xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken);
+ if(HPTaskAwoken == pdTRUE) {
+ portYIELD_FROM_ISR() ;
+ }
+ }
+ else {
+ uart_reg->int_clr.val = uart_intr_status; /*simply clear all other intr status*/
+ uart_event.type = UART_EVENT_MAX;
+ }
+
+ if(uart_event.type != UART_EVENT_MAX && p_uart->xQueueUart) {
+ xQueueSendFromISR(p_uart->xQueueUart, (void * )&uart_event, &HPTaskAwoken);
+ if(HPTaskAwoken == pdTRUE) {
+ portYIELD_FROM_ISR() ;
+ }
+ }
+ uart_intr_status = uart_reg->int_st.val;
+ }
+}
+
+/**************************************************************/
+esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL);
+ BaseType_t res;
+ portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait;
+ //Take tx_mux
+ res = xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)ticks_to_wait);
+ if(res == pdFALSE) {
+ return ESP_ERR_TIMEOUT;
+ }
+ ticks_to_wait = ticks_end - xTaskGetTickCount();
+ xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, 0);
+ ticks_to_wait = ticks_end - xTaskGetTickCount();
+ if(UART[uart_num]->status.txfifo_cnt == 0) {
+ xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
+ return ESP_OK;
+ }
+ uart_enable_intr_mask(uart_num, UART_TX_DONE_INT_ENA_M);
+ //take 2nd tx_done_sem, wait given from ISR
+ res = xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, (portTickType)ticks_to_wait);
+ if(res == pdFALSE) {
+ uart_disable_intr_mask(uart_num, UART_TX_DONE_INT_ENA_M);
+ xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
+ return ESP_ERR_TIMEOUT;
+ }
+ xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
+ return ESP_OK;
+}
+
+static esp_err_t uart_set_break(uart_port_t uart_num, int break_num)
+{
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ UART[uart_num]->idle_conf.tx_brk_num = break_num;
+ UART[uart_num]->conf0.txd_brk = 1;
+ UART[uart_num]->int_clr.tx_brk_done = 1;
+ UART[uart_num]->int_ena.tx_brk_done = 1;
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
+//Fill UART tx_fifo and return a number,
+//This function by itself is not thread-safe, always call from within a muxed section.
+static int uart_fill_fifo(uart_port_t uart_num, const char* buffer, uint32_t len)
+{
+ uint8_t i = 0;
+ uint8_t tx_fifo_cnt = UART[uart_num]->status.txfifo_cnt;
+ uint8_t tx_remain_fifo_cnt = (UART_FIFO_LEN - tx_fifo_cnt);
+ uint8_t copy_cnt = (len >= tx_remain_fifo_cnt ? tx_remain_fifo_cnt : len);
+ for(i = 0; i < copy_cnt; i++) {
+ WRITE_PERI_REG(UART_FIFO_AHB_REG(uart_num), buffer[i]);
+ }
+ return copy_cnt;
+}
+
+int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));
+ UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1));
+ UART_CHECK(buffer, "buffer null", (-1));
+ if(len == 0) {
+ return 0;
+ }
+ xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY);
+ int tx_len = uart_fill_fifo(uart_num, (const char*) buffer, len);
+ xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
+ return tx_len;
+}
+
+static int uart_tx_all(uart_port_t uart_num, const char* src, size_t size, bool brk_en, int brk_len)
+{
+ if(size == 0) {
+ return 0;
+ }
+ size_t original_size = size;
+
+ //lock for uart_tx
+ xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY);
+ if(p_uart_obj[uart_num]->tx_buf_size > 0) {
+ int max_size = xRingbufferGetMaxItemSize(p_uart_obj[uart_num]->tx_ring_buf);
+ int offset = 0;
+ uart_tx_data_t evt;
+ evt.tx_data.size = size;
+ evt.tx_data.brk_len = brk_len;
+ if(brk_en) {
+ evt.type = UART_DATA_BREAK;
+ } else {
+ evt.type = UART_DATA;
+ }
+ xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void*) &evt, sizeof(uart_tx_data_t), portMAX_DELAY);
+ while(size > 0) {
+ int send_size = size > max_size / 2 ? max_size / 2 : size;
+ xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void*) (src + offset), send_size, portMAX_DELAY);
+ size -= send_size;
+ offset += send_size;
+ }
+ xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
+ uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT);
+ } else {
+ while(size) {
+ //semaphore for tx_fifo available
+ if(pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_fifo_sem, (portTickType)portMAX_DELAY)) {
+ size_t sent = uart_fill_fifo(uart_num, (char*) src, size);
+ if(sent < size) {
+ p_uart_obj[uart_num]->tx_waiting_fifo = true;
+ uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT);
+ }
+ size -= sent;
+ src += sent;
+ }
+ }
+ if(brk_en) {
+ uart_set_break(uart_num, brk_len);
+ xSemaphoreTake(p_uart_obj[uart_num]->tx_brk_sem, (portTickType)portMAX_DELAY);
+ }
+ xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem);
+ }
+ xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
+ return original_size;
+}
+
+int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));
+ UART_CHECK((p_uart_obj[uart_num] != NULL), "uart driver error", (-1));
+ UART_CHECK(src, "buffer null", (-1));
+ return uart_tx_all(uart_num, src, size, 0, 0);
+}
+
+int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t size, int brk_len)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));
+ UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1));
+ UART_CHECK((size > 0), "uart size error", (-1));
+ UART_CHECK((src), "uart data null", (-1));
+ UART_CHECK((brk_len > 0 && brk_len < 256), "break_num error", (-1));
+ return uart_tx_all(uart_num, src, size, 1, brk_len);
+}
+
+int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));
+ UART_CHECK((buf), "uart_num error", (-1));
+ UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1));
+ uint8_t* data = NULL;
+ size_t size;
+ size_t copy_len = 0;
+ int len_tmp;
+ if(xSemaphoreTake(p_uart_obj[uart_num]->rx_mux,(portTickType)ticks_to_wait) != pdTRUE) {
+ return -1;
+ }
+ while(length) {
+ if(p_uart_obj[uart_num]->rx_cur_remain == 0) {
+ data = (uint8_t*) xRingbufferReceive(p_uart_obj[uart_num]->rx_ring_buf, &size, (portTickType) ticks_to_wait);
+ if(data) {
+ p_uart_obj[uart_num]->rx_head_ptr = data;
+ p_uart_obj[uart_num]->rx_ptr = data;
+ p_uart_obj[uart_num]->rx_cur_remain = size;
+ } else {
+ xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
+ return copy_len;
+ }
+ }
+ if(p_uart_obj[uart_num]->rx_cur_remain > length) {
+ len_tmp = length;
+ } else {
+ len_tmp = p_uart_obj[uart_num]->rx_cur_remain;
+ }
+ memcpy(buf + copy_len, p_uart_obj[uart_num]->rx_ptr, len_tmp);
+ p_uart_obj[uart_num]->rx_ptr += len_tmp;
+ p_uart_obj[uart_num]->rx_cur_remain -= len_tmp;
+ copy_len += len_tmp;
+ length -= len_tmp;
+ if(p_uart_obj[uart_num]->rx_cur_remain == 0) {
+ vRingbufferReturnItem(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_head_ptr);
+ p_uart_obj[uart_num]->rx_head_ptr = NULL;
+ p_uart_obj[uart_num]->rx_ptr = NULL;
+ if(p_uart_obj[uart_num]->rx_buffer_full_flg) {
+ BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1);
+ if(res == pdTRUE) {
+ p_uart_obj[uart_num]->rx_buffer_full_flg = false;
+ uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num);
+ }
+ }
+ }
+ }
+ xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
+ return copy_len;
+}
+
+esp_err_t uart_flush(uart_port_t uart_num)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL);
+ uart_obj_t* p_uart = p_uart_obj[uart_num];
+ uint8_t* data;
+ size_t size;
+
+ //rx sem protect the ring buffer read related functions
+ xSemaphoreTake(p_uart->rx_mux, (portTickType)portMAX_DELAY);
+ esp_intr_disable(p_uart->intr_handle);
+ while(true) {
+ if(p_uart->rx_head_ptr) {
+ vRingbufferReturnItem(p_uart->rx_ring_buf, p_uart->rx_head_ptr);
+ p_uart->rx_ptr = NULL;
+ p_uart->rx_cur_remain = 0;
+ p_uart->rx_head_ptr = NULL;
+ }
+ data = (uint8_t*) xRingbufferReceive(p_uart->rx_ring_buf, &size, (portTickType) 0);
+ if(data == NULL) {
+ break;
+ }
+ vRingbufferReturnItem(p_uart->rx_ring_buf, data);
+ }
+ p_uart->rx_ptr = NULL;
+ p_uart->rx_cur_remain = 0;
+ p_uart->rx_head_ptr = NULL;
+ esp_intr_enable(p_uart->intr_handle);
+ xSemaphoreGive(p_uart->rx_mux);
+
+ if(p_uart->tx_buf_size > 0) {
+ xSemaphoreTake(p_uart->tx_mux, (portTickType)portMAX_DELAY);
+ esp_intr_disable(p_uart->intr_handle);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ UART[uart_num]->int_ena.txfifo_empty = 0;
+ UART[uart_num]->int_clr.txfifo_empty = 1;
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ do {
+ data = (uint8_t*) xRingbufferReceive(p_uart->tx_ring_buf, &size, (portTickType) 0);
+ if(data == NULL) {
+ break;
+ }
+ vRingbufferReturnItem(p_uart->rx_ring_buf, data);
+ } while(1);
+ p_uart->tx_brk_flg = 0;
+ p_uart->tx_brk_len = 0;
+ p_uart->tx_head = NULL;
+ p_uart->tx_len_cur = 0;
+ p_uart->tx_len_tot = 0;
+ p_uart->tx_ptr = NULL;
+ p_uart->tx_waiting_brk = 0;
+ p_uart->tx_waiting_fifo = false;
+ esp_intr_enable(p_uart->intr_handle);
+ xSemaphoreGive(p_uart->tx_mux);
+ }
+ uart_reset_fifo(uart_num);
+ return ESP_OK;
+}
+
+esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, void* uart_queue, int intr_alloc_flags)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((rx_buffer_size > 0), "uart rx buffer length error", ESP_FAIL);
+ if(p_uart_obj[uart_num] == NULL) {
+ p_uart_obj[uart_num] = (uart_obj_t*) malloc(sizeof(uart_obj_t));
+ if(p_uart_obj[uart_num] == NULL) {
+ ESP_LOGE(UART_TAG, "UART driver malloc error");
+ return ESP_FAIL;
+ }
+ p_uart_obj[uart_num]->uart_num = uart_num;
+ p_uart_obj[uart_num]->tx_fifo_sem = xSemaphoreCreateBinary();
+ xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem);
+ p_uart_obj[uart_num]->tx_done_sem = xSemaphoreCreateBinary();
+ p_uart_obj[uart_num]->tx_brk_sem = xSemaphoreCreateBinary();
+ p_uart_obj[uart_num]->tx_mux = xSemaphoreCreateMutex();
+ p_uart_obj[uart_num]->rx_mux = xSemaphoreCreateMutex();
+ p_uart_obj[uart_num]->queue_size = queue_size;
+ p_uart_obj[uart_num]->tx_ptr = NULL;
+ p_uart_obj[uart_num]->tx_head = NULL;
+ p_uart_obj[uart_num]->tx_len_tot = 0;
+ p_uart_obj[uart_num]->tx_brk_flg = 0;
+ p_uart_obj[uart_num]->tx_brk_len = 0;
+ p_uart_obj[uart_num]->tx_waiting_brk = 0;
+
+ if(uart_queue) {
+ p_uart_obj[uart_num]->xQueueUart = xQueueCreate(queue_size, sizeof(uart_event_t));
+ *((QueueHandle_t*) uart_queue) = p_uart_obj[uart_num]->xQueueUart;
+ ESP_LOGI(UART_TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_uart_obj[uart_num]->xQueueUart));
+ } else {
+ p_uart_obj[uart_num]->xQueueUart = NULL;
+ }
+ p_uart_obj[uart_num]->rx_buffer_full_flg = false;
+ p_uart_obj[uart_num]->tx_waiting_fifo = false;
+ p_uart_obj[uart_num]->rx_ptr = NULL;
+ p_uart_obj[uart_num]->rx_cur_remain = 0;
+ p_uart_obj[uart_num]->rx_head_ptr = NULL;
+ p_uart_obj[uart_num]->rx_ring_buf = xRingbufferCreate(rx_buffer_size, RINGBUF_TYPE_BYTEBUF);
+ if(tx_buffer_size > 0) {
+ p_uart_obj[uart_num]->tx_ring_buf = xRingbufferCreate(tx_buffer_size, RINGBUF_TYPE_NOSPLIT);
+ p_uart_obj[uart_num]->tx_buf_size = tx_buffer_size;
+ } else {
+ p_uart_obj[uart_num]->tx_ring_buf = NULL;
+ p_uart_obj[uart_num]->tx_buf_size = 0;
+ }
+ } else {
+ ESP_LOGE(UART_TAG, "UART driver already installed");
+ return ESP_FAIL;
+ }
+ uart_isr_register(uart_num, uart_rx_intr_handler_default, p_uart_obj[uart_num], intr_alloc_flags);
+ uart_intr_config_t uart_intr = {
+ .intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M
+ | UART_RXFIFO_TOUT_INT_ENA_M
+ | UART_FRM_ERR_INT_ENA_M
+ | UART_RXFIFO_OVF_INT_ENA_M
+ | UART_BRK_DET_INT_ENA_M
+ | UART_PARITY_ERR_INT_ENA_M,
+ .rxfifo_full_thresh = UART_FULL_THRESH_DEFAULT,
+ .rx_timeout_thresh = UART_TOUT_THRESH_DEFAULT,
+ .txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT
+ };
+ uart_intr_config(uart_num, &uart_intr);
+ return ESP_OK;
+}
+
+//Make sure no other tasks are still using UART before you call this function
+esp_err_t uart_driver_delete(uart_port_t uart_num)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ if(p_uart_obj[uart_num] == NULL) {
+ ESP_LOGI(UART_TAG, "ALREADY NULL");
+ return ESP_OK;
+ }
esp_intr_free(p_uart_obj[uart_num]->intr_handle);
- uart_disable_rx_intr(uart_num);\r
- uart_disable_tx_intr(uart_num);\r
-\r
- if(p_uart_obj[uart_num]->tx_fifo_sem) {\r
- vSemaphoreDelete(p_uart_obj[uart_num]->tx_fifo_sem);\r
- p_uart_obj[uart_num]->tx_fifo_sem = NULL;\r
- }\r
- if(p_uart_obj[uart_num]->tx_done_sem) {\r
- vSemaphoreDelete(p_uart_obj[uart_num]->tx_done_sem);\r
- p_uart_obj[uart_num]->tx_done_sem = NULL;\r
- }\r
- if(p_uart_obj[uart_num]->tx_brk_sem) {\r
- vSemaphoreDelete(p_uart_obj[uart_num]->tx_brk_sem);\r
- p_uart_obj[uart_num]->tx_brk_sem = NULL;\r
- }\r
- if(p_uart_obj[uart_num]->tx_mux) {\r
- vSemaphoreDelete(p_uart_obj[uart_num]->tx_mux);\r
- p_uart_obj[uart_num]->tx_mux = NULL;\r
- }\r
- if(p_uart_obj[uart_num]->rx_mux) {\r
- vSemaphoreDelete(p_uart_obj[uart_num]->rx_mux);\r
- p_uart_obj[uart_num]->rx_mux = NULL;\r
- }\r
- if(p_uart_obj[uart_num]->xQueueUart) {\r
- vQueueDelete(p_uart_obj[uart_num]->xQueueUart);\r
- p_uart_obj[uart_num]->xQueueUart = NULL;\r
- }\r
- if(p_uart_obj[uart_num]->rx_ring_buf) {\r
- vRingbufferDelete(p_uart_obj[uart_num]->rx_ring_buf);\r
- p_uart_obj[uart_num]->rx_ring_buf = NULL;\r
- }\r
- if(p_uart_obj[uart_num]->tx_ring_buf) {\r
- vRingbufferDelete(p_uart_obj[uart_num]->tx_ring_buf);\r
- p_uart_obj[uart_num]->tx_ring_buf = NULL;\r
- }\r
-\r
- free(p_uart_obj[uart_num]);\r
- p_uart_obj[uart_num] = NULL;\r
- return ESP_OK;\r
-}\r
+ uart_disable_rx_intr(uart_num);
+ uart_disable_tx_intr(uart_num);
+
+ if(p_uart_obj[uart_num]->tx_fifo_sem) {
+ vSemaphoreDelete(p_uart_obj[uart_num]->tx_fifo_sem);
+ p_uart_obj[uart_num]->tx_fifo_sem = NULL;
+ }
+ if(p_uart_obj[uart_num]->tx_done_sem) {
+ vSemaphoreDelete(p_uart_obj[uart_num]->tx_done_sem);
+ p_uart_obj[uart_num]->tx_done_sem = NULL;
+ }
+ if(p_uart_obj[uart_num]->tx_brk_sem) {
+ vSemaphoreDelete(p_uart_obj[uart_num]->tx_brk_sem);
+ p_uart_obj[uart_num]->tx_brk_sem = NULL;
+ }
+ if(p_uart_obj[uart_num]->tx_mux) {
+ vSemaphoreDelete(p_uart_obj[uart_num]->tx_mux);
+ p_uart_obj[uart_num]->tx_mux = NULL;
+ }
+ if(p_uart_obj[uart_num]->rx_mux) {
+ vSemaphoreDelete(p_uart_obj[uart_num]->rx_mux);
+ p_uart_obj[uart_num]->rx_mux = NULL;
+ }
+ if(p_uart_obj[uart_num]->xQueueUart) {
+ vQueueDelete(p_uart_obj[uart_num]->xQueueUart);
+ p_uart_obj[uart_num]->xQueueUart = NULL;
+ }
+ if(p_uart_obj[uart_num]->rx_ring_buf) {
+ vRingbufferDelete(p_uart_obj[uart_num]->rx_ring_buf);
+ p_uart_obj[uart_num]->rx_ring_buf = NULL;
+ }
+ if(p_uart_obj[uart_num]->tx_ring_buf) {
+ vRingbufferDelete(p_uart_obj[uart_num]->tx_ring_buf);
+ p_uart_obj[uart_num]->tx_ring_buf = NULL;
+ }
+
+ free(p_uart_obj[uart_num]);
+ p_uart_obj[uart_num] = NULL;
+ return ESP_OK;
+}