(十)零基础开发小安派-Eyes-S1【外设篇】——UART

[复制链接]
查看3677 | 回复27 | 2023-10-9 15:42:35 | 显示全部楼层 |阅读模式

零基础开发小安派-Eyes-S1【外设篇】——UART

通用异步收发传输器(Universal Asynchronous Receiver/Transmitter, 通常称为 UART) 是一种异步收发传输器,提供了与外部设备进行全双工数据交换的灵活方式。BL616/BL618 共有 2组 UART,配合 DMA 使用,可以实现高效的数据通信。

一、了解小安派-Eyes-S1的UART

小安派的UART是全双工异步通讯,具有丰富的中断控制,DMA传输、485协议、10Mbps波特率、LIN总线协议等等特征。其有三个时钟源,分别是XCK、160Mhz CLK和BCLK。UART的控制器分为两个功能模块:发送器和接收器。

数据位长度可选 5 / 6 / 7 / 8 比特

#define UART_DATA_BITS_5 0
#define UART_DATA_BITS_6 1
#define UART_DATA_BITS_7 2
#define UART_DATA_BITS_8 3
#define UART_DATA_BITS_9 4

停止位长度可选 0.5 / 1 / 1.5 / 2 比特

#define UART_STOP_BITS_0_5 0
#define UART_STOP_BITS_1   1
#define UART_STOP_BITS_1_5 2
#define UART_STOP_BITS_2   3

支持 奇 / 偶 / 无 / 校验比特

#define UART_PARITY_NONE  0
#define UART_PARITY_ODD   1
#define UART_PARITY_EVEN  2
#define UART_PARITY_MARK  3
#define UART_PARITY_SPACE 4

可配置 MSB / LSB 优先输出

#define UART_LSB_FIRST 0
#define UART_MSB_FIRST 1

1.struct bflb_uart_config_s

说明:uart初始化配置结构体

struct bflb_uart_config_s {
uint32_t baudrate;
uint8_t direction;
uint8_t data_bits;
uint8_t stop_bits;
uint8_t parity;
uint8_t bit_order;
uint8_t flow_ctrl;
uint8_t tx_fifo_threshold;
uint8_t rx_fifo_threshold;
};
parameter description
baudrate 波特率
direction 方向
data_bits 数据位
stop_bits 停止位
parity 校验位
bit_orders bit 先行方式
flow_ctrl 流控
tx_fifo_threshold 发送 fifo 中断触发阈值(大于阈值触发中断)
rx_fifo_threshold 接收 fifo 中断触发阈值(大于阈值触发中断)

2.bflb_uart_init

说明: 初始化 uart。使用之前需要开启 uart ip 时钟、设置 uart 时钟源和分频值、选择 gpio 为 uart 中的一个功能。

void bflb_uart_init(struct bflb_device_s *dev, const struct bflb_uart_config_s *config);
parameter description
dev 设备句柄
config 配置项

3.bflb_uart_deinit

说明: 反初始化 uart。

void bflb_uart_deinit(struct bflb_device_s *dev);
parameter description
dev 设备句柄

4.bflb_uart_link_txdma

说明: uart tx dma 使能开关。

void bflb_uart_link_txdma(struct bflb_device_s *dev, bool enable);
parameter description
dev 设备句柄
enable 是否使能 dma

5.bflb_uart_link_rxdma

说明: uart rx dma 使能开关。

void bflb_uart_link_rxdma(struct bflb_device_s *dev, bool enable);
parameter description
dev 设备句柄
enable 是否使能 dma

6.bflb_uart_putchar

说明: 通过 uart 阻塞式发送一个字符。

int bflb_uart_putchar(struct bflb_device_s *dev, int ch);
parameter description
dev 设备句柄
ch 字符

7.bflb_uart_getchar

说明: 通过 uart 异步接收一个字符。

int bflb_uart_getchar(struct bflb_device_s *dev);
parameter description
dev 设备句柄
return 返回 -1 表示没有数据,返回其他表示接收的字符

8.bflb_uart_put

