Zephry Uart Device详解

 目录

前言

一、Uart Device介绍

1 常用API介绍

1.1 uart_configure

1.2 uart_get

1.3 uart_tx

1.4 uart_tx_abort

1.5 uart_rx_enable

1.6 uart_poll_in

1.7 uart_poll_out

1.8  uart_callback_set

1.9 uart_irq_callback_set(旧版)

1.9.2 回调函数介绍

2.0 uart_irq_callback_user_data_set

2.1 uart_irq_tx_enable

2.2 uart_irq_tx_disable

2.3 uart_irq_rx_enable

2.2 uart_irq_rx_disable

2.3 uart_irq_tx_ready

2.4 uart_irq_update

2.2 参数介绍

2.3 注释

2.5 uart_irq_rx_ready

2.2 参数介绍

2.5 uart_irq_tx_ready

2.2 参数介绍

2.5 IRQ相关函数使用事项

2.6 uart_fifo_fill

2.7 uart_fifo_fill

2.8 uart_drv_cmd

2 结构体介绍

1. uart_config

1.3 位相关枚举

2. uart_event

2.1 结构体原型

2.2 主要成员介绍

3 开发注意事项

4 示例


前言

Uart实现原理与理论知识请参考这篇文章:UART工作原理详解

一、Uart Device介绍

1 常用API介绍

1.1 uart_configure

1.1.1 函数介绍

函数原型

作用

返回值

int uart_configure(const struct device* dev, const struct uart_config* cfg)配置uart设备0成功,非0失败

1.1.2 参数介绍

参数名

类型

作用

devconst struct device*指向Uart设备驱动指针
cfgconst struct uart_config*指向配置结构体的指针

1.2 uart_get

1.2.1 函数介绍

函数原型

作用

返回值

int uart_config_get(const struct device* dev, struct uart_config* cfg)获取当前Uart设备的属性,如波特率之类的0成功,非0失败

1.2.2 参数介绍

参数名

类型

作用

devconst struct device*指向Uart设备驱动指针
cfgstruct uart_config*指向配置结构体的指针,会将Uart设备属性写入到这个结构体的成员变量中

1.3 uart_tx

1.3.1 函数介绍

函数原型

作用

返回值

int uart_tx(const struct device* dev, const uint8_t* buf, size_t len, int32_t timeout)向串口写入数据0成功,非0失败

1.3.2 参数介绍

参数名

类型

作用

devconst struct device*指向Uart设备驱动指针
bufconst uint8_t*要写入的数据
lensize_t写入数据的长度
timeoutint32_t超时等待时长,毫秒为单位

1.4 uart_tx_abort

1.4.1 函数介绍

函数原型

作用

返回值

int uart_tx_abort(const struct device *dev)终止当前串口数据的发送0成功,非0失败

1.4.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针

1.5 uart_rx_enable

1.5.1 函数介绍

函数原型

作用

返回值

int uart_rx_enable(const struct device *dev, uint8_t *buf, size_t len, int32_t timeout)从串口接收数据0成功,非0失败

1.5.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针
bufuint8_t *指向接收缓冲区的指针
lensize_t接收缓冲区的大小
timeoutint32_t超时时间

1.6 uart_poll_in

1.6.1 函数介绍

函数原型

作用

返回值

int uart_poll_in(const struct device *dev, unsigned char *p_char)在轮询的模式下接收数据的输入0成功,非0失败

1.6.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针
p_charunsigned char *指向unsigned char类型的指针

1.6.3 注释

轮询模式是指每隔一段时间就去读一下缓冲区是否有数据,这个函数每次只能读入一个字节的字符

此函数需要配合循环使用,这个函数的作用就是去检查UART LSR寄存器中的DR位,这个位表示是否有新的数据到来,如果为1则有数据到了,则从里面读入一个字节数据出来,需要注意它不是阻塞函数,需要用户使用while循环配合使用

1.7 uart_poll_out

1.7.1 函数介绍

函数原型

作用

返回值

void uart_poll_out(const struct device *dev, unsigned char out_char)轮询的模式下向串口输出一个字符无返回值

1.7.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针
out_charunsigned char输出的字符

1.7.3 注释

