I.MX RT 串口外设

  • by

其实这是最简单最好用的外设啦,库函数给了很多方法,但是我不太喜欢,主要是功能上有些迷人,也不太耐优化,啃吃了一会手册,自己写了个.

首先官方提供那么几个例子:

  • polling 轮询
  • polling_seven_bits 轮询(7位)
  • interrupt 自己实现中断传输
  • interrupt_transfer 中断传输(非阻塞,回调方式)
  • interrupt_rb_transfer 中断传输(非阻塞,环形缓冲)
  • interrupt_transfer_seven_bits 中断传输(非阻塞,回调方式)
  • edma_transfer DMA传输(数据量少并不划算)

我实测下,官方的历程均没使用FIFO,简直暴殄天物,而且DMA在数据量较少(比如几百字节)时候还不如FIFO + Interrupt方法呢.所以我自己也了个中断 + FIFO方法.实测TX FIFO为0,依然可以做到连续发送,说明硬件上取出数据后立马就减FIFO threshold,还是不错的.

代码参考:https://gist.github.com/nickfox-taterli/50d2b38319662967fee7eed16933b0e4

#include "board.h"
#include "fsl_lpuart.h"

#include "pin_mux.h"
#include "clock_config.h"

uint8_t txData[] = "Hello,World!";
uint8_t rxData[512];

typedef struct
{
    uint8_t *txData;
    uint16_t txIndex;
    uint16_t txLength;

    uint8_t *rxData;
    uint16_t rxIndex;
    uint16_t rxLength;
} LPUART_DataHandler;

LPUART_DataHandler LPUART1_DataHandler;

void LPUART1_IRQHandler(void)
{
    uint8_t count;

    if ((kLPUART_TxDataRegEmptyFlag)&LPUART_GetStatusFlags(LPUART1))
    {
        if (LPUART1_DataHandler.txLength == LPUART1_DataHandler.txIndex)
        {
            LPUART_DisableInterrupts(LPUART1, kLPUART_TxDataRegEmptyInterruptEnable);
            // 全部发送完毕,可以通知用户处理.
            __BKPT(0);
        }

        for (count = 0;
             count < MIN(4 - ((LPUART1->WATER >> 8U) & 0x07), LPUART1_DataHandler.txLength - LPUART1_DataHandler.txIndex);
             count++)
        {
            LPUART1->DATA = LPUART1_DataHandler.txData[LPUART1_DataHandler.txIndex++];
        }
    }

    if ((kLPUART_RxDataRegFullFlag)&LPUART_GetStatusFlags(LPUART1))
    {
        for (count = 0;
             count < ((LPUART1->WATER >> 24U) & 0x07) + 1;
             count++)
        {
            LPUART1_DataHandler.rxData[LPUART1_DataHandler.rxIndex] = LPUART1->DATA;
            LPUART1_DataHandler.rxIndex++;
            LPUART1_DataHandler.rxLength++;
        }
    }

    if ((kLPUART_IdleLineFlag)&LPUART_GetStatusFlags(LPUART1))
    {

        for (count = 0;
             count < ((LPUART1->WATER >> 24U) & 0x07) + 1;
             count++)
        {
            LPUART1_DataHandler.rxData[LPUART1_DataHandler.rxIndex] = LPUART1->DATA;
            LPUART1_DataHandler.rxIndex++;
            LPUART1_DataHandler.rxLength++;
        }

        LPUART1_DataHandler.rxIndex = 0;

        LPUART_ClearStatusFlags(LPUART1, kLPUART_IdleLineFlag);

        // 全部接收完成,可以通知用戶处理.
        __BKPT(0);
    }
}

void LPUART1_Send(uint8_t *xfer, uint8_t len)
{
    LPUART1_DataHandler.txData = xfer;
    LPUART1_DataHandler.txIndex = 0;
    LPUART1_DataHandler.txLength = len;
    LPUART_EnableInterrupts(LPUART1, kLPUART_TxDataRegEmptyInterruptEnable);
}

int main(void)
{
    lpuart_config_t config;

    BOARD_ConfigMPU();
    BOARD_InitPins();
    BOARD_BootClockRUN();

    LPUART_GetDefaultConfig(&config);
    config.baudRate_Bps = 115200U;
    config.parityMode = kLPUART_ParityDisabled;
    config.stopBitCount = kLPUART_OneStopBit;
    config.rxFifoWatermark = 0;
    config.rxFifoWatermark = 3;
    config.enableTx = true;
    config.enableRx = true;

    LPUART_Init(LPUART1, &config, BOARD_DebugConsoleSrcFreq());

    LPUART1_DataHandler.rxData = rxData;

    LPUART_EnableInterrupts(LPUART1, kLPUART_RxDataRegFullInterruptEnable);
    LPUART_EnableInterrupts(LPUART1, kLPUART_IdleLineInterruptEnable);
    EnableIRQ(LPUART1_IRQn);

    LPUART1_Send(txData, strlen((const char *)txData));

    while (1)
    {
    }
}

在IMX1010 EVK上实测,官方库函数DMA在370字节左右开始,才能拼得上我这个简易程序的速度,当然,官方是考虑更周详,所以也有轻微的牺牲,只是奇怪的是,竟然没用上FIFO,真是奇怪.

发表评论

电子邮件地址不会被公开。 必填项已用*标注