天天看點

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 = ;
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 = ;
    U8 byStatus = ;
    //收取資料,超過最大包長的資料将簡單丢棄
    while (wLenAvail = U_GetBytesAvail(hPort)> && 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 = ;
    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[];
    for (i=; i<gwLenUartBuffer; i++)
    {
        AnsiiToUnicodeString((S8*)my_data_buffer, (S8*)gabyUartBuffer);
        if (my_data_buffer[]=='p'&&my_data_buffer[]=='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]-=;
    }
    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);
}