此函数会向数据缓存器里写一个字节,然后查UART LSR寄存器中的TEMT和THRE两个位是否为0,只有这两个位为0时则代表数据发送寄存器里已经有数据了以及已经做好了发送准备可以进行发送了,然后开始发送,它也不是阻塞函数,需要用户配合while循环来使用,目的就是为了达到轮询的效果

1.8  uart_callback_set

1.8.1 函数介绍

函数原型

作用

返回值

static inline int uart_callback_set(const struct device *dev, uart_callback_t callback, void *user_data)设置事件处理回调函数0成功,非0失败

1.8.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针
callbackuart_callback_t回调函数,原型:void uart_call (const struct device *dev, struct uart_event* evt,void* user_data)
user_datavoid *要传递的参数

1.8.3 回调函数介绍

1.8.3.1 函数介绍

函数原型

作用

返回值

void uart_call (const struct device *dev, struct uart_event* evt,void* user_data)uart事件回调

1.8.3.2 参数介绍

这些参数会在回调时由uart驱动传递进来

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针
evtstruct uart_event*发生的事件
user_datavoid*传递参数

1.9 uart_irq_callback_set(旧版)

1.9.1 函数介绍

函数原型

作用

返回值

static inline void uart_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb)设置IRQ中断回调函数

1.9.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针
cbuart_irq_callback_user_data_t回调函数原型

1.9.2 回调函数介绍

1.9.2.1 函数介绍

函数原型

作用

返回值

static void func_irq(const struct device *dev, void *user_data)当UART硬件产生中断时回调的函数

1.9.2.2 参数介绍

参数名

类型

作用

devconst struct device *产生中断的Uart设备驱动
user_datavoid *传递的数据指针

1.9.3 注释

这个函数不支持传递数据指针

2.0 uart_irq_callback_user_data_set

2.1 函数介绍

函数原型

作用

返回值

static inline void uart_irq_callback_user_data_set(const struct device *dev, uart_irq_callback_user_data_t cb, void *user_data)设置IRQ回调函数,支持传递参数

2.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针
cbuart_irq_callback_user_data_t回调函数原型
user_datavoid *传递参数

2.3 注释

回调参数原型参考uart_irq_callback_set函数介绍

2.1 uart_irq_tx_enable

2.1 函数介绍

函数原型

作用

返回值

void uart_irq_tx_enable(const struct device *dev)将IER(中断使能寄存器)寄存器中的TX开启,允许产生TX中断

2.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针

2.2 uart_irq_tx_disable

2.1 函数介绍

函数原型

作用

返回值

void uart_irq_tx_disable(const struct device *dev)将IER(中断使能寄存器)寄存器中的TX关闭,禁止产生TX中断

2.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针

2.3 uart_irq_rx_enable

2.1 函数介绍

函数原型

作用

返回值

void uart_irq_rx_enable(const struct device *dev)将IER(中断使能寄存器)寄存器中的RX开启,允许产生RX中断

2.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针

2.2 uart_irq_rx_disable

2.1 函数介绍

函数原型

作用

返回值

void uart_irq_rx_disable(const struct device *dev)将IER(中断使能寄存器)寄存器中的RX关闭,禁止产生RX中断

2.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针

2.3 uart_irq_tx_ready

2.1 函数介绍

函数原型

作用

返回值

static inline int uart_irq_tx_ready(const struct device *dev)检查TX的Ready位是否有效,即判断TX FIFO输入缓冲区是否可以接收新的数据可以写入返回1,不能写入返回0

2.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针

2.4 uart_irq_update

2.1 函数介绍

函数原型

作用

返回值

int uart_irq_update(const struct device *dev)更新中断标志位成功返回1,否则返回0

2.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针

2.3 注释

在硬件中断开发时我们是需要手动更新中断标志位的,这个函数的作用就是如此

2.5 uart_irq_rx_ready

2.1 函数介绍

函数原型

作用

返回值

static inline int uart_irq_rx_ready(const struct device *dev)检查RX Ready位是否为1,即检查输入缓冲区是否有新的数据来返回1则代表有新数据可以读取,非1则无数据

2.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针

2.5 uart_irq_tx_ready

2.1 函数介绍

函数原型

作用

返回值

