Zephyr UART

文章目录

  • 串口驱动工作方式
  • 定义串口设备节点
  • 修改串口配置
  • 编写设备驱动程序
    • 接口定义
    • 蓝牙串口驱动实例
    • 功能演示

串口驱动工作方式

  • 与大多数外设一样,串口的工作模式有三种:

    • 中断驱动模式
    • DMA异步模式
    • 轮询模式
  • 串口支持全双工通讯,不同的使用场景会采用不同的工作模式:

    • 当传输的数据流长度不固定时,需要对每一字节进行处理,通常会采用中断接收数据,确保数据解析的实时性。
    • 发送的数据量较大时,采用DMA进行发送,在DMA发送完成之前,其他任务可以继续正常工作,发送完成后阻塞任务被唤醒继续向下执行。

定义串口设备节点

  • 与串口相连接的设备通常定义在串口对应的节点下,根据设备的不同为其添加不同的属性。
  • 例如使用串口1控制串口蓝牙模块,该模块上除了使用串口,还可以提供一个低电平复位的引脚,此处不做演示,对应的设备树如下:
&usart1{
	uart-bluetooth: bluetooth{
		compatible = "uart-bluetooth-module";
		status = "okay";
	};
};
  • 除了设备树,还需要编写对应的绑定文件,下面是uart-bluetooth-module.yaml的内容
description: uart bluetooth module

compatible: "uart-bluetooth-module"

include: uart-device.yaml
  • 绑定文件的查找位置,在CMake编译设备树之前,会从一些目录查找绑定文件与设备树中的compatible属性进行匹配,如果匹配成功,会按照绑定文件中声明的类型将其编译成对应的宏,下面这些目录的子目录dts/bindings目录如果存在yaml文件,都会进行匹配:
    • zephyr源码仓库
    • 你的应用程序目录
    • zephyr源码中的boards下所使用的开发板对应的目录
    • 任何shield目录
  • 为了方便的添加设备,会在应用程序目录下新建一个dts/bindings目录,用于存放yaml文件,如果不在上述目录中添加,那么程序中访问对应节点时会报错找不到宏,此时可以通过生成的头文件devicetree_generated.h查看是否存在与该属性相关的宏,如果没有则需要检查绑定文件的目录是否正确。

修改串口配置

  • 此处需要使用串口中断,因此需要将 CONFIG_UART_INTERRUPT_DRIVEN 使能。

编写设备驱动程序

接口定义

  • 在这里将串口驱动用一组接口来进行表示,方便对功能进行扩展,首先是接口头文件:
#pragma once

#include <stdint.h>
#include <stdbool.h>

typedef void com_inface_t;

typedef struct
{
    const char *name;
    const void *user_data;
    void (*init)(com_inface_t *obj);
    int (*read)(com_inface_t *obj, void *buf, uint32_t length, uint32_t timeout_ms);
    int (*write)(com_inface_t *obj, const void *src, uint32_t size, uint32_t timeout_ms);
    void (*flush)(com_inface_t *obj);
} com_drv_t;

void com_init(com_inface_t *p);
const char *com_device_name(com_inface_t *p);
int com_read(com_inface_t *p, void *buf, uint32_t length, uint32_t timeout_ms);
int com_write(com_inface_t *p, const void *src, uint32_t size, uint32_t timeout_ms);
void com_flush(com_inface_t *p);
  • 接口源文件
#include "com_interface.h"

#define DEBUG_ASSERT(VALUE) \
    while (!(VALUE))        \
    {                       \
    }

void com_init(com_inface_t *p)
{
    DEBUG_ASSERT(((com_drv_t *)p)->init);
    ((com_drv_t *)p)->init(p);
}

const char *com_device_name(com_inface_t *p)
{
    return (p) ? (((com_drv_t *)p)->name) : ("");
}

int com_read(com_inface_t *p, void *buf, uint32_t length, uint32_t timeout_ms)
{
    DEBUG_ASSERT(((com_drv_t *)p)->read);
    return ((com_drv_t *)p)->read(p, buf, length, timeout_ms);
}

