Skip to content

Commit

Permalink
Merge branch 'feature/uart' into 'master'
Browse files Browse the repository at this point in the history
driver: uart

1. add uart rx buffer data length API
2. add uart pattern detect event
3. add uart example code
4. modify uart_isr_register API
5. modify uart.rst
6. fix parity err event and frame err event.

See merge request !321
  • Loading branch information
costaud committed Dec 21, 2016
2 parents 4f3ff1c + 9dbdab5 commit 168190d
Show file tree
Hide file tree
Showing 6 changed files with 326 additions and 50 deletions.
58 changes: 54 additions & 4 deletions components/driver/include/driver/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extern "C" {
#include "soc/uart_reg.h"
#include "soc/uart_struct.h"
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "driver/periph_ctrl.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
Expand Down Expand Up @@ -129,6 +130,7 @@ typedef enum {
UART_PARITY_ERR, /*!< UART RX parity event*/
UART_DATA_BREAK, /*!< UART TX data and break event*/
UART_EVENT_MAX, /*!< UART event max index*/
UART_PATTERN_DET, /*!< UART pattern detected */
} uart_event_type_t;

/**
Expand All @@ -139,6 +141,8 @@ typedef struct {
size_t size; /*!< UART data size for UART_DATA event*/
} uart_event_t;

typedef intr_handle_t uart_isr_handle_t;

/**
* @brief Set UART data bits.
*
Expand Down Expand Up @@ -372,12 +376,14 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh);
* @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.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
*
* @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);
esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags, uart_isr_handle_t *handle);


/**
Expand Down Expand Up @@ -463,9 +469,11 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_
* @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 rx_buffer_size UART RX ring buffer size, rx_buffer_size should be greater than UART_FIFO_LEN.
* @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.
Expand Down Expand Up @@ -586,13 +594,56 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
*/
esp_err_t uart_flush(uart_port_t uart_num);

/**
* @brief UART get RX ring buffer cached data length
*
* @param uart_num UART port number.
* @param size Pointer of size_t to accept cached data length
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size);

/**
* @brief UART disable pattern detect function.
* Designed for applications like 'AT commands'.
* When the hardware detect a series of one same character, the interrupt will be triggered.
*
* @param uart_num UART port number.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_disable_pattern_det_intr(uart_port_t uart_num);

/**
* @brief UART enable pattern detect function.
* Designed for applications like 'AT commands'.
* When the hardware detect a series of one same character, the interrupt will be triggered.
*
* @param uart_num UART port number.
* @param pattern_chr character of the pattern
* @param chr_num number of the character, 8bit value.
* @param chr_tout timeout of the interval between each pattern characters, 24bit value, unit is APB(80Mhz) clock cycle.
* @param post_idle idle time after the last pattern character, 24bit value, unit is APB(80Mhz) clock cycle.
* @param pre_idle idle time before the first pattern character, 24bit value, unit is APB(80Mhz) clock cycle.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_enable_pattern_det_intr(uart_port_t uart_num, char pattern_chr, uint8_t chr_num, int chr_tout, int post_idle, int pre_idle);
/***************************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 = {
Expand Down Expand Up @@ -655,7 +706,7 @@ esp_err_t uart_flush(uart_port_t uart_num);
* //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, NULL, 0);
* uart_driver_install(uart_num, 1024 * 2, 1024*4, 0, NULL, 0);
* uint8_t data[1000];
* while(1) {
* //Read data from UART
Expand Down Expand Up @@ -689,7 +740,6 @@ esp_err_t uart_flush(uart_port_t uart_num);
* 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:
Expand Down
119 changes: 74 additions & 45 deletions components/driver/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ typedef struct {
QueueHandle_t xQueueUart; /*!< UART queue handler*/
intr_handle_t intr_handle; /*!< UART interrupt handle*/
//rx parameters
int rx_buffered_len; /*!< UART cached data length */
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*/
Expand Down Expand Up @@ -260,22 +261,38 @@ esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask)
return ESP_OK;
}

esp_err_t uart_enable_pattern_det_intr(uart_port_t uart_num, char pattern_chr, uint8_t chr_num, int chr_tout, int post_idle, int pre_idle)
{
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
UART_CHECK(chr_tout >= 0 && chr_tout <= UART_RX_GAP_TOUT_V, "uart pattern set error\n", ESP_FAIL);
UART_CHECK(post_idle >= 0 && post_idle <= UART_POST_IDLE_NUM_V, "uart pattern set error\n", ESP_FAIL);
UART_CHECK(pre_idle >= 0 && pre_idle <= UART_PRE_IDLE_NUM_V, "uart pattern set error\n", ESP_FAIL);
UART[uart_num]->at_cmd_char.data = pattern_chr;
UART[uart_num]->at_cmd_char.char_num = chr_num;
UART[uart_num]->at_cmd_gaptout.rx_gap_tout = chr_tout;
UART[uart_num]->at_cmd_postcnt.post_idle_num = post_idle;
UART[uart_num]->at_cmd_precnt.pre_idle_num = pre_idle;
return uart_enable_intr_mask(uart_num, UART_AT_CMD_CHAR_DET_INT_ENA_M);
}

