1. 程式人生 > >ESP8266--學習筆記(八)串列埠原始碼分析

ESP8266--學習筆記(八)串列埠原始碼分析

 我一直對ESP8266的串列埠傳輸的機制很好奇,沒辦法只得好好分析原始碼了。
 ESP8266的中斷系統是必須要了解的。我分析的原始碼是分配有任務的,所以在任務函式中是無法看到中斷的。我的分析如下:

這裡寫圖片描述

程式碼實現如下:

串列埠接收中斷處理函式

LOCAL void
uart0_rx_intr_handler(void *para)
{
  uint8 uart_no = UART0;//UartDev.buff_uart_no;

  if(UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST))
  {
    os_printf("FRM_ERR\r\n"
); WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR); } if(UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) { ETS_UART_INTR_DISABLE();//中斷失能 system_os_post(at_recvTaskPrio, 0, 0);//向任務函式傳送訊息 } else if(UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) { ETS_UART_INTR_DISABLE();///
/中斷失能
system_os_post(at_recvTaskPrio, 0, 0);//向任務函式傳送訊息 }

任務函式

void ICACHE_FLASH_ATTR
at_init(void)
{
  system_os_task(at_recvTask, at_recvTaskPrio, at_recvTaskQueue, at_recvTaskQueueLen);
  system_os_task(at_procTask, at_procTaskPrio, at_procTaskQueue, at_procTaskQueueLen);
}

 如此這般,當串列埠接收中斷髮生時,FIFO滿了或FIFO超時了,都會使得中斷向任務傳送訊息,從而讓任務中的接收任務事件跑起來。

串列埠中斷函式分析:

首先UART的中斷暫存器有:

  • UART_INT_RAW 中斷原始狀態暫存器
  • UART_INT_ENA 中斷使能暫存器:表⽰示當前使能的uart中斷。
  • UART_INT_ST 中斷狀態暫存器:表⽰示當前有效的中斷狀態
  • UART_INT_CLR 清除中斷暫存器:置對應位來清除中斷狀態暫存器

然後UART的一些特殊的位:

  • UART_RXFIFO_FULL_INT_ST :接收full中斷位
  • UART_RXFIFO_OVF_INT_ST:接收溢位中斷位
  • UART_RXFIFO_TOUT_INT_ST :接收超時中斷位
  • UART_TXFIFO_EMPTY_INT_ST:傳送空中斷位

然後UART的暫存器操作函式:

  • READ_PERI_REG(addr) 讀暫存器值的函式
  • WRITE_PERI_REG(addr, val) 寫暫存器函式

程式碼分析 uart.c–uart0_rx_intr_handler()

if(UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(UART0)) & UART_FRM_ERR_INT_ST))
  {
    os_printf("FRM_ERR\r\n");
    WRITE_PERI_REG(UART_INT_CLR(UART0), UART_FRM_ERR_INT_CLR);
  }

根據前面的各種各樣的識別符號分析

  • 首先讀uart0的中斷狀態暫存器READ_PERI_REG(UART_INT_ST(UART0))
  • 而 UART_FRM_ERR_INT_ST 是這麼定義的#define UART_FRM_ERR_INT_ST (BIT(3))
  • 然後將這兩個暫存器進行“和”運算再與UART_FRM_ERR_INT_ST進行判斷

總結:

 經過一系列的分析,所謂的串列埠接收中斷函式就是:中斷髮生後,CPU首先檢視串列埠中斷位,然後在將查詢到的值與那些特殊位進行比較,得出串列埠的當前狀態:串列埠接收錯誤?串列埠接收FIFO滿了?串列埠接收FIFO超時?…….然後根據不同的狀態進行不同的操作。
 如果加入了任務調控機制,就可以在串列埠發生中斷的時候,給任務傳送訊息了。讓任務進行操作。

————————————————————

下面這段程式碼首先分析識別符號:

  • READ_PERI_REG(…):讀取tx/rx 佇列內當前剩餘的位元組數
  • UART_STATUS(…)
  • UART_RXFIFO_CNT :0x000000FF (255)
  • UART_RXFIFO_CNT_S :0
while(READ_PERI_REG(UART_STATUS(UART0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S))
  {
  }