int com_write(com_inface_t *p, const void *src, uint32_t size, uint32_t timeout_ms)
{
    DEBUG_ASSERT(((com_drv_t *)p)->write);
    return ((com_drv_t *)p)->write(p, src, size, timeout_ms);
}

void com_flush(com_inface_t *p)
{
    DEBUG_ASSERT(((com_drv_t *)p)->flush);
    ((com_drv_t *)p)->flush(p);
}

蓝牙串口驱动实例

  • 蓝牙模块连接在串口1上,可以通过 DT_PARENT 获取父节点:
#define BLUETOOTH_NODE DT_NODELABEL(uart_bluetooth)
#if !DT_NODE_HAS_STATUS(BLUETOOTH_NODE, okay)
#error "Unsupported bluetooth: please check devicetree and retry"
#endif
#define BLUETOOTH_UART_NODE DT_PARENT(BLUETOOTH_NODE )

#define BLUETOOTH_UART_RX_RING_BUFFER_SIZE 512
#define BLUETOOTH_UART_TX_RING_BUFFER_SIZE 512

typedef struct
{
    const struct device *dev;

    uint16_t rx_front;
    uint16_t rx_rear;
    uint8_t rx_ring_buffer[BLUETOOTH_UART_RX_RING_BUFFER_SIZE];
    struct k_sem rx_sem;

    uint16_t tx_front;
    uint16_t tx_rear;
    uint8_t tx_ring_buffer[BLUETOOTH_UART_TX_RING_BUFFER_SIZE];
    struct k_sem tx_sem;
} bluetooth_uart_t;

bluetooth_uart_t s_bluetooth_uart = {.dev = DEVICE_DT_GET(BLUETOOTH_UART_NODE)};
  • 初始化串口
void bluetooth_uart_init(com_inface_t *p)
{
    com_drv_t *obj = (com_drv_t *)p;
    bluetooth_uart_t *uart = (bluetooth_uart_t *)obj->user_data;

    if (obj)
    {
        if (!device_is_ready(uart->dev))
        {
            printk("bluetooth uart not ready\n");
            return;
        }

        k_sem_init(&uart->rx_sem, 0, K_SEM_MAX_LIMIT);
        k_sem_init(&uart->tx_sem, BLUETOOTH_UART_TX_RING_BUFFER_SIZE - 1, K_SEM_MAX_LIMIT);

        uart_irq_callback_user_data_set(uart->dev, bluetooth_uart_isr, uart);
        uart_irq_rx_enable(uart->dev);
    }
}
  • 串口中断回调函数
static int bluetooth_uart_irq_input(bluetooth_uart_t *uart, uint8_t c)
{
    int rear = uart->rx_rear + 1;

    if (rear >= BLUETOOTH_UART_RX_RING_BUFFER_SIZE)
    {
        rear = 0;
    }

    if (rear == uart->rx_front)
    {
        /* input was lost */
        return 1;
    }

    uart->rx_ring_buffer[uart->rx_rear] = c;
    uart->rx_rear = rear;
    k_sem_give(&uart->rx_sem);

    return 1;
}

static void bluetooth_uart_isr(const struct device *dev, void *user_data)
{
    uint8_t c = 0;
    bluetooth_uart_t *uart = user_data;

    uart_irq_update(dev);

    if (uart_irq_rx_ready(dev))
    {
        while (1)
        {
            if (uart_fifo_read(dev, &c, 1) == 0)
            {
                break;
            }
            bluetooth_uart_irq_input(uart, c);
        }
    }

    if (uart_irq_tx_ready(dev))
    {
        if (uart->tx_front == uart->tx_rear)
        {
            uart_irq_tx_disable(dev);
        }
        else
        {
            uart_fifo_fill(dev, &uart->tx_ring_buffer[uart->tx_front++], 1);

            if (uart->tx_front >= BLUETOOTH_UART_RX_RING_BUFFER_SIZE)
            {
                uart->tx_front = 0U;
            }

            k_sem_give(&uart->tx_sem);
        }
    }
}
  • 串口读取函数
