6621E UART1 使能FIFO与CTI实现长帧不丢数据接收

wen sir · 422次点击 · 2023-11-30

通过使能UART1 FIFO模式,并结合CTI中断,实现从1~1500字节 连连续不丢码接收

主要按以下三步骤来进行

(1) 首先,参考下文,加入uart.c 为源文件编译模式

6621E 外设源文件编译修改例程(uart)-昂瑞微论坛BBS (onmicro.com.cn)

(2) 配置FIFO模式,8字节FIFO接收中断加超时5ms读取数据。

(3)为了进一步提高处理速度,可以把uart.c 加入到 sram 中执行。

..\..\..\..\lib\keil\scatter_om6621e_flash_armclang.sct

image.png

uart.c 代码示例

/*********************************************************************
 * @file uart.c
 * @brief
 * @version 1.0
 * @date Wed 19 Nov 2014 04:11:47 PM CST
 * @author Onmicro
 *
 * @note
 */

/*********************************************************************
 * INCLUDES
 */
#include "features.h"
#include "hs66xx.h"
#include "uart.h"
#include "cpm.h"
#include "co_evt.h"


/*********************************************************************
 * MACROS
 */
#define MODE_X_DIV          16
#define ISO7816_RX_MODE     1
#define ISO7816_TX_MODE     0

#define UART_TIMEOUT        (1024 * 1024 * 2)

/*********************************************************************
 * TYPEDEFS
 */
typedef struct
{
    uart_rx_callback_t      rx_cb;
    uart_tx_cmp_callback_t  tx_cmp_cb;
} uart_callback_t;

typedef struct
{
    uart_callback_t uart[1];
} uart_env_t;

/*********************************************************************
 * CONSTANTS
 */
volatile char  uart1_dma_recv_flag = false;

/*********************************************************************
 * LOCAL VARIABLES
 */

static uart_env_t uart_env;

/*********************************************************************
 * GLOBAL VARIABLES
 */


/*********************************************************************
 * LOCAL FUNCTIONS
 */

/**
 * @brief uart_check_irq()
 *
 * @param[in] uart
 *
 * @return
 **/

#define CNT_MAX  (1500) //最多连接接收字符数
#define TIMEOUT_MS  (5) //暂停超时
uint16_t recv_byte_cnt = 0;/*每帧接收计数*/
char recv_buffer[CNT_MAX];/*接收缓冲,可以不必须清空*/


void uart1_reset_recv_timeout(void);


static co_timer_t uart_recv_break_timer;
static void uart_recv_break_timer_handler(co_timer_t *timer, void *param)
{
    //1-打印接收字节数
    log_debug("\nrecv=%d", recv_byte_cnt);
    //2-接收数据处理,需要读取到其它地方,进行处理
    log_debug_array_ex("\ndata", recv_buffer, recv_byte_cnt);
    //3-清0计数器,重新接收
    recv_byte_cnt = 0;
}
/**
 * @brief 如果(TIMEOUT_MS)ms内没有新的数据,表示此次接收完毕,连续接收数不超过 CNT_MAX
 */
void uart1_reset_recv_timeout(void)
{
    co_timer_set(&uart_recv_break_timer, TIMEOUT_MS, TIMER_ONE_SHOT, uart_recv_break_timer_handler, NULL);
}

static void uart_check_irq(HS_UART_Type *uart, uart_callback_t *uart_cb)
{
    uint8_t status;
    volatile uint8_t ch;
    while (1)
    {
        status = uart->IIR & UART_IIR_ID;
        switch (status)
        {
        case UART_IIR_RDI: /* Receiver data interrupt */
        {
            while (uart->LSR & UART_LSR_DR)
            {
                recv_buffer[recv_byte_cnt] = uart->RBR;
                if (recv_byte_cnt < CNT_MAX)
                    recv_byte_cnt++;
            }
            uart1_reset_recv_timeout();
        }
        break;
        case UART_IIR_THRI:
            uart->IER &= ~UART_IER_THRI;
            if (uart_cb->tx_cmp_cb)
                uart_cb->tx_cmp_cb();
            break;
        case UART_IIR_NO_INT:
            return;
        case UART_IIR_BDI:
            status = uart->USR;
            break;
        case UART_IIR_RLSI:
            ch = uart->LSR;
            break;
        case UART_IIR_CTI:/* character timeout */
        {
            while (uart->LSR & UART_LSR_DR)
            {
                recv_buffer[recv_byte_cnt] = uart->RBR;
                if (recv_byte_cnt < CNT_MAX)
                    recv_byte_cnt++;
            }
            uart1_reset_recv_timeout();
        }
        break;
        default:
            break;
        }
    }
}

/*********************************************************************
 * PUBLIC FUNCTIONS
 */

/**
 * @brief uart initialize
 *
 * @param[in] uart  uart object
 * @param[in] baud_rate  baud rate
 * @param[in] flow_ctrl  flow control (Only UART1 support)
 * @param[in] uart_rx_cb  receive callback
 *
 * @return None
 **/