static inline int uart_irq_tx_ready(const struct device *dev)检查TX Ready位是否为1,即检查输出缓冲区是否有新的数据可以输出返回1则代表有新数据可以输出,非1则无数据

2.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针

2.5 IRQ相关函数使用事项

在使用IRQ相关的函数时,Zephry要求在中断处理函数中,先调用uart_irq_update更新中断标志寄存器,然后调用uart_irq_tx_ready或uart_irq_rx_ready来检查输入输出是否有效,然后在进行相关读写操作

其次uart_irq_callback_set与uart_callback_set是不同的,uart_irq_callback_set是用来设置硬件方面的中断的回调,uart_callback_set是用来Zephry Uart驱动内部回调事件,比如Uart驱动写入了一个数据它自己会产生一个消息为DONE,即写入完成的事件然后回调函数并将事件传入

2.6 uart_fifo_fill

2.1 函数介绍

函数原型

作用

返回值

static inline int uart_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)向FIFO缓冲区写入数据返回写入字节长度

2.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针
tx_dataconst uint8_t *输入缓冲区指针
sizeint缓冲区大小

2.7 uart_fifo_fill

2.1 函数介绍

函数原型

作用

返回值

static inline int uart_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)从FIFO缓冲区读取数据返回读取字节长度

2.2 参数介绍

参数名

类型

作用

devconst struct device *指向Uart设备驱动指针
rx_dataconst uint8_t *接收数据缓冲区指针
sizeint缓冲区大小

2.8 uart_drv_cmd

2.1 函数介绍

函数原型

作用

返回值

int uart_drv_cmd(const struct device* dev, uint32_t cmd, uint32_t p)向串口发送命令0成功,非0失败

2.2 参数介绍

参数名

类型

作用

devconst struct device*指向Uart设备驱动指针
cmduint32_t命令
puint32_t命令附加参数

2.3 注释

该函数需要驱动程序实现uart命令,详细请参考Zephry Uart驱动

2 结构体介绍

1. uart_config

1.1 结构体原型

struct uart_config {
    uint32_t baudrate;
    uint8_t parity;
    uint8_t stop_bits;
    uint8_t data_bits;
    uint8_t flow_ctrl;
};

1.2 成员介绍

成员名

类型

作用

baudrateuint32_t波特率
parityuint8_t奇偶校验位
stop_bitsuint8_t停止位
data_bitsuint8_t数据位
flow_ctrluint8_t流控制位

1.3 位相关枚举

1.3.1 奇偶校验位:uart_config_parity

枚举定义

作用

UART_CFG_PARITY_NONE

无奇偶校验位
UART_CFG_PARITY_ODD奇校验位,1为奇数校验位为0,偶数校验位为1
UART_CFG_PARITY_EVEN偶校验位,1为奇数校验位为1,偶数校验位为0
UART_CFG_PARITY_MARK校验位始终为1
UART_CFG_PARITY_SPACE校验位始终为0

1.3.2 停止位:uart_config_stop_bits

枚举定义

作用

UART_CFG_STOP_BITS_0_5停止位为0或5个BIT
UART_CFG_STOP_BITS_1停止位为1个BIT
UART_CFG_STOP_BITS_1_5停止位为1或5个BIT
UART_CFG_STOP_BITS_2停止位为2个BIT

1.3.3 数据位: uart_config_data_bits

枚举定义

作用

UART_CFG_DATA_BITS_5数据位为5BIT
UART_CFG_DATA_BITS_6数据位为6BIT
UART_CFG_DATA_BITS_7数据位为7BIT
UART_CFG_DATA_BITS_8数据位为8BIT
UART_CFG_DATA_BITS_9数据位为9BIT

1.3.4 流控制位:uart_config_flow_control

枚举定义

作用

UART_CFG_FLOW_CTRL_NONE无流控制
UART_CFG_FLOW_CTRL_RTS_CTSRTS/CTS线有效
UART_CFG_FLOW_CTRL_DTR_DSRDTR/DSR线有效

流控制一旦开启,需要用户手动根据当前流方向来修改RTS/CTS或DTR/DSR线的高低电平

2. uart_event

2.1 结构体原型

struct uart_event {
    enum uart_event_type type;
    union uart_event_data {
        struct uart_event_tx tx;
        struct uart_event_rx rx;
        struct uart_event_rx_buf rx_buf;
        struct uart_event_rx_stop rx_stop;
    } data;
};