static int bluetooth_uart_read_char(bluetooth_uart_t *uart, uint32_t timeout)
{
    int ret = 0;
    uint8_t c = 0;
    unsigned int key = 0;

    ret = k_sem_take(&uart->rx_sem, SYS_TIMEOUT_MS(timeout));

    if (ret < 0)
    {
        return ret;
    }

    key = irq_lock();
    c = uart->rx_ring_buffer[uart->rx_front++];

    if (uart->rx_front >= BLUETOOTH_UART_RX_RING_BUFFER_SIZE)
    {
        uart->rx_front = 0U;
    }

    irq_unlock(key);

    return c;
}

static int bluetooth_uart_read(com_inface_t *p, void *buf, uint32_t length, uint32_t timeout)
{
    uint32_t end_time = k_uptime_get_32() + timeout;
    uint32_t remaining_time = timeout;

    com_drv_t *obj = (com_drv_t *)p;
    bluetooth_uart_t *uart = (bluetooth_uart_t *)obj->user_data;

    int res = 0;
    int out = 0;
    uint8_t *data = buf;

    while (length && (remaining_time <= timeout))
    {
        res = bluetooth_uart_read_char(uart, remaining_time);

        if (res < 0)
        {
            if (out == 0)
            {
                errno = -res;
                return res;
            }

            return out;
        }

        *data++ = (uint8_t)res;
        ++out;
        --length;

        if (timeout != SYS_FOREVER_MS)
        {
            remaining_time = end_time - k_uptime_get_32();
        }
    }

    return out;
}
  • 串口写入函数
static int bluetooth_uart_write_char(bluetooth_uart_t *uart, uint8_t c, uint32_t timeout)
{
    int ret = 0;
    int tx_rear = 0;
    unsigned int key = 0;

    ret = k_sem_take(&uart->tx_sem, SYS_TIMEOUT_MS(timeout));

    if (ret < 0)
    {
        return ret;
    }

    key = irq_lock();
    tx_rear = uart->tx_rear + 1;

    if (tx_rear >= BLUETOOTH_UART_TX_RING_BUFFER_SIZE)
    {
        tx_rear = 0;
    }

    if (tx_rear == uart->tx_front)
    {
        irq_unlock(key);
        return -ENOSPC;
    }

    uart->tx_ring_buffer[uart->tx_rear] = c;
    uart->tx_rear = tx_rear;
    irq_unlock(key);
    uart_irq_tx_enable(uart->dev);

    return 0;
}

static int bluetooth_uart_write(com_inface_t *p, const void *src, uint32_t size, uint32_t timeout)
{
    uint32_t end_time = k_uptime_get_32() + timeout;
    uint32_t remaining_time = timeout;

    com_drv_t *obj = (com_drv_t *)p;
    bluetooth_uart_t *uart = (bluetooth_uart_t *)obj->user_data;

    int res = 0;
    int out = 0;
    const uint8_t *data = src;

    while (size && (remaining_time <= timeout))
    {
        res = bluetooth_uart_write_char(uart, *data++, remaining_time);

        if (res < 0)
        {
            if (out == 0)
            {
                errno = -res;
                return res;
            }

            return out;
        }

        ++out;
        --size;

        if (timeout != SYS_FOREVER_MS)
        {
            remaining_time = end_time - k_uptime_get_32();
        }
    }

    return out;
}
  • 清空接收缓存
static void bluetooth_uart_flush(com_inface_t *p)
{
    unsigned int key = 0;
    com_drv_t *obj = (com_drv_t *)p;
    bluetooth_uart_t *uart = (bluetooth_uart_t *)obj->user_data;

    k_sem_reset(&uart->rx_sem);
    key = irq_lock();
    uart->rx_front = 0;
    uart->rx_rear = 0;
    irq_unlock(key);
}

  • 最后是获取实例的方法,仅有该函数可以在外部访问:
com_drv_t *bluetooth_uart_drv_get(void)
{
    static com_drv_t drv = {
        .name = usart1,
        .init = bluetooth_uart_init,
        .flush = bluetooth_uart_flush,
        .read = bluetooth_uart_read,
        .write = bluetooth_uart_write,
        .user_data = &s_bluetooth_uart};

    return &drv;
}
  • 头文件声明
#pragma once

#include "com_interface.h"

com_drv_t *bluetooth_uart_drv_get(void);

