某个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 本博客的文章如无特殊说明,均为原创,转载请注明出处。如未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利。