2.2 主要成员介绍

1. type

此成员是个枚举,它的值指向当前发生的事件,可以取如下值:

枚举定义

作用

枚举定义

作用

UART_TX_DONE写入完成
UART_TX_ABORTED超时写入,在调用uart_tx有个超时参数,当超时时会发送此事件
UART_RX_RDY接收数据已经准备好处理
UART_RX_BUF_REQUEST缓冲区切换接收,当一个缓冲区在接收时调用uart_rx_buf_rsp进行无缝切换接收时会产生这个事件
UART_RX_BUF_RELEASED,RX接收被禁用且此时可以进行启动时候产生的事件
UART_RX_DISABLEDRX被禁用时产生的事件
UART_RX_STOPPED由于外部原因,导致RX停止接收时产生的事件

2. uart_event_data

此成员是个联合体,当产生不同事件时它内部仅有一个成员有效

当产生tx相关事件时tx成员有效

rx相关时rx成员有效

产生stop时rx_stop有效

3 开发注意事项

Zephry针对不同的板子有不同的Uart驱动实现,都放在zephyrproject/zephyr/drivers/serial这个目录下打开可以看到有不同板子的实现

CMakeLists.txt         Kconfig.mcux_lpsci     Kconfig.test            uart_lpc11u6x.c       uart_rcar.c
Kconfig                Kconfig.mcux_lpuart    Kconfig.uart_sam        uart_lpc11u6x.h       uart_rom_esp32c3.c
Kconfig.altera_jtag    Kconfig.miv            Kconfig.usart_sam       uart_mcux.c           uart_rtt.c
Kconfig.apbuart        Kconfig.msp432p4xx     Kconfig.xlnx            uart_mcux_flexcomm.c  uart_rv32m1_lpuart.c
Kconfig.b91            Kconfig.native_posix   Kconfig.xmc4xxx         uart_mcux_iuart.c     uart_sam0.c
Kconfig.cc13xx_cc26xx  Kconfig.npcx           leuart_gecko.c          uart_mcux_lpsci.c     uart_sam.c
Kconfig.cc32xx         Kconfig.nrfx           serial_test.c           uart_mcux_lpuart.c    uart_sifive.c
Kconfig.cmsdk_apb      Kconfig.ns16550        uart_altera_jtag_hal.c  uart_miv.c            uart_stellaris.c
Kconfig.esp32          Kconfig.nuvoton        uart_apbuart.c          uart_msp432p4xx.c     uart_stm32.c
Kconfig.esp32c3_rom    Kconfig.pl011          uart_b91.c              uart_native_posix.c   uart_stm32.h
Kconfig.gecko          Kconfig.psoc6          uart_cc13xx_cc26xx.c    uart_npcx.c           uart_xlnx_ps.c
Kconfig.imx            Kconfig.rcar           uart_cc32xx.c           uart_nrfx_uart.c      uart_xlnx_uartlite.c
Kconfig.leuart_gecko   Kconfig.rtt            uart_cmsdk_apb.c        uart_nrfx_uarte.c     uart_xmc4xxx.c
Kconfig.litex          Kconfig.rv32m1_lpuart  uart_esp32.c            uart_ns16550.c        usart_sam.c
Kconfig.lpc11u6x       Kconfig.sam0           uart_gecko.c            uart_ns16550.h
Kconfig.mcux           Kconfig.sifive         uart_handlers.c         uart_nuvoton.c
Kconfig.mcux_flexcomm  Kconfig.stellaris      uart_imx.c              uart_pl011.c
Kconfig.mcux_iuart     Kconfig.stm32          uart_liteuart.c         uart_psoc6.c

可以看到许多uart开头的实现文件,如我们的是stm32的板子,对应的驱动实现就是uart_stm32.c这个文件,如果你在使用时出现了问题,可以到这个文件中去看下驱动实现,出现了什么问题

4 示例

这里我基于FIFO模式实现了一个LOOPBACK回环的代码,我的UART RX与TX是相连的,可供大家参考与使用

注意使用前需要在prj.conf中开启驱动

CONFIG_SERIAL=y
CONFIG_UART_ASYNC_API=y
CONFIG_UART_INTERRUPT_DRIVEN=y