esp_err_t uart_disable_pattern_det_intr(uart_port_t uart_num)
{
return uart_disable_intr_mask(uart_num, UART_AT_CMD_CHAR_DET_INT_ENA_M);
}

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;
return uart_enable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
}

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;
return uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
}

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;
return uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA);
}

esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh)
Expand All @@ -290,21 +307,21 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh)
return ESP_OK;
}

esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags)
esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags, uart_isr_handle_t *handle)
{
int ret;
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);
ret=esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, 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);
ret=esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, 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);
ret=esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
break;
}
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
Expand Down Expand Up @@ -595,6 +612,9 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param)
p_uart->rx_buffer_full_flg = true;
uart_event.type = UART_BUFFER_FULL;
} else {
UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
p_uart->rx_buffered_len += p_uart->rx_stash_len;
UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
uart_event.type = UART_DATA;
}
if(HPTaskAwoken == pdTRUE) {
Expand All @@ -618,10 +638,10 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param)
} 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 ) {
} else if(uart_intr_status & UART_FRM_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) {
} else if(uart_intr_status & UART_PARITY_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) {
Expand All @@ -647,6 +667,9 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param)
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_AT_CMD_CHAR_DET_INT_ST_M) {
uart_reg->int_clr.at_cmd_char_det = 1;
uart_event.type = UART_PATTERN_DET;
} 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;
Expand All @@ -656,8 +679,7 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param)
if(HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR() ;
}
}
else {
} else {
uart_reg->int_clr.val = uart_intr_status; /*simply clear all other intr status*/
uart_event.type = UART_EVENT_MAX;
}
Expand Down Expand Up @@ -833,6 +855,9 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
p_uart_obj[uart_num]->rx_cur_remain = size;
} else {
xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffered_len -= copy_len;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
return copy_len;
}
}
Expand All @@ -853,16 +878,30 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
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) {
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
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);
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffered_len -= copy_len;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
return copy_len;
}

esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size)
{
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL);
*size = p_uart_obj[uart_num]->rx_buffered_len;
return ESP_OK;
}

esp_err_t uart_flush(uart_port_t uart_num)
{
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
Expand All @@ -873,10 +912,13 @@ esp_err_t uart_flush(uart_port_t uart_num)

//rx sem protect the ring buffer read related functions
xSemaphoreTake(p_uart->rx_mux, (portTickType)portMAX_DELAY);
esp_intr_disable(p_uart->intr_handle);
uart_disable_rx_intr(p_uart_obj[uart_num]->uart_num);
while(true) {
if(p_uart->rx_head_ptr) {
vRingbufferReturnItem(p_uart->rx_ring_buf, p_uart->rx_head_ptr);
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffered_len -= p_uart->rx_cur_remain;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
p_uart->rx_ptr = NULL;
p_uart->rx_cur_remain = 0;
p_uart->rx_head_ptr = NULL;
Expand All @@ -885,47 +927,33 @@ esp_err_t uart_flush(uart_port_t uart_num)
if(data == NULL) {
break;
}
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffered_len -= size;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
vRingbufferReturnItem(p_uart->rx_ring_buf, data);
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) {
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffer_full_flg = false;
}
}
}
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);
uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num);
xSemaphoreGive(p_uart->rx_mux);
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);
UART_CHECK((rx_buffer_size > UART_FIFO_LEN), "uart rx buffer length error(>128)", 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) {
Expand All @@ -946,6 +974,7 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b
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;
p_uart_obj[uart_num]->rx_buffered_len = 0;

if(uart_queue) {
p_uart_obj[uart_num]->xQueueUart = xQueueCreate(queue_size, sizeof(uart_event_t));
Expand All @@ -971,7 +1000,7 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b
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_isr_register(uart_num, uart_rx_intr_handler_default, p_uart_obj[uart_num], intr_alloc_flags, &p_uart_obj[uart_num]->intr_handle);
uart_intr_config_t uart_intr = {
.intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M
| UART_RXFIFO_TOUT_INT_ENA_M
Expand Down
4 changes: 3 additions & 1 deletion docs/api/uart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,7 @@ Functions
.. doxygenfunction:: uart_write_bytes_with_break
.. doxygenfunction:: uart_read_bytes
.. doxygenfunction:: uart_flush

.. doxygenfunction:: uart_get_buffered_data_len
.. doxygenfunction:: uart_disable_pattern_det_intr
.. doxygenfunction:: uart_enable_pattern_det_intr

Loading

0 comments on commit 168190d

Please sign in to comment.