说明:通过uart轮询发送数据。

int bflb_uart_put(struct bflb_device_s *dev, uint8_t *data, uint32_t len);
parameter description
dev 设备句柄
data 数据指针
len 数据长度

9.bflb_uart_put_block

说明:通过uart阻塞式发送数据。

int bflb_uart_put_block(struct bflb_device_s *dev, uint8_t *data, uint32_t len);
parameter description
dev 设备句柄
data 数据指针
len 数据长度

10.bflb_uart_get

说明:通过uart异步阻塞接收数据。

int bflb_uart_get(struct bflb_device_s *dev, uint8_t *data, uint32_t len);
parameter description
dev 设备句柄
data 数据指针
len 数据长度

11.bflb_uart_txready

说明: 查询 uart tx fifo 是否准备就绪,准备好才可以填充字符。

bool bflb_uart_txready(struct bflb_device_s *dev);
parameter description
dev 设备句柄
return 为true表示就绪

12.bflb_uart_txempty

说明: 查询 uart tx fifo 是否为空。

bool bflb_uart_txempty(struct bflb_device_s *dev);
parameter description
dev 设备句柄
return 为true表示fifo已空,无法填充数据

13.bflb_uart_rxavailable

说明: 查询 uart rx 是否有数据。

bool bflb_uart_rxavailable(struct bflb_device_s *dev);
parameter description
dev 设备句柄
return 为true表示有数据,可以进行读取

14.bflb_uart_txint_mask

说明: uart tx fifo 阈值中断屏蔽开关,开启后超过设定阈值则触发中断。

void bflb_uart_txint_mask(struct bflb_device_s *dev, bool mask);
parameter description
dev 设备句柄
mask 是否屏蔽中断

15.bflb_uart_rxint_mask

说明: uart rx fifo 阈值中断和超时屏蔽开关,开启后超过设定阈值则或者超时则触发中断。

void bflb_uart_rxint_mask(struct bflb_device_s *dev, bool mask);
parameter description
dev 设备句柄
mask 是否屏蔽中断

16.bflb_uart_errint_mask

说明:uart错误中断屏蔽开关。

void bflb_uart_errint_mask(struct bflb_device_s *dev, bool mask);
parameter description
dev 设备句柄
mask 是否屏蔽中断

17.bflb_uart_get_intstatus

说明: 获取 uart 中断标志。

uint32_t bflb_uart_get_intstatus(struct bflb_device_s *dev);
parameter description
dev 设备句柄
retrun 中断标志

返回的中断标志有以下选项:

#define UART_INTSTS_TX_END  (1 << 0)
#define UART_INTSTS_RX_END  (1 << 1)
#define UART_INTSTS_TX_FIFO (1 << 2)
#define UART_INTSTS_RX_FIFO (1 << 3)
#define UART_INTSTS_RTO     (1 << 4)
#define UART_INTSTS_PCE     (1 << 5)
#define UART_INTSTS_TX_FER  (1 << 6)
#define UART_INTSTS_RX_FER  (1 << 7)
#if !defined(BL602)
#define UART_INTSTS_RX_LSE (1 << 8)
#endif
#if !defined(BL602) && !defined(BL702)
#define UART_INTSTS_RX_BCR (1 << 9)
#define UART_INTSTS_RX_ADS (1 << 10)
#define UART_INTSTS_RX_AD5 (1 << 11)
#endif

18.bflb_uart_int_clear

说明: 清除 uart 中断标志。

void bflb_uart_int_clear(struct bflb_device_s *dev, uint32_t int_clear);
parameter description
dev 设备句柄
int_clear 清除值

清除值可填入以下参数:

#define UART_INTCLR_TX_END (1 << 0)
#define UART_INTCLR_RX_END (1 << 1)
#define UART_INTCLR_RTO    (1 << 4)
#define UART_INTCLR_PCE    (1 << 5)
#if !defined(BL602)
#define UART_INTCLR_RX_LSE (1 << 8)
#endif
#if !defined(BL602) && !defined(BL702)
#define UART_INTCLR_RX_BCR (1 << 9)
#define UART_INTCLR_RX_ADS (1 << 10)
#define UART_INTCLR_RX_AD5 (1 << 11)
#endif