完整实现代码:

#include <zephyr.h>
#include <sys/printk.h>
#include <device.h>
#include <drivers/uart.h>
#include <errno.h>
#include <string.h>
//Packaging structure
struct tx_data{
    uint8_t* data;
    size_t   len;
    size_t   msg;
}send_data;
 
struct rx_data{
    uint8_t* data;
    size_t   len;
    size_t   msg;
}recv_data;
 
static void uart_fifo_callback(const struct device *dev, void *user_data){
 
    static int tx_send_index;
    static int rx_recv_index;
    struct tx_data* tx_send_data = &send_data;
    struct rx_data* rx_recv_data = &recv_data;
 
    if(uart_irq_update(dev) !=1 ){
        return;
 
    }
    //if write
    if(uart_irq_tx_ready(dev) && tx_send_index < tx_send_data->len && tx_send_data->msg == MSG_SEND){
 
        uart_fifo_fill(dev,(uint8_t*)&tx_send_data->data[tx_send_index++],SEND_LEN);
        if(tx_send_index >= tx_send_data->len){
 
            tx_send_index = 0;
            tx_send_data->msg = MSG_DONE;
            //Stop and interrupt manually after meeting the requirements
            uart_irq_tx_disable(dev);
 
        }
    }
 
 
    //if read
    if(uart_irq_rx_ready(dev)){
        uart_fifo_read(dev,(uint8_t*)&rx_recv_data->data[rx_recv_index++],RECV_LEN);
        if(rx_recv_index >= rx_recv_data->len){
            uart_irq_rx_disable(dev);
        }
    }
 
 
}
int uart_send(const struct device* dev,uint8_t* data,size_t len){
 
    if(dev == NULL || data == NULL || len == 0){
 
        return -1;
 
    }
 
    send_data.data = data;
    send_data.len  = len;
    send_data.msg  = MSG_SEND;
    //After the enable interrupt, judge whether to write or not                                                                      
    uart_irq_tx_enable(dev);
 
    k_sleep(K_MSEC(TIME_OUT));
 
    uart_irq_tx_disable(dev);
 
    if(send_data.msg != MSG_DONE) return -2;
    return 0;
 
 
}
 
int uart_recv(const struct device* dev,uint8_t* data,size_t len){
 
    if(dev == NULL || data == NULL || len == 0){
 
        return -1;
 
    }
 
    recv_data.data = data;
    recv_data.len  = len;
    recv_data.msg  = MSG_RECV;
 
    uart_irq_rx_enable(dev);
 
    k_sleep(K_MSEC(TIME_OUT));
 
    uart_irq_rx_disable(dev);
 
    if(send_data.msg != MSG_DONE) return -2;
    return 0;
 
}
 
void main(){
 
    printk("--- UART ---\n");
    uint8_t tx_buff[BUFF_LEN] = "hello word\r\n1";
    uint8_t rx_buff[BUFF_LEN] = {0};
 
    const struct device* dev = device_get_binding("UART_6");
    if(dev == NULL){ printk("ERROR bind\n");  return; }
 
    if(!device_is_ready(dev)) { printk("device is no ready\n"); return; }
 
    struct uart_config ut = {
        .baudrate = 115200,
        .parity =  UART_CFG_PARITY_NONE,
        .stop_bits = UART_CFG_STOP_BITS_1,
        .data_bits = UART_CFG_DATA_BITS_8,
        .flow_ctrl  =  UART_CFG_FLOW_CTRL_NONE,
    };
 
 
    if(uart_configure(dev,&ut) != 0) {
        printk("uart config error\n");
        return;
    }
 
    uart_irq_callback_set(dev,uart_fifo_callback);
 
    //write
    recv_data.data = rx_buff;
    recv_data.len  = strlen(rx_buff);
    uart_send(dev,tx_buff,strlen(tx_buff));
 
    printk("%s",rx_buff);
 
 
}

上述代码需要注意我没有写接收,因为是回环相接,当产生写入硬中断并写入后会立马产生RX中断

运行结果:

ing Zephyr OS build zephyr-v2.6.0-1753-g365ff6db9f02  ***
--- UART ---
hello word

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

17岁boy想当攻城狮

感谢打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值