功能演示


void main(void)
{
	com_inface_t *drv = bluetooth_uart_drv_get();
	com_init(drv);

	while (1)
	{
		com_write(drv, "hello world\r\n", strlen("hello world\r\n"), K_TICKS_FOREVER);
		k_msleep(1000);
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/4642.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI遮天传 NLP-词表示

本文重点在第三部分“词嵌入”及对Word2vec的介绍&#xff0c;前面的知识主要用于小白对词表示和一些定义、名称的理解&#xff0c;和对一些方法不足的思考。一、词表示1.1 词表示的定义词表示是一种将自然语言中的词转换为机器可理解含义的过程其中意思&#xff08;meaning&am…

Docker之安装Docker

安装Docker1. Docker 基本组成2. 安装Docker3. 阿里云镜像加速4. 底层原理1. Docker 基本组成 镜像&#xff08;image&#xff09; docker 镜像就好比是一个模板&#xff0c;可以同通过这个模板来创建容器服务&#xff0c;如&#xff1a;tomcat 镜像 > run > tomcat1 容器…

网络技术这十个术语你知道吗?

你好&#xff0c;这里是网络技术联盟站。 网络技术术语是指在计算机网络领域中所使用的专业术语。由于计算机技术的快速发展&#xff0c;网络技术术语也在不断地更新和发展。本文将对网络技术术语进行一些介绍和解释&#xff0c;以帮助读者更好地了解和掌握网络技术。 一、协…

内网Nexus代理yum、epel 源私有仓库 + 内网设备配置(centos)

一、准备 一些常用的镜像开源站 yum: 阿里开源镜像源&#xff1a;http://mirrors.aliyun.com/centos 网易开源镜像站&#xff1a;http://mirrors.163.com/ Centos社区镜像站&#xff1a;http://mirror.centos.org/centos/ 中科大开源镜像站&#xff1a;http://centos.ustc.edu…

Web3中文|World ID与GPT-4同时上线,OpenAI创始人的另一场探险?

这两天GPT-4的到来&#xff0c;再次成为朋友圈及媒体热议的话题。此次升级、更新让大家看到了AI给科技和社会带来的潜在挑战性甚至革命性。在赞叹AI迅速发展的同时&#xff0c;也让人再次聚焦关注其背后拥有超强开发和创新能力的OpenAI团队。 令人刮目相看的是&#xff0c;由A…

JMeter使用教程

作为一名开发工程师&#xff0c;当我们接到需求的时候&#xff0c;一般就是分析需要&#xff0c;确定思路&#xff0c;编码&#xff0c;自测&#xff0c;然后就可以让测试人员去测试了。在自测这一步&#xff0c;作为开发人员&#xff0c;很多时候就是测一下业务流程是否正确&a…

【JAVA程序设计】(C00125)基于Springboot的人事管理系统

基于Springboot的人事管理系统项目简介项目获取开发环境项目技术运行截图项目简介 基于Springboot框架开发的人事管理系统共分为四个角色&#xff1a;系统管理员、财务专员、人事专员、普通用户 管理员角色包含以下功能&#xff1a; 管理员拥有所有功能&#xff1a;绩效考核&a…

华为OD机试题,用 Java 解【叠放书籍】问题 | 含解题说明

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典本篇题目:叠放书籍 题目 书籍的长宽都是…

RabbitMQ中死信队列和延迟队列

目录一、死信队列1.过期时间代码实现2.长度限制代码实现3.测试消息拒收4.死信队列小结二、延迟队列1.代码实现1.1 生产者1.2 生产者一、死信队列 死信队列&#xff0c;英文缩写&#xff1a;DLX 。Dead Letter Exchange&#xff08;死信交换机&#xff09;&#xff0c;当消息成…

Makefile第三课:C语言的编译

目录C语言的编译前言1.Fundamental Compiling2.Comiling C2.1 Preprocessing2.2 Generating Assembly Language2.3 Source File to Object File2.4 Single Source to Executable2.5 Multiple Sources to Executable3.Creating a Static Library4.Creating a Shared Library5.总…

贯穿设计模式第二话--开闭职责原则

&#x1f973;&#x1f973;&#x1f973; 茫茫人海千千万万&#xff0c;感谢这一刻你看到了我的文章&#xff0c;感谢观赏&#xff0c;大家好呀&#xff0c;我是最爱吃鱼罐头&#xff0c;大家可以叫鱼罐头呦~&#x1f973;&#x1f973;&#x1f973; 从今天开始&#xff0c;将…

java基础学习——字符流

1.为什么会出现字符流&#xff1a; 由于字节流 操作中文不是特别的方便&#xff0c;所以java就提供字符流 字符流字节流编码表 用字节流复制文本文件时&#xff0c;文本文件也会有中文&#xff0c;但是没有问题&#xff0c;原因是最终底层操作会自动进行字节拼接成中文&#xf…

摄影入门 | 相机的基本原理

一、获取图像——小孔成像实验 小孔成像实验中&#xff0c;点燃蜡烛&#xff0c;会在小孔另一面的白纸上看到一个倒立的烛焰。 此现象可以用来解释物理学原理&#xff1a;光在同种均匀介质中&#xff0c;在不受引力作用干扰的情况下沿直线传播。 这样&#xff0c;我们就用一种…

从零开始搭建游戏服务器 第一节 创建一个简单的服务器架构

目录引言技术选型正文创建基础架构IDEA创建项目添加Netty监听端口编写客户端进行测试总结引言 由于现在java web太卷了&#xff0c;所以各位同行可以考虑换一个赛道&#xff0c;做游戏还是很开心的。 本篇教程给新人用于学习游戏服务器的基本知识&#xff0c;给新人们一些学习…

伪静态技术

网址和纯静态一样&#xff0c;只是&#xff0c;其内部仍旧需要查询数据库&#xff1a;如果有一个页面&#xff0c;希望这个页面利于seo,但是有不适合使用真静态&#xff0c;比如csdn论坛帖子&#xff0c;可以考虑使用伪静态&#xff0c;即: 形式上是一个静态地址&#xff0c;比…

Chapter7.2:MATLAB在频率法中的应用及频率法稳定性分析

该系列博客主要讲述Matlab软件在自动控制方面的应用&#xff0c;如无自动控制理论基础&#xff0c;请先学习自动控制系列博文&#xff0c;该系列博客不再详细讲解自动控制理论知识。 自动控制理论基础相关链接&#xff1a;https://blog.csdn.net/qq_39032096/category_10287468…

PyTorch 深度学习实战 | DIEN 模拟兴趣演化的序列网络

01、实例&#xff1a;DIEN 模拟兴趣演化的序列网络深度兴趣演化网络(Deep Interest Evolution Network,DIEN)是阿里巴巴团队在2018年推出的另一力作,比DIN 多了一个Evolution,即演化的概念。在DIEN 模型结构上比DIN 复杂许多,但大家丝毫不用担心,我们将DIEN 拆解开来详细地说明…

Intel 处理器 macOS降级到Big Sur

1 创建可引导的 macOS 安装器 将移动硬盘作安装 Mac 操作系统的启动磁盘。 创建可引导安装器需要满足的条件 移动硬盘&#xff08;格式化为 Mac OS 扩展格式&#xff09;&#xff0c;至少有 14GB 可用空间已下载 macOS Big Sur的安装器 2 下载 macOS macOS Big Sur安装器会…

【GPT4】微软 GPT-4 测试报告(1)总体介绍

欢迎关注【youcans的AGI学习笔记】原创作品&#xff0c;火热更新中 微软 GPT-4 测试报告&#xff08;1&#xff09;总体介绍 微软 GPT-4 测试报告&#xff08;2&#xff09;多模态与跨学科能力 微软 GPT-4 测试报告&#xff08;3&#xff09;GPT4 的编程能力 【GPT4】微软 GPT-…

Thingsboard使用gateway网关

简介&#xff1a; 本次是想测试一下thingsboard网关的使用&#xff0c;实现通过网关mqttthingsboardemqx 实现间接设备创建和数据传输 前期准备&#xff1a; thingsboard平台 thingsboard网关 emqx平台 MQTTX工具 详细过程&#xff1a; 1&#xff1a;thingsboard平台搭建 …