19.bflb_uart_feature_control

说明:uart其他特性相关控制,一般不常用。

int bflb_uart_feature_control(struct bflb_device_s *dev, int cmd, size_t arg);
parameter description
dev 设备句柄
cmd 控制字
arg 控制参数
return 为负表示不支持该命令

cmd 可以填入以下参数:

#define UART_CMD_SET_BAUD_RATE           (0x01)
#define UART_CMD_SET_DATA_BITS           (0x02)
#define UART_CMD_SET_STOP_BITS           (0x03)
#define UART_CMD_SET_PARITY_BITS         (0x04)
#define UART_CMD_CLR_TX_FIFO             (0x05)
#define UART_CMD_CLR_RX_FIFO             (0x06)
#define UART_CMD_SET_RTO_VALUE           (0x07)
#define UART_CMD_SET_RTS_VALUE           (0x08)
#define UART_CMD_GET_TX_FIFO_CNT         (0x09)
#define UART_CMD_GET_RX_FIFO_CNT         (0x0a)
#define UART_CMD_SET_AUTO_BAUD           (0x0b)
#define UART_CMD_GET_AUTO_BAUD           (0x0c)
#define UART_CMD_SET_BREAK_VALUE         (0x0d)
#define UART_CMD_SET_TX_LIN_VALUE        (0x0e)
#define UART_CMD_SET_RX_LIN_VALUE        (0x0f)
#define UART_CMD_SET_TX_RX_EN            (0x10)
#define UART_CMD_SET_TX_RS485_EN         (0x11)
#define UART_CMD_SET_TX_RS485_POLARITY   (0x12)
#define UART_CMD_SET_ABR_ALLOWABLE_ERROR (0x13)
#define UART_CMD_SET_SW_RTS_CONTROL      (0x14)
#define UART_CMD_IR_CONFIG               (0x15)
#define UART_CMD_SET_TX_FREERUN          (0x16)
#define UART_CMD_SET_TX_END_INTERRUPT    (0x17)
#define UART_CMD_SET_RX_END_INTERRUPT    (0x18)
#define UART_CMD_SET_TX_TRANSFER_LEN     (0x19)
#define UART_CMD_SET_RX_TRANSFER_LEN     (0x20)
#define UART_CMD_SET_TX_EN               (0x21)
#define UART_CMD_SET_BCR_END_INTERRUPT   (0x22)
#define UART_CMD_GET_BCR_COUNT           (0x23)

二、示例:UART发送,中断接收

小安派-Eyes-S1具有两组串口,UART0已经被映射为prtinf函数,也就是LOG函数,我们还剩下一组UART1可使用,而且小安派的GPIO可以任意配置为UART的TX或RX,这里使用GPIO_1和GPIO_0配置为UART1。

实现的效果是,在主函数里轮询发送数据,当UART1接收到其他数据时,触发接收中断并使用UART0发送,也就是LOG函数发送出来,实现透传的效果。

Main

//头文件
#include "bflb_mtimer.h"
#include "bflb_uart.h"
#include "bflb_gpio.h"
#include "board.h"

//设置名为uart1的外设句柄
struct bflb_device_s *uart1;

//定义需要轮询发送的数据
static uint8_t uart_txbuf[4] = { 0,1,2,3 };

void uart_isr(int irq, void *arg);

//初始化串口配置,如波特率,数据位和停止位
//tx_fifo_threshold 和 rx_fifo_threshold 参数设置表示为fifo中断的触发阈值

