Nuvoton NUC200 NUC220使用FIFO觸發中斷及接收超時中斷處理UART接收的資料

NUC200NUC220_BSP當中所提供之UART_Read(uart, pu8RxBuf, u32ReadBytes)函式屬於輪詢方式,接收緩衝器為空時這個函式就會在原地等待,屆時CPU沒辦法做其他事情。本篇介紹使用中斷的方式處理UART接收到的資料。

在這邊我們使用到UART兩個中斷源,分別是"接收資料可用中斷"及"接收超時中斷"。

接收資料可用中斷的發生條件為,當接收到的位元組大於等於所設定之閥值發生,而閥值可由UART->FCR[7:4] RFITL設定1Byte、4Bytes、8Bytes、14Bytes、30Bytes、46Bytes及62Bytes。在這邊要注意,NUC220的UART0才有提供到64Bytes的接收緩衝區,UART1及UART2只提供了16Bytes的接收緩衝區,當閥值設定超過14Bytes則以14Bytes為準。清除接收資料可用中斷的中斷旗標只要讀取RBR即可。

接收超時中斷的發生條件為,當超時計數器的值大於等於超時比較器(UART->TOR[7:0] TOIC)的值發生接收超時中斷。超時計數器在每一個Byte進來時會歸零並且開始計時,而計數器的時脈等於Baudrate,所以建議將TOIC設定在40~255之間,以避免在下一個Byte進來以前就發生了超時中斷。若要清除接收超時中斷的中斷旗標同樣讀取RBR即可。

那麼為甚麼我們要使用這兩種中斷? 首先我們將緩衝區設定在30Bytes會發生中斷,若進來資料是一長串的話可以每30Bytes收一次以降低CPU的負擔。問題是如果進來的資料不剛好整除30個Byte怎麼辦? 這些不到30Bytes的資料就透過超時中斷來處理。假設進來的資料剛好是30個Byte,那很好就剛好把30個Byte收完以後就結束了,如果大於30個Byte則會在超時中斷發生時將剩下的幾個Byte讀取完畢。

下面的程式透過接收中斷的方式將RX接收到的資料傳回TX,所以TX應傳出RX所接收到的資料。由Arduino IDE的Serial Monitor來輸入資料及監測程式運作的狀況。記得UART0的中斷服務程式要叫做"UART02_IRQHandler"。
1. 首先輸入一個不到30Bytes的字串會發生超時中斷,並將這些字元存入軟體buffer然後再傳出來。
2. 輸入"012345678901234567890123456789",怎麼發生了FIFO ready及timeout兩種中斷? 因為我們在Serial Monitor下方的傳輸設定將傳出的字串尾端自動加入New line及Carriage return,故會多出兩個Byte。
3. 所以我們輸入"0123456789012345678901234567"28個Byte,加上New line及Carriage return共30個Byte則只會發生FIFO ready一個中斷。


#include "stdlib.h"
#include "stdio.h"
#include "NUC200Series.h"

#define PLL_CLOCK   48000000

void SYS_Init(void)
{
 /*---------------------------------------------------------------------------------------------------------*/
 /* Init System Clock                                                                                       */
 /*---------------------------------------------------------------------------------------------------------*/

 /* Enable Internal RC 22.1184MHz clock */
 CLK_EnableXtalRC(CLK_PWRCON_OSC22M_EN_Msk);

 /* Waiting for Internal RC clock ready */
 CLK_WaitClockReady(CLK_CLKSTATUS_OSC22M_STB_Msk);

 /* Set core clock as PLL_CLOCK from PLL */
 CLK_EnablePLL(CLK_PLLCON_PLL_SRC_HIRC, PLL_CLOCK);

 CLK_WaitClockReady(CLK_CLKSTATUS_PLL_STB_Msk);

 /* Switch HCLK clock source to Internal RC and HCLK source divide 1 */
 CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HIRC, CLK_CLKDIV_HCLK(1));

 /* Enable UART module clock */
 CLK_EnableModuleClock(UART0_MODULE);

 /* Select UART module clock source */
 CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART_S_HIRC, CLK_CLKDIV_UART(1));  

 /* Update System Core Clock */
 SystemCoreClockUpdate();

 /*---------------------------------------------------------------------------------------------------------*/
 /* Init I/O Multi-function                                                                                 */
 /*---------------------------------------------------------------------------------------------------------*/

 /* Set GPB multi-function pins for UART0 RXD(PB.0) and TXD(PB.1) */
 SYS->GPB_MFP &= ~(SYS_GPB_MFP_PB0_Msk | SYS_GPB_MFP_PB1_Msk);
 SYS->GPB_MFP |= SYS_GPB_MFP_PB0_UART0_RXD | SYS_GPB_MFP_PB1_UART0_TXD;
 
}

void UART02_IRQHandler(void)
{
 //printf("UART0 interrupt happen.\r\n");
 if(UART_GET_INT_FLAG(UART0, UART_ISR_TOUT_INT_Msk))
 {
  uint8_t i, str[30];
  printf("UART0 RX timeout.\r\n");
  for(i=0; !(UART0->FSR & UART_FSR_RX_EMPTY_Msk); i++) str[i] = UART0->RBR;
  UART_Write(UART0, str, i);
 }
 if(UART_GET_INT_FLAG(UART0, UART_ISR_RDA_INT_Msk))
 {
  uint8_t i, str[30];
  printf("UART0 FIFO ready.\r\n");
  for(i=0; i<30 i="" str="" uart0-="">RBR;
  UART_Write(UART0, str, 30);
 }
}

void UART0_Init()
{
 /*---------------------------------------------------------------------------------------------------------*/
 /* Init UART                                                                                               */
 /*---------------------------------------------------------------------------------------------------------*/
 /* Reset UART0 module */
 SYS_ResetModule(UART0_RST);

 /* Configure UART0 and set UART0 Baudrate */
 UART_Open(UART0, 115200);
}

int main()
{
 SYS_UnlockReg();
 SYS_Init();
 SYS_LockReg();
 
 UART0_Init();
 //將FIFO中斷閥值設為30個Byte
 UART0->FCR &= ~(UART_FCR_RFITL_Msk);
 UART0->FCR |= UART_FCR_RFITL_30BYTES;
 //設定接收超時比較值
 UART_SetTimeoutCnt(UART0, 0xf0);
 //啟用FIFO中斷及接收超時中斷
 UART_EnableInt(UART0, UART_IER_RDA_IEN_Msk | UART_IER_TOUT_IEN_Msk);
 printf("\r\nNUC220 ok\r\n");
 
 PA10=1;
 GPIO_SetMode(PA, BIT10, GPIO_PMD_QUASI);
 
 while(1)
 {
  
 }
}

留言

這個網誌中的熱門文章

無法被取代的指針型三用電表(一):前言

關於新唐科技NuMicro ISP的介紹和使用方式

新唐火神板開箱實作(一):NuMaker-Volcano與NuEclipse IDE入門篇