void uart_open(HS_UART_Type *uart, uint32_t baud_rate, uart_flow_ctrl_t flow_ctrl, uart_rx_callback_t uart_rx_cb)
{
    uint16_t baud_divisor;
    // Reset and Bypass UART1
    register_set1(&HS_PSO->UART1_CFG, CPM_UART_SOFT_RESET_MASK);
    register_set0(&HS_PSO->UART1_CFG, CPM_UART_DIV_SEL_MASK | CPM_UART_GATE_EN_MASK);
    HS_PSO_UPD_RDY();
    uart_env.uart[0].tx_cmp_cb = NULL;
    uart_env.uart[0].rx_cb = NULL;
    /* Compute divisor value. Normally, we should simply return:
     *   NS16550_CLK / MODE_X_DIV / baudrate
     * but we need to round that value by adding 0.5.
     * Rounding is especially important at high baud rates.
     */
    if (cpm_get_clock(CPM_TOP_CLK) >= 32000000 && baud_rate < 19200)
        baud_divisor = 4; // make sure 9600bps is supported
    else
        baud_divisor = 1;
    cpm_set_clock(CPM_UART1_CLK, baud_divisor * baud_rate * MODE_X_DIV);
    // Disable LCR and irq
    uart->LCR = 0x00;
    uart->IER = 0;
    // Auto RTS – Becomes active when the following occurs:
    //   - Auto Flow Control is selected during configuration
    //   - FIFOs are implemented
    //   - RTS (MCR[1] bit and MCR[5]bit are both set)
    //   - FIFOs are enabled (FCR[0]) bit is set)
    //   - SIR mode is disabled (MCR[6] bit is not set)
    if (flow_ctrl == UART_FLOW_CTRL_ENABLED)
        uart->MCR = UART_MCR_RTS | UART_MCR_AFCE;
    else
        uart->MCR = 0x00;
    /*FCR: FIFO Control Register*/
    uart->FCR = UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
                UART_FCR_FIFO_EN | UART_FCR_TRIGGER_8;
    /* Baud rate setting.*/
    uart->LCR = UART_LCR_DLAB;
    uart->DLL = baud_divisor & 0xff;
    uart->DLH = (baud_divisor >> 8) & 0xff;
    /* 8 data, 1 stop, no parity */
    uart->LCR = UART_LCR_8N1;
    /* Set UARTs int mask */
    if (uart_rx_cb)
    {
        uart->IER = UART_IER_RLSI | UART_IER_RDI;
        NVIC_ClearPendingIRQ(UART1_IRQn);
        NVIC_SetPriority(UART1_IRQn, IRQ_PRIORITY_HIGH);
        NVIC_EnableIRQ(UART1_IRQn);
    }
    else
    {
        uart->IER = 0;
        NVIC_DisableIRQ(UART1_IRQn);
    }
    uart_env.uart[0].tx_cmp_cb = NULL;
    uart_env.uart[0].rx_cb = uart_rx_cb;
}

/**
 * @brief uart send with noblock
 *
 * @param[in] uart  uart object
 * @param[in] buf  transmit data buffer
 * @param[in] length  transmit data length
 * @param[in] txcb  transmit complete callback
 *
 * @return None
 **/
void uart_send_noblock(HS_UART_Type *uart, uint8_t **buf, unsigned *length, uart_tx_cmp_callback_t txcb)
{
    uint32_t count = *length;
    uint32_t fifo_len = 0;
    uart_env.uart[0].tx_cmp_cb = txcb;
    fifo_len = 16;
    if (count >= fifo_len)
        count = fifo_len;
    (*length) -= count;
    do
    {
        uart->THR = *((*buf)++);
        count--;
    }
    while (count);
    uart->IER |= UART_IER_THRI;
}

/**
 * @brief uart wait send finish @ref uart_send_noblock
 *
 * @param[in] uart  uart object
 *
 * @return None
 **/
void uart_wait_send_finish(HS_UART_Type *uart)
{
    while (!(uart->LSR & UART_LSR_TEMT));
}

/**
 * @brief uart send with block
 *
 * @param[in] uart  uart object
 * @param[in] buf  transmit data buffer
 * @param[in] length  transmit data length
 *
 * @return None
 **/
void uart_send_block(HS_UART_Type *uart, const uint8_t *buf, unsigned length)
{
    unsigned i;
    for (i = 0; i < length; ++i)
    {
        while (!(uart->LSR & UART_LSR_THRE));
        uart->THR = buf[i];
    }
    while (!(uart->LSR & UART_LSR_TEMT));
}

/**
 * @brief uart empty fifo
 *
 * @param[in] uart  uart object
 *
 * @return None
 **/
void uart_empty_fifo(HS_UART_Type *uart)
{
    volatile uint32_t data;
    while (uart->LSR & UART_LSR_DR) /* Read all characters out of the fifo */
        data = uart->RBR;
    (void) data;
}

void UART1_IRQHandler(void)
{
    uart_check_irq(HS_UART1, &uart_env.uart[0]);
}





4 测试结果,发1280,收1280。

  // Init UART

    uart_open(DEBUG_UART, DEBUG_UART_BAUDRATE, UART_FLOW_CTRL_DISABLED, uart_recv_cb);

   //callback 实际未使用,可以根据需要去使用

image.png



uart-202311307524.c
被收藏 0  ∙  0 赞  
加入收藏
点赞
0 回复  
善言善语 (您需要 登录 后才能回复 没有账号 ?)

请先登录网站