keil/include/drivers/mk_uart.c
@@ -1,5 +1,5 @@
/*
 * Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and
 * Copyright (c) 2019-2025 Beijing Hanwei Innovation Technology Ltd. Co. and
 * its subsidiaries and affiliates (collectly called MKSEMI).
 *
 * All rights reserved.
@@ -59,13 +59,13 @@
        .dma_tx_ch = DMA_CH7,
    },
};
//ÒÆÖ²
uint32_t SerialKeyPressed(uint8_t *key)//ÅжÏÊý¾ÝÊÇ·ñÊÕµ½µÄ MK8000ÐÞ¸Ä
//ò??2
uint32_t SerialKeyPressed(uint8_t *key)//?D??êy?Yê?·?ê?μ?μ? MK8000DT??
{
    uint32_t status = uart_handle[1].base->STATUS;
    if (status & UART_STATUS_DR_MSK)
    {
        //Serial0PutString("³É¹¦½ÓÊÕing");
        //Serial0PutString("3é1|?óê?ing");
        //uart_receive(UART_ID1,test_buf,10,NULL);
        *key = (uint8_t)uart_handle[1].base->RX_DATA;
        //uart_rx_fifo_clear(UART_ID1);
@@ -93,7 +93,7 @@
    }
}
void Serial0PutChar(uint8_t c)
{   //ÅжÏÊý¾Ý»º´æÇøÎª¿Õ¼´ÉÏÒ»¸ö×Ö½ÚÊý¾ÝÒѾ­±»Ë͵½·¢ËͼĴæÆ÷·¢ËͳöÈ¥ÁË
{   //?D??êy?Y?o′????a???′é?ò???×??úêy?Yò??-±??íμ?·¢?í??′??÷·¢?í3?è¥á?
    // wait TX FIFO empty
    while (uart_handle[0].base->TX_FL)
    {
@@ -139,37 +139,37 @@
    // update state
    switch (uart_handle[id].state)
    {
    case UART_STATE_READY:
        uart_handle[id].state = state;
        break;
    case UART_STATE_BUSY_RX:
        if (state == UART_STATE_BUSY_TX)
        {
            uart_handle[id].state = UART_STATE_BUSY_TX_RX;
        }
        else
        {
        case UART_STATE_READY:
            uart_handle[id].state = state;
            break;
        case UART_STATE_BUSY_RX:
            if (state == UART_STATE_BUSY_TX)
            {
                uart_handle[id].state = UART_STATE_BUSY_TX_RX;
            }
            else
            {
                ret = DRV_BUSY;
            }
            break;
        case UART_STATE_BUSY_TX:
            if (state == UART_STATE_BUSY_RX)
            {
                uart_handle[id].state = UART_STATE_BUSY_TX_RX;
            }
            else
            {
                ret = DRV_BUSY;
            }
            break;
        case UART_STATE_BUSY_TX_RX:
            ret = DRV_BUSY;
        }
        break;
    case UART_STATE_BUSY_TX:
        if (state == UART_STATE_BUSY_RX)
        {
            uart_handle[id].state = UART_STATE_BUSY_TX_RX;
        }
        else
        {
            ret = DRV_BUSY;
        }
        break;
    case UART_STATE_BUSY_TX_RX:
        ret = DRV_BUSY;
        break;
    case UART_STATE_RESET:
    case UART_STATE_TIMEOUT:
    case UART_STATE_ERROR:
        ret = DRV_ERROR;
        break;
            break;
        case UART_STATE_RESET:
        case UART_STATE_TIMEOUT:
        case UART_STATE_ERROR:
            ret = DRV_ERROR;
            break;
    }
    int_unlock(lock);
@@ -193,15 +193,24 @@
    return uart_handle[id].state;
}
bool uart_tx_in_progress(enum UART_DEV_T id)
bool uart_is_busy(enum UART_DEV_T id)
{
    return ((uart_handle[id].state & UART_STATE_BUSY_TX) && (uart_handle[id].base->STATUS & UART_STATUS_BUSY_MSK));
    // - Transmission in progress on serial interface
    // - Transmit data present in TX FIFO
    // - Reception in progress on the interface
    // - Receive data present in RX FIFO
    // - [Patch] UART is not enabled but RX is pulled low
    return ((uart_handle[id].state != UART_STATE_RESET) && (uart_handle[id].base->STATUS & UART_STATUS_BUSY_MSK));
}
bool uart_fifo_busy(enum UART_DEV_T id)
bool uart_tx_in_progress(enum UART_DEV_T id)
{
    // UART is not enabled but RX is pulled low
    return ((uart_handle[id].state != UART_STATE_RESET) && (uart_handle[id].base->STATUS & UART_STATUS_BUSY_MSK));
    return ((uart_handle[id].state & UART_STATE_BUSY_TX) || !(uart_handle[id].base->STATUS & UART_STATUS_TEMT_MSK));
}
bool uart_tx_fifo_is_empty(enum UART_DEV_T id)
{
    return (uart_handle[id].base->STATUS & UART_STATUS_TEMT_MSK);
}
void uart_rx_fifo_clear(enum UART_DEV_T id)
@@ -210,6 +219,13 @@
    while (uart_handle[id].base->STATUS & UART_STATUS_RFNE_MSK)
    {
        uart_handle[id].base->RX_DATA;
    }
    if (uart_handle[id].dma_en)
    {
        // reset RX FIFO, clear DMA request for rx fifo
        // Note: It is not recommended to use UART DMA software ack, as this may affect the actively working TX unless in half-duplex mode
        uart_handle[id].base->CTRL0 = uart_handle[id].ctrl0 | UART_CTRL0_RX_FIFO_RESET_MSK;
    }
}
@@ -432,14 +448,6 @@
        while (uart_handle[id].tx_count < uart_handle[id].tx_size)
        {
            status = uart_handle[id].base->STATUS;
            if (status & (UART_STATUS_OE_MSK | UART_STATUS_PE_MSK | UART_STATUS_FE_MSK | UART_STATUS_BI_MSK | UART_STATUS_RFE_MSK))
            {
                // TODO: user handle the error case
                uart_handle[id].base->INTR_CLR = UART_INTR_CLR_LSR_INT_CLR_MSK;
                status |= UART_ERR_LINE;
                ret = DRV_ERROR;
                break;
            }
            if (uart_handle[id].base->STATUS & UART_STATUS_TFNF_MSK)
            {
@@ -544,8 +552,6 @@
            if (status & (UART_STATUS_OE_MSK | UART_STATUS_PE_MSK | UART_STATUS_FE_MSK | UART_STATUS_BI_MSK | UART_STATUS_RFE_MSK))
            {
                // TODO: user handle the error case
                // Clear error bits
                uart_handle[id].base->INTR_CLR = UART_INTR_CLR_LSR_INT_CLR_MSK;
                status |= UART_ERR_LINE;
                ret = DRV_ERROR;
                break;
@@ -569,6 +575,91 @@
    }
    return ret;
}
int uart_dma_receive_with_llp(enum UART_DEV_T id, uint8_t *rx_buf, uint32_t len, struct DMA_LINK_DESC_T *desc, drv_callback_t callback)
{
    if ((rx_buf == 0) || (len == 0) || !(uart_handle[id].dma_en) || (desc == NULL))
    {
        return DRV_ERROR;
    }
    // update state
    int ret = uart_state_set(id, UART_STATE_BUSY_RX);
    if (ret != DRV_OK)
    {
        return ret;
    }
    uart_handle[id].rx_callback = callback;
    // fix TX output low level when host MCU reset
    uint32_t err_code = uart_handle[id].base->STATUS;
    if (err_code & (UART_STATUS_FE_MSK | UART_STATUS_BI_MSK | UART_STATUS_RFE_MSK))
    {
        // reset FIFO
        uart_handle[id].base->CTRL0 = UART_CTRL0_RX_FIFO_RESET_MSK | UART_CTRL0_TX_FIFO_RESET_MSK;
        // clear STATUS
        uart_handle[id].base->INTR_CLR =
            UART_INTR_CLR_THRE_INT_CLR_MSK | UART_INTR_CLR_BUSY_INT_CLR_MSK | UART_INTR_CLR_LSR_INT_CLR_MSK | UART_INTR_CLR_MSR_INT_CLR_MSK;
        uart_handle[id].base->CTRL0 = uart_handle[id].ctrl0;
    }
    struct DMA_CH_CFG_T uart_rx_dma_cfg = {
        .fifo_th = DMA_FIFO_TH_1,
        .src_burst_size = DMA_SRC_BURST_SIZE_1,
        .src_width = DMA_WIDTH_1B,
        .dst_width = DMA_WIDTH_1B,
        .src_addr_ctrl = DMA_ADDR_FIXED,
        .dst_addr_ctrl = DMA_ADDR_INC,
        .src_req_sel = (id == UART_ID1 ? DMA_REQ_UART1_RX : DMA_REQ_UART0_RX),
        .dst_req_sel = DMA_REQ_MEM,
    };
    uart_handle[id].dma_rx_err_state = 0;
    NVIC_ClearPendingIRQ(uart_handle[id].irq);
    // Enable Receiver Line Status Interrupt, used to obtain the error interrupt event triggered by the receiver
    uart_handle[id].base->INTR_EN = (UART_INTR_EN_ELCOLR_MSK | UART_INTR_EN_ELSI_MSK);
    dma_open(uart_handle[id].dma_rx_ch, &uart_rx_dma_cfg);
    DMA->CH[uart_handle[id].dma_rx_ch].CHAIN_PTR = (uint32_t)desc;
    while (desc)
    {
        desc->src_addr = (uint32_t)&uart_handle[id].base->RX_DATA;
        desc->ctrl = uart_rx_dma_cfg.fifo_th << 29 | uart_rx_dma_cfg.src_width << 25 | uart_rx_dma_cfg.dst_width << 22 | uart_rx_dma_cfg.src_addr_ctrl << 20 |
                     uart_rx_dma_cfg.dst_addr_ctrl << 18;
        desc = desc->nxt;
    }
    dma_transfer(uart_handle[id].dma_rx_ch, (uint8_t *)&uart_handle[id].base->RX_DATA, rx_buf, len, uart_dma_callback);
    return ret;
}
void uart_send_over_fifo(enum UART_DEV_T id, uint8_t *tx_buf, uint32_t len)
{
    for (uint32_t i = 0; i < len; i++)
    {
        uart_handle[id].base->TX_DATA = tx_buf[i];
    }
}
uint32_t uart_receive_from_fifo(enum UART_DEV_T id, uint8_t *rx_buf, uint32_t len)
{
    for (uint32_t i = 0; i < len; i++)
    {
        uint32_t status = uart_handle[id].base->STATUS;
        if (status & UART_STATUS_RFNE_MSK)
        {
            rx_buf[i] = (uint8_t)uart_handle[id].base->RX_DATA;
        }
        else
        {
            return i;
        }
    }
    return len;
}
int uart_tx_abort_dma(enum UART_DEV_T id, drv_callback_t abort_tx_callback)
@@ -598,6 +689,24 @@
        uart_handle[id].base->CTRL0 = uart_handle[id].ctrl0 | UART_CTRL0_RX_FIFO_RESET_MSK;
        uart_handle[id].rx_abort_callback = abort_rx_callback;
        ret = dma_abort(uart_handle[id].dma_rx_ch, uart_dma_abort_callback);
    }
#endif
    return ret;
}
int uart_rx_force_abort_dma(enum UART_DEV_T id, drv_callback_t abort_rx_callback)
{
    int ret = DRV_ERROR;
#if UART_DMA_MODE_EN
    if (uart_handle[id].dma_en)
    {
        // RX err - disable interrupts
        uart_handle[id].base->INTR_EN &= ~(UART_INTR_EN_ELCOLR_MSK | UART_INTR_EN_ELSI_MSK);
        // reset rx FIFO, de-assert the DMA RX request
        uart_handle[id].base->CTRL0 = uart_handle[id].ctrl0 | UART_CTRL0_RX_FIFO_RESET_MSK;
        uart_handle[id].rx_abort_callback = abort_rx_callback;
        dma_force_abort(uart_handle[id].dma_rx_ch, uart_dma_abort_callback);
        ret = DRV_OK;
    }
#endif
    return ret;
@@ -710,6 +819,16 @@
            // RX done
            usr_callback = uart_handle[id].rx_callback;
            if ((DMA->CH[uart_handle[id].dma_rx_ch].CFG & 0x000F0000) != 0)
            {
                if (usr_callback)
                {
                    usr_callback(&id, err_code);
                }
                return;
            }
            // update state
            uart_state_clear(id, UART_STATE_BUSY_RX);
        }
@@ -747,26 +866,22 @@
void uart_irq_handler(enum UART_DEV_T id)
{
    drv_callback_t usr_callback = NULL;
    uint32_t err_code = 0;
    // read interrupt ID
    uint8_t iid = uart_handle[id].base->INTR_STATUS & 0x0f;
    uint32_t err_code = uart_handle[id].base->STATUS;
    // If DMA is enabled, the uart interrupt handler is only used to handle the error events reported by the receiver
    if (uart_handle[id].dma_en)
    {
#if UART_DMA_MODE_EN
        err_code = uart_handle[id].base->STATUS;
        // iid == 0xC: The precondition that the timeout event will not be triggered is that the length of
        // the received data is an integer multiple of the RX FIFO level
        if ((err_code & UART_STATUS_ERROR_MSK) || (iid == 0x0C) || (iid == 0x01))
        if (err_code & UART_STATUS_ERROR_MSK)
        {
            // RX err - disable interrupts
            uart_handle[id].base->INTR_EN &= ~UART_INTR_EN_ELSI_MSK;
            uart_handle[id].base->INTR_CLR = UART_INTR_CLR_LSR_INT_CLR_MSK;
            uart_handle[id].dma_rx_err_state = UART_ERR_LINE | iid;
            uart_handle[id].dma_rx_err_state = UART_ERR_LINE;
            usr_callback = uart_handle[id].rx_callback;
            err_code = UART_ERR_LINE | iid;
            err_code |= UART_ERR_LINE;
            // update state
            uart_state_clear(id, UART_STATE_BUSY_RX);
@@ -781,108 +896,119 @@
    else
    {
#if UART_INT_MODE_EN
        // read interrupt ID
        uint8_t iid = uart_handle[id].base->INTR_STATUS & 0x0f;
        switch (iid)
        {
            // modem status
        case 0x0:
            // clear int
            uart_handle[id].base->INTR_CLR = UART_INTR_CLR_MSR_INT_CLR_MSK;
            err_code = UART_ERR_MODEM | iid;
            break;
            case 0x0:
                // clear int
                uart_handle[id].base->INTR_CLR = UART_INTR_CLR_MSR_INT_CLR_MSK;
                err_code |= UART_ERR_MODEM;
                break;
            // no interrupt pending
        case 0x1:
            break;
            case 0x1:
                break;
            // TX_DATA empty
        case 0x2:
            // clear int
            uart_handle[id].base->INTR_CLR = UART_INTR_CLR_THRE_INT_CLR_MSK;
            if ((uart_handle[id].state == UART_STATE_BUSY_TX) || (uart_handle[id].state == UART_STATE_BUSY_TX_RX))
            {
                if (uart_handle[id].tx_count == uart_handle[id].tx_size)
            case 0x2:
                // clear int
                uart_handle[id].base->INTR_CLR = UART_INTR_CLR_THRE_INT_CLR_MSK;
                if ((uart_handle[id].state == UART_STATE_BUSY_TX) || (uart_handle[id].state == UART_STATE_BUSY_TX_RX))
                {
                    // TX done - disable interrupt
                    uart_handle[id].base->INTR_EN &= ~UART_INTR_EN_ETBEI_MSK;
                    usr_callback = uart_handle[id].tx_callback;
                    if (uart_handle[id].tx_count == uart_handle[id].tx_size)
                    {
                        // TX done - disable interrupt
                        uart_handle[id].base->INTR_EN &= ~UART_INTR_EN_ETBEI_MSK;
                        usr_callback = uart_handle[id].tx_callback;
                    // update state
                    uart_state_clear(id, UART_STATE_BUSY_TX);
                        // update state
                        uart_state_clear(id, UART_STATE_BUSY_TX);
                    uart_handle[id].tx_buff = NULL;
                    uart_handle[id].tx_callback = NULL;
                    uart_handle[id].tx_count = 0;
                    uart_handle[id].tx_size = 0;
                        uart_handle[id].tx_buff = NULL;
                        uart_handle[id].tx_callback = NULL;
                        uart_handle[id].tx_count = 0;
                        uart_handle[id].tx_size = 0;
                    }
                    else
                    {
                        // TX continue - write data to FIFO
                        while ((uart_handle[id].tx_count < uart_handle[id].tx_size) && (uart_handle[id].base->STATUS & UART_STATUS_TFNF_MSK))
                        {
                            uart_handle[id].base->TX_DATA = uart_handle[id].tx_buff[uart_handle[id].tx_count++];
                        }
                    }
                }
                else
                {
                    // TX continue - write data to FIFO
                    while ((uart_handle[id].tx_count < uart_handle[id].tx_size) && (uart_handle[id].base->STATUS & UART_STATUS_TFNF_MSK))
                    {
                        uart_handle[id].base->TX_DATA = uart_handle[id].tx_buff[uart_handle[id].tx_count++];
                    }
                    // should not get this interrupt in any other state
                    ASSERT(0, "Uart %d state goes wrong %d", id, uart_handle[id].state);
                }
            }
            else
            {
                // should not get this interrupt in any other state
                ASSERT(0, "Uart %d state goes wrong %d", id, uart_handle[id].state);
            }
            break;
                break;
            // timeout
        case 0xc:
            case 0xc:
            // No characters in or out of the RCVR FIFO during the last 4 character times and
            // there is at least 1 character in it during this time
            // received data available
        case 0x4:
            if ((uart_handle[id].state == UART_STATE_BUSY_RX) || (uart_handle[id].state == UART_STATE_BUSY_TX_RX))
            {
                // uint8_t len = uart_handle[id].base->RX_FL;
                while ((uart_handle[id].rx_count < uart_handle[id].rx_size) && (uart_handle[id].base->STATUS & UART_STATUS_RFNE_MSK))
            case 0x4:
                if ((uart_handle[id].state == UART_STATE_BUSY_RX) || (uart_handle[id].state == UART_STATE_BUSY_TX_RX))
                {
                    uint8_t data = (uint8_t)uart_handle[id].base->RX_DATA;
                    uart_handle[id].rx_buff[uart_handle[id].rx_count++] = data;
                }
                    // uint8_t len = uart_handle[id].base->RX_FL;
                    while ((uart_handle[id].rx_count < uart_handle[id].rx_size) && (uart_handle[id].base->STATUS & UART_STATUS_RFNE_MSK))
                    {
                        uint8_t data = (uint8_t)uart_handle[id].base->RX_DATA;
                        uart_handle[id].rx_buff[uart_handle[id].rx_count++] = data;
                    }
                if (uart_handle[id].rx_count == uart_handle[id].rx_size)
                    if (uart_handle[id].rx_count == uart_handle[id].rx_size)
                    {
                        // RX done - disable interrupts
                        uart_handle[id].base->INTR_EN &= ~(UART_INTR_EN_ELSI_MSK | UART_INTR_EN_ERBFI_MSK);
                        usr_callback = uart_handle[id].rx_callback;
                        // update state
                        uart_state_clear(id, UART_STATE_BUSY_RX);
                        uart_handle[id].rx_buff = NULL;
                        uart_handle[id].rx_callback = NULL;
                        uart_handle[id].rx_count = 0;
                        uart_handle[id].rx_size = 0;
                    }
                }
                else
                {
                    // RX done - disable interrupts
                    uart_handle[id].base->INTR_EN &= ~(UART_INTR_EN_ELSI_MSK | UART_INTR_EN_ERBFI_MSK);
                    usr_callback = uart_handle[id].rx_callback;
                    // update state
                    uart_state_clear(id, UART_STATE_BUSY_RX);
                    uart_handle[id].rx_buff = NULL;
                    uart_handle[id].rx_callback = NULL;
                    uart_handle[id].rx_count = 0;
                    uart_handle[id].rx_size = 0;
                    // received unexpected data
                }
            }
            else
            {
                // received unexpected data
            }
            break;
                break;
            // receiver line status
        case 0x6:
            // clear int
            uart_handle[id].base->INTR_CLR = UART_INTR_CLR_LSR_INT_CLR_MSK;
            err_code = UART_ERR_LINE | iid;
            break;
            case 0x6:
                // clear int (Overrun/parity/framing errors, break interrupt, or address received interrupt)
                // RX err - disable interrupts
                uart_handle[id].base->INTR_EN &= ~UART_INTR_EN_ELSI_MSK;
                uart_handle[id].base->INTR_CLR = UART_INTR_CLR_LSR_INT_CLR_MSK;
                usr_callback = uart_handle[id].rx_callback;
                err_code |= UART_ERR_LINE;
                uart_handle[id].rx_buff = NULL;
                uart_handle[id].rx_callback = NULL;
                uart_handle[id].rx_count = 0;
                uart_handle[id].rx_size = 0;
                break;
            // busy detect
        case 0x7:
            // clear int
            uart_handle[id].base->INTR_CLR = UART_INTR_CLR_BUSY_INT_CLR_MSK;
            err_code = UART_ERR_BUSY | iid;
            break;
            case 0x7:
                // clear int
                uart_handle[id].base->INTR_CLR = UART_INTR_CLR_BUSY_INT_CLR_MSK;
                err_code |= UART_ERR_BUSY;
                break;
        default:
            break;
            default:
                break;
        }
#endif
    }