static void uart_init(void)
{
    struct bflb_device_s* gpio;
    struct bflb_uart_config_s cfg = {
        .baudrate = 115200,
        .data_bits = UART_DATA_BITS_8,
        .stop_bits = UART_STOP_BITS_1,
        .parity = UART_PARITY_NONE,
        .flow_ctrl = 0,
        .tx_fifo_threshold = 4,
        .rx_fifo_threshold = 4,
    };

    gpio = bflb_device_get_by_name("gpio");
    uart1 = bflb_device_get_by_name("uart1");

    //将GPIO_1和GPIO_0设置为TX和RX

    bflb_gpio_uart_init(gpio, GPIO_PIN_1, GPIO_UART_FUNC_UART1_TX);
    bflb_gpio_uart_init(gpio, GPIO_PIN_0, GPIO_UART_FUNC_UART1_RX);

    bflb_uart_init(uart1, &cfg);

    bflb_uart_txint_mask(uart1, true);
    bflb_uart_rxint_mask(uart1, false);
    bflb_irq_attach(uart1->irq_num, uart_isr, NULL);
    bflb_irq_enable(uart1->irq_num);

}

//中断服务函数,触发中断后会进入该函数

void uart_isr(int irq, void *arg)
{
    uint32_t intstatus = bflb_uart_get_intstatus(uart1);

   //这里注释了fifo管道的RX中断触发,fifo的触发方式也就是上面设置的字节数4,也就是要接收4个字节以上数据才会触发fifo中断

    // if (intstatus & UART_INTSTS_RX_FIFO) {
    //     printf("rx fifo\r\n");
    //     while (bflb_uart_rxavailable(uart1)) {
    //         printf("0x%02x\r\n", bflb_uart_getchar(uart1));
    //     }
    // }

   //接收超时中断,当一段时间内数据没有接收后便会停止,在触发中断后,轮询使用prtintf发送uart1接收到的字符,停止接收后清空中断标志等待下一次发送

    if (intstatus & UART_INTSTS_RTO) {
        printf("rto\r\n");
        while (bflb_uart_rxavailable(uart1)) {
            printf("0x%02x\r\n", bflb_uart_getchar(uart1));
        }
        bflb_uart_int_clear(uart1, UART_INTCLR_RTO);
    }
}

int main(void)
{
    board_init();
    uart_init();

    //主函数每两秒轮询一次发送 uart_txbuf 数据

    while (1) {
        bflb_mtimer_delay_ms(2000);
        bflb_uart_put(uart1,uart_txbuf,4);
    }
}

实现效果

uart1每两秒发送一次 00 01 02 03 ,左边框中可以看见持续接收到数据,当uart1接收到其他数据时如 AA BB CC DD EE FF 或 11 22 33 ,可以在右边的uart0框中看见接收到的数据,可以看见触发的中断方式为RTO超时。可以尝试fifo的方式看看两种方式的差异性,在后续处理串口协议时,面对不同的协议采用不同的方式来应对。

UART.gif

本帖被以下淘专辑推荐:

回复

使用道具 举报

秋天的童话 | 2023-10-9 16:11:47 | 显示全部楼层
学习
回复

使用道具 举报

WangChong | 2023-10-9 16:18:38 | 显示全部楼层
学习了 但是似乎也没有学习
回复 支持 反对

使用道具 举报

爱笑 | 2023-10-9 17:05:43 | 显示全部楼层
小泽排版越来越好看了~
用心做好保姆工作
回复 支持 反对

使用道具 举报

iiv | 2023-10-9 18:56:04 | 显示全部楼层
重大新闻,泽哥更新了!
回复 支持 反对

使用道具 举报

18350766600@139 | 2023-10-9 21:12:10 | 显示全部楼层
没有置顶啊,会丢失
回复 支持 反对

使用道具 举报

lsrly | 2023-10-10 10:52:08 | 显示全部楼层
帮顶一下,省的找不到
回复 支持 反对

使用道具 举报

开发板 | 2023-10-10 16:40:07 | 显示全部楼层
终于更了
回复

使用道具 举报

见素抱朴 | 2023-10-17 21:11:06 | 显示全部楼层
学习了 但是似乎也没有学习
回复 支持 反对

使用道具 举报

见素抱朴 | 2023-10-17 21:12:34 | 显示全部楼层
看不懂呀
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则