某個Cortex-M4芯片帶有1個UART,支持Tx,Rx 的FIFO功能,並且能夠經過寄存器配置FIFO的閾值,芯片的datasheet並不完善,沒有說明RX的FIFO具體有幾個級別,每隔級別的閾值是多少。html
可是須要注意的是 TX, RX 的FIFO均可以經過UART 的 DR 寄存器進行訪問。ui
功夫不負有心人,終於在SDK的某段代碼中窺見了RX的幾個FIFO閾值:線程
默認狀況下RX FIFO 是收到32字節纔會產生一次RX中斷。調試
若是收到的數據長度沒有32字節,則一直等,等到知足32字節,才產生RX中斷。code
之因此注意到這個問題,是由於下面的一件事情:htm
調試的時候發現電腦發送6個字符,可是開發板並無打印6個字符,再加6個字符,仍是沒有,繼續加6個字符,直到知足了32個字節,這個時候纔有了RX中斷,把收到的數據打印了出來。blog
上面雖然收到了數據,可是並無把32個字符都保存下來。原來在UART中斷程序中,在RX中斷條件下,每次都把前面的數據清空了。開發
if (ui32Status & ( AM_REG_UART_IES_RXRIS_M | AM_REG_UART_IES_RTRIS_M)) { // 其餘操做 os_memset(g_uart_buf, '\0', sizeof(g_uart_buf)); // 後來才意識到在 uart 中斷服務程序中每次接收都清空接收緩衝區是一個大錯誤。 // 接收數據 *(g_uart_buf + index++) = AM_REGn(UART, ui32Module, DR); }
如上面的例子,會致使每一次中斷中清空前面的數據,永遠只能看到後一次FIFO中的數據,最多爲32個字節。這樣絕對是錯誤的,由於每次從FIFO中取走了一個字節,後面當FIFO滿時又會產生新的RX中斷。
因此每次中斷中儘可能取走全部的數據。該怎麼作呢?須要讀UART寄存器狀態,FIFO不空的狀況下把全部的數據取走,例以下面:get
if(ui32Status & (AM_REG_UART_IES_RXRIS_M | AM_REG_UART_IES_RTRIS_M)) { while ( !AM_BFRn(UART, 0, FR, RXFE) ) { if (uart_data_index < UART_BUF_LENGTH) { // 不能超出 g_uart_buf 的長度 *(g_uart_buf + uart_data_index++) = AM_REGn(UART, ui32Module, DR); } else { // 超出部分直接丟棄 ui8Char = AM_REGn(UART, ui32Module, DR); } } }
還須要注意,若是對端模塊返回的UART數據超過了接收緩衝區的長度,須要丟棄。若是不丟棄則沒法退出中斷。博客
UART 使用主要是初始化,中斷服務程序以及應用程序對收發數據的處理。
初始化部分,須要完成的工做:
AM_HAL_UART_INT_RX
表示RX中斷,AM_HAL_UART_INT_RX_TMOUT
表示超時中斷中斷服務程序,通常來講主要負責接收,能夠按照下面的流程:
應用程序,在某個時候處理UART接收緩衝區,必要的時候須要清空緩衝區。
若是不清空的話,UART中斷會一直把數據拷貝到緩衝區,直到緩衝區滿,後面的數據就浪費了。同時應用程序也會處理這些重複的數據可能沒法進入正常的流程。
按道理說在應用層清空緩衝區就能夠了,可是我擔憂應用程序在操做緩衝區的時候忽然被中斷打斷了,清空操做出錯了或者把剛剛收到的數據清空了,我覺得讓中斷程序在某些條件下清空或許是一個不錯的選擇。
以下是個人實現,應用層發出清空緩衝區的請求uart_data_clear()
,若是剛好下一次UART中斷即時,就能夠在中斷一開始清空緩衝區。若是下一次UART中斷來的不及時,那麼第二次調用uart_data_clear()
就能夠在應用層清空緩衝區。
extern unsigned char g_uart_buf[UART_BUF_LENGTH]; // UART 接收緩衝區 extern uint16_t uart_data_index; // 當前寫入UART接收緩衝區的數據的位置。 extern uint8_t uart_data_clear_flag; // 1 -- 表示須要清除數據; 0 -- 不須要清除數據 /** * 第一次調用,可讓UART中斷清空緩衝區,第二次調用能夠在應用層清空緩衝區 */ void uart_data_clear(void) { // 說明尚未進入一次UART中斷,這裏在應用層主動清空UART數據 if (uart_data_clear_flag) { os_memset(g_uart_buf, 0, sizeof(g_uart_buf)); uart_data_index = 0; uart_data_clear_flag = 0; } else { // 在UART中斷清空數據 uart_data_clear_flag = 1; } } // 另外一個文件中的UART中斷服務程序 void am_uart_isr(void) { uint32_t ui32Status; uint32_t ui32Module = 0; uint8_t ui8Char = 0; // // Read the masked interrupt status from the UART. // ui32Status = am_hal_uart_int_status_get(true); if(ui32Status & (AM_REG_UART_IES_RXRIS_M | AM_REG_UART_IES_RTRIS_M)) { // 用戶已經處理完了上一次的UART接收數據,能夠清空緩衝區以備下一次接收 if (uart_data_clear_flag) { uart_data_clear_flag = 0; os_memset(g_uart_buf, '\0', sizeof(g_uart_buf)); uart_data_index = 0; } while ( !AM_BFRn(UART, 0, FR, RXFE) ) { if (uart_data_index < UART_BUF_LENGTH) { // 不能超出 g_uart_buf 的長度 *(g_uart_buf + uart_data_index++) = AM_REGn(UART, ui32Module, DR); } else { // 超出部分直接丟棄 ui8Char = AM_REGn(UART, ui32Module, DR); } } } // Clear the UART interrupts. // am_hal_uart_int_clear(ui32Status); // 發出信號量通知其餘任務 // do something... }
歡迎轉載,請註明出處和做者,同時保留聲明。
做者:LinTeX9527
出處:http://www.javashuo.com/article/p-pxdevlxt-q.html 本博客的文章如無特殊說明,均爲原創,轉載請註明出處。如未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。