MTK之UART串列埠收發資料
暫存器
UARTn_RBR: Rx Buffer Register,通過讀取該暫存器接收資料。要求LCR[7]=0。
UARTn_THR: Tx Holding Register,資料先寫入該暫存器,再送至PC端。要求LCR[7]=0。
UARTn_IER: Interrupt Enable Register,IER[3:0] are modified when LCR[7]=0. IER[7:4] are modified when LCR[7]=0 & EFR[4]=1.
EDSSI: 如果MSR[4:1] 有資料,產生中斷。IER[3]=1
ERBFI: 如果Rx Buffer有資料,產生中斷。IER[0]=1
UARTn_IIR: Interrupt Identification Register
Rx Data Received: Rx Data received or RX Trigger Level reached. IIR[5:0] = 000100
Rx Data Timeout: Timeout on character in RX FIFO. IIR[5:0] = 001100
串列埠流程
UART1_HISR //根據IIR型別判斷tx or rx
// UART_IIR_CTI
UART1_HISR
=> UART_RecHandler(&UARTPort[uart_port1]);
=> UARTPort[UARTData->port_no].rx_cb(UARTData->port_no);
=> UART_dafault_rx_cb
=> UART_sendilm(port, MSG_ID_UART_READY_TO_READ_IND);
// from MOD_DRV_HISR to UARTPort[port].ownerid
預設發訊息到MOD_TST_READER,處理後再呼叫
=> DclSerialPort_Control(handle, SIO_CMD_GET_BYTES, (DCL_CTRL_DATA_T*)&data_getbyte);
最終呼叫DCL_STATUS UART_Handler(DCL_DEV dev, DCL_CTRL_CMD cmd, DCL_CTRL_DATA_T *data) // return buffer
// UART_IIR_THRE
UART1_HISR
=> UART_TrxHandler(&UARTPort[uart_port1]);
=> UARTPort[UARTData->port_no].tx_cb(UARTData->port_no);
=> UART_datafault_tx_cb
=> UART_sendilm(port, MSG_ID_UART_READY_TO_WRITE_IND);
// from MOD_DRV_HISR to UARTPort[port].ownerid // MOD_ATCI==41
預設發訊息到MOD_TST_READER,處理後再呼叫
=> DclSerialPort_Control(handle, SIO_CMD_PUT_BYTES, (DCL_CTRL_DATA_T*)&data_getbyte);
最終呼叫DCL_STATUS UART_Handler(DCL_DEV dev, DCL_CTRL_CMD cmd, DCL_CTRL_DATA_T *data) // send buffer
軟體處理:直接傳送MSG_ID_UART_READY_TO_READ_IND到MOD_ATCI,會呼叫UART_Handler中SIO_CMD_GET_BYTES獲取AT命令,在此處給指標賦值並且中斷從串列埠讀取資料的流程,完成後MOD_ATCI會繼續呼叫UART_Handler中SIO_CMD_PUT_BYTES輸入AT命令返回的結果,在此處可以拷貝一份傳給軟體處理,此處同時會傳遞給串列埠往外輸出。
軟體流程
因為MSG_ID_UART_READY_TO_READ_IND屬於驅動層的訊息,通過串列埠傳送AT指令的過程為MOD_DRV_HISR->MOD_TST_READER。如果在MMI層中設定響應函式來響應UART的READY TO READ訊息,這時AT指令無效,直接發往MMI層。由於MMI層截獲了這個訊息,因此先響應MMI層的響應函式,如果在讀取UART的buffer後將其清空,MOD_TST_READER自然得不到AT指令,因此無法做出任何AT響應。值得注意的是,所有串列埠在接到字元後響應的都是該訊息,因此在讀取的時候需要判斷是否來自所需串列埠的資訊。
開啟串列埠
(1) 禁止休眠
(2) 設定MSG_ID_UART_READY_TO_READ_IND訊息的響應函式
(3) 將串列埠所屬MOD切換至將要使用的MOD(UART_GetOwnerID, UART_SetOwner)
(4) 設定串列埠引數,波特率等(UART_SetDCBConfig)
(5) 清空對應串列埠的接收Buffer(UART_ClrRxBuffer)
讀取串列埠資訊
(1) UART_GetBytesAvail
(2) UART_GetBytes
(3) 讀完之後清空接收Buffer(UART_ClrRxBuffer)
向串列埠寫資訊
(1) 清空裝置輸入、輸出FIFO(UART_Purge)
(2) 清空傳送、接收Buffer(UART_ClrTxBuffer,UART_ClrRxBuffer)
(3) 寫入資料UART_PutBytes
關閉串列埠
(1) 將所使用的串列埠MOD設定為原來的MOD
(2) 使能睡眠
#define GC_UART_PORT uart_port1
#define MAX_ECHO_PACKET_LEN 255
extern module_type U_GetOwnerID(UART_PORT port);
extern void U_ClrTxBuffer(UART_PORT port, module_type ownerid);
extern void U_ClrRxBuffer(UART_PORT port, module_type ownerid);
static kal_uint8 ghSleepMode;
static module_type gnOrigUartOwner;
static kal_bool gbUartInitialized = KAL_FALSE;
static kal_bool gbUartEchoStarted = KAL_FALSE;
static U16 gwLenUartBuffer = 0;
static U8 gabyUartBuffer[MAX_ECHO_PACKET_LEN];
static void gc_init_uart(void)
{
if (gbUartInitialized)
return;
//禁止休眠
ghSleepMode = L1SM_GetHandle();
L1SM_SleepDisable(ghSleepMode);
//切換MOD,設定串列埠引數、波特率等
gnOrigUartOwner = UART_GetOwnerID(GC_UART_PORT);
U_SetOwner(GC_UART_PORT, MOD_MMI);
U_SetBaudRate(GC_UART_PORT, UART_BAUD_115200, MOD_MMI);
//設定MSG_ID_UART_READY_TO_READ_IND訊息的響應函式
ClearProtocolEventHandler(MSG_ID_UART_READY_TO_READ_IND);
SetProtocolEventHandler(mmi_gc_uart_readyToRead_ind_handler, MSG_ID_UART_READY_TO_READ_IND);
gbUartInitialized = KAL_TRUE;
}
void mmi_gc_uart_readyToRead_ind_handler(void *msg)
{
uart_ready_to_read_ind_struct* uart_rtr_ind = (uart_ready_to_read_ind_struct*) msg;
kal_uint8 status;
gwLenUartBuffer = DT_HAL_UART_GetBytes(uart_port1, gabyUartBuffer, sizeof(gabyUartBuffer), &status, MOD_MMI);
DT_HAL_UART_PutBytes(uart_port1, gabyUartBuffer, gwLenUartBuffer, MOD_MMI);
}
//////////////////////
static U16 read_from_uart(U8 *pbyBuf, U16 wLenMax, UART_PORT hPort, module_type hOwner)
{
U16 wLenAvail;
U16 wLenRead;
U16 wLenRet = 0;
U8 byStatus = 0;
//收取資料,超過最大包長的資料將簡單丟棄
while (wLenAvail = U_GetBytesAvail(hPort)>0 && wLenRet < wLenMax)
{
if (wLenAvail + wLenRet > wLenMax)
wLenAvail = wLenMax - wLenRet;
wLenRead = U_GetBytes(hPort, (kal_uint8*) (pbyBuf + wLenRet), (kal_uint16)wLenAvail, &byStatus, hOwner);
wLenRet += wLenRead;
}
//讀完後,清空串列埠接收Buffer
U_ClrRxBuffer(hPort, hOwner);
return wLenRet;
}
static U8 write_to_uart(U8 *pbyBuf, U16 wLenBuf, UART_PORT hPort, module_type hOwner)
{
U16 wSent = 0;
U8 bRet = FALSE;
// 傳送前清空輸入、輸出FIFO
U_Purge(hPort, RX_BUF, hOwner);
U_Purge(hPort, TX_BUF, hOwner);
// 清空傳送、接收Buffer
U_ClrTxBuffer(hPort, hOwner);
U_ClrRxBuffer(hPort, hOwner);
//寫入資料
wSent = U_PutBytes(hPort, (kal_uint8 *)pbyBuf, (kal_uint16)wLenBuf, hOwner);
if (wSent == wLenBuf)
bRet = TRUE;
return bRet;
}
static void exit_uart()
{
if (gbUartInitialized)
{
//恢復原有端口占用者
U_SetOwner(GC_UART_PORT, (kal_uint8)gnOrigUartOwner);
L1SM_SleepEnable(ghSleepMode);
gbUartInitialized = KAL_FALSE;
}
}
static void mmi_gc_uart_readyToRead_ind_handler(void *msg)
{
uart_ready_to_read_ind_struct* uart_rtr_ind = (uart_read_to_read_ind_struct*)msg;
if (KAL_FALSE == gbUartEchoStarted || GC_UART_PORT != uart_rtr_ind->port || MOD_MMI != UART_GetOwnerID(uart_rtr_ind->port))
return;
gwLenUartBuffer = read_from_uart(gabyUartBuffer, sizeof(gabyUartBuffer), GC_UART_PORT, MOD_MMI);
uart_echo_process();
}
static void start_uart_echo(void)
{
S8 strHelllo[] = "Hello World Uart Echo Example Started!\r\n";
if (gbUartEchoStarted)
return;
gc_init_uart();
write_to_uart((kal_uint8*)strHello, (kal_uint16)strlen(strHello), GC_UART_PORT, MOD_MMI);
gbUartEchoStarted = KAL_TRUE;
SetKeyHandler(stop_uart_echo, KEY_LSK, KEY_EVENT_UP);
}
static void uart_echo_process(void)
{
U8 i;
char my_data_buffer[256];
for (i=0; i<gwLenUartBuffer; i++)
{
AnsiiToUnicodeString((S8*)my_data_buffer, (S8*)gabyUartBuffer);
if (my_data_buffer[0]=='p'&&my_data_buffer[2]=='t')
{
S8 strByte[] = "Play tone successfully\r\n";
write_to_uart((kal_uint8*)strByte, (kal_uint16)strlen(strByte), GC_UART_PORT, MOD_MMI);
}
else gabyUartBuffer[i]-=0x20;
}
write_to_uart(gabyUartBuffer, gwLenUartBuffer, GC_UART_PORT, MOD_MMI);
}
static void stop_uart_echo(void)
{
S8 strBye[] = "Hello World Uart Echo Example Stop!\r\n";
if (gbUartEchoStarted)
{
write_to_uart((kal_uint8*)strByte, (kal_uint16)strlen(strBye), GC_UART_PORT, MOD_MMI);
gbUartEchoStarted = KAL_FALSE;
SetKeyHandler(start_uart_echo, KEY_LSK, KEY_EVENT_UP);
}
exit_uart();
}
void mmi_HelloWorld_entry(void)
{
SetKeyHandler(start_uart_echo, KEY_LSK, KEY_EVENT_UP);
}