rt-thread uart驱动

        uart驱动描述基于GD32F470芯片。

        rt-thread提供了一套I/O设备模型,如果想要使用操作系统的驱动去进行操作,就得将具体芯片的硬件驱动注册到设备驱动框架上。

        关于rt-thread的I/O设备模型相关内容可以参考

rt-thread I/O设备模型-CSDN博客文章浏览阅读554次,点赞21次,收藏5次。事实上即便有操作系统也是可以直接使用裸机操作方式去操作的,但是这样做有几个缺点,一是代码看起来比较不统一,显得很乱,二是软件没有分层,耦合严重,不利于维护,三是裸机操作属于不受操作系统管控的部分,在对硬件资源的占用上,裸机操作可能会与操作系统操作产生冲突导致异常。实际上具体设备的驱动和操作系统的驱动函数是有个对应的,而用来实现这种对应的就是rt_device_register()函数,通过这个函数就可以将种类繁多的驱动注册到设备驱动框架上,之后就可以使用统一的操作函数了。可以看到最终访问设备用的是。https://blog.csdn.net/u011436603/article/details/136492057?spm=1001.2014.3001.5501        本次主要描述如何实现GD32F470的uart设备驱动

        首先我们查看一下rt-thread的官方驱动文件serial.c,这里面有很多关于串口的函数,包括串口设备注册函数,串口设备操作函数,串口中断函数等。这个文件里的函数都是抽象的,并没有具体的硬件操作方法,我们要做的就是给它赋予实际的硬件操作能力。

        来看一下串口设备的结构,包含了通用设备类型,串口操作函数,串口配置以及两个空类型的指针函数。

        操作函数包含配置,控制,发送,接收,还有个dma传输。

        配置包含uart常见的配置参数,如波特率,数据位等。

struct rt_serial_device
{struct rt_device          parent;const struct rt_uart_ops *ops;struct serial_configure   config;void *serial_rx;void *serial_tx;
};struct rt_uart_ops
{rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg);rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg);int (*putc)(struct rt_serial_device *serial, char c);int (*getc)(struct rt_serial_device *serial);rt_size_t (*dma_transmit)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction);
};struct serial_configure
{rt_uint32_t baud_rate;rt_uint32_t data_bits               :4;rt_uint32_t stop_bits               :2;rt_uint32_t parity                  :2;rt_uint32_t bit_order               :1;rt_uint32_t invert                  :1;rt_uint32_t bufsz                   :16;rt_uint32_t reserved                :6;
};

        接下来我们先注册串口驱动,首先定义一个数据结构 gd32_uart,用于具体硬件初始化用,再定义一个串口设备变量。

struct gd32_uart
{             uint32_t uart_periph;           //Todo: 3bitsIRQn_Type irqn;                 //Todo: 7bits    rcu_periph_enum per_clk;        //Todo: 5bitsrcu_periph_enum tx_gpio_clk;    //Todo: 5bitsrcu_periph_enum rx_gpio_clk;    //Todo: 5bitsuint32_t tx_port;               //Todo: 4bitsuint16_t tx_af;                 //Todo: 4bitsuint16_t tx_pin;                //Todo: 4bitsuint32_t rx_port;               //Todo: 4bitsuint16_t rx_af;                 //Todo: 4bitsuint16_t rx_pin;                //Todo: 4bits    
};static struct gd32_uart uarts = 
{USART0,                                 // uart peripheral indexUSART0_IRQn,                            // uart iqrnRCU_USART0, RCU_GPIOA, RCU_GPIOA,       // periph clock, tx gpio clock, rt gpio clockGPIOA, GPIO_AF_7, GPIO_PIN_9,           // tx port, tx alternate, tx pinGPIOA, GPIO_AF_7, GPIO_PIN_10,          // rx port, rx alternate, rx pin}struct rt_serial_device serial0;

        接下来是实现操作系统设备驱动的各个函数,包括configure,control,getc,putc,至于dma_transmit我们暂时没用到,然后完成设备注册。

void gd32_uart_gpio_init(struct gd32_uart *uart)
{/* enable USART clock */rcu_periph_clock_enable(uart->tx_gpio_clk);rcu_periph_clock_enable(uart->rx_gpio_clk);rcu_periph_clock_enable(uart->per_clk);/* connect port to USARTx_Tx */gpio_af_set(uart->tx_port, uart->tx_af, uart->tx_pin);/* connect port to USARTx_Rx */gpio_af_set(uart->rx_port, uart->rx_af, uart->rx_pin);/* configure USART Tx as alternate function push-pull */gpio_mode_set(uart->tx_port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, uart->tx_pin);gpio_output_options_set(uart->tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, uart->tx_pin);/* configure USART Rx as alternate function push-pull */gpio_mode_set(uart->rx_port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, uart->rx_pin);gpio_output_options_set(uart->rx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, uart->rx_pin);NVIC_SetPriority(uart->irqn, 0);NVIC_EnableIRQ(uart->irqn);
}static rt_err_t gd32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{struct gd32_uart *uart;RT_ASSERT(serial != RT_NULL);RT_ASSERT(cfg != RT_NULL);uart =(struct gd32_uart *) serial->parent.user_data;gd32_uart_gpio_init(uart);usart_baudrate_set(uart->uart_periph, cfg->baud_rate);switch (cfg->data_bits){case DATA_BITS_9:usart_word_length_set(uart->uart_periph, USART_WL_9BIT);break;default:usart_word_length_set(uart->uart_periph, USART_WL_8BIT);break;}switch (cfg->stop_bits){case STOP_BITS_2:usart_stop_bit_set(uart->uart_periph, USART_STB_2BIT);break;default:usart_stop_bit_set(uart->uart_periph, USART_STB_1BIT);break;}switch (cfg->parity){case PARITY_ODD:usart_parity_config(uart->uart_periph, USART_PM_ODD);break;case PARITY_EVEN:usart_parity_config(uart->uart_periph, USART_PM_EVEN);break;default:usart_parity_config(uart->uart_periph, USART_PM_NONE);break;}usart_receive_config(uart->uart_periph, USART_RECEIVE_ENABLE);usart_transmit_config(uart->uart_periph, USART_TRANSMIT_ENABLE);usart_enable(uart->uart_periph);return RT_EOK;
}static rt_err_t gd32_control(struct rt_serial_device *serial, int cmd, void *arg)
{struct gd32_uart *uart;RT_ASSERT(serial != RT_NULL);uart =(struct gd32_uart *) serial->parent.user_data;switch (cmd){case RT_DEVICE_CTRL_CLR_INT:/* disable rx irq */NVIC_DisableIRQ(uart->irqn);/* disable interrupt */usart_interrupt_disable(uart->uart_periph, USART_INT_RBNE);break;case RT_DEVICE_CTRL_SET_INT:/* enable rx irq */NVIC_EnableIRQ(uart->irqn);/* enable interrupt */usart_interrupt_enable(uart->uart_periph, USART_INT_RBNE);break;}return RT_EOK;
}static int gd32_putc(struct rt_serial_device *serial, char ch)
{struct gd32_uart *uart;RT_ASSERT(serial != RT_NULL);uart =(struct gd32_uart *) serial->parent.user_data;usart_data_transmit(uart->uart_periph, ch);while((usart_flag_get(uart->uart_periph, USART_FLAG_TC) == RESET));return 1;
}static int gd32_getc(struct rt_serial_device *serial)
{int ch;struct gd32_uart *uart;RT_ASSERT(serial != RT_NULL);uart =(struct gd32_uart *) serial->parent.user_data;ch = -1;if (usart_flag_get(uart->uart_periph, USART_FLAG_RBNE) != RESET)ch = usart_data_receive(uart->uart_periph);return ch;
}static const struct rt_uart_ops gd32_uart_ops =
{gd32_configure,gd32_control,gd32_putc,gd32_getc,
};int gd32_hw_usart_init(void)
{struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;serial0.ops    = &gd32_uart_ops;config.baud_rate=BAUD_RATE_9600;config.data_bits=DATA_BITS_8;config.stop_bits=STOP_BITS_1;config.parity=PARITY_NONE;serial0.config = config;rt_hw_serial_register(&serial0,"uart0",RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,(void *)&uarts);return 0;
}
INIT_BOARD_EXPORT(gd32_hw_usart_init);

        完成上面这些基本就能够使用uart了,但是因为我们配置了串口中断,所以我们还需要去实现串口中断函数。

static void uart_isr(struct rt_serial_device *serial)
{struct gd32_uart *uart;RT_ASSERT(serial != RT_NULL);uart =(struct gd32_uart *) serial->parent.user_data;/* UART in mode Receiver -------------------------------------------------*/if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_RBNE) != RESET) &&(usart_flag_get(uart->uart_periph, USART_FLAG_RBNE) != RESET)){rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);/* Clear RXNE interrupt flag */usart_flag_clear(uart->uart_periph, USART_FLAG_RBNE);}
}void USART0_IRQHandler(void)
{/* enter interrupt */rt_interrupt_enter();uart_isr(&serial0);/* leave interrupt */rt_interrupt_leave();
}

        现在,uart驱动已经注册完毕,剩余的就是具体的应用功能了。这里为了减少篇幅,只列举了单串口,例程里提供了7个串口的驱动,有兴趣可以看看https://download.csdn.net/download/u011436603/88914288?spm=1001.2014.3001.5503

        下面简单介绍一种应用的方式

        首先通过rt_device_find去找到uart设备,使用rt_device_open去打开设备。注意,在rt_device_open打开设备时,如果首次打开,会调用device_init进行初始化,此时才会执行gd32_configure进行串口的初始化。

        之后可以创建两个线程,一个发送一个接收,通过操作系统提供的事件来进行同步。发送线程时刻等待发送事件,一旦接收到发送事件则开始发送数据。接收线程时刻等待接收事件,一旦接收到接收事件则从串口中读数据填入缓存,以备后续处理。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue命令行

书接上回,一直没能将vue-shop-master项目启动,还是停留在命令行,现参考链接如下, https://blog.csdn.net/jieyucx/article/details/127915699 止步不前了,晚上再摸索吧,搞电商去。。。。溜了溜了&#x…

MySQL进阶之(四)InnoDB数据存储结构之行格式

四、InnoDB数据存储结构之行格式 4.1 行格式的语法4.2 COMPACT 行格式4.2.1 记录的额外信息01、变长字段长度列表02、NULL 值列表03、记录头信息 4.2.2 记录的真实数据 4.3 Dynamic 和 Compressed 行格式4.3.1 字段的长度限制4.3.2 行溢出4.3.3 Dynamic 和 Compressed 行格式 4…

【Flutter 】get-cli init报错处理

报错内容 get init 命令跳出,报错内如下 Select which type of project you want to creat Synchronous waiting using dart:cli waitFor Unhandled exceotion . Dart WaitforEvent is deprecated and disabled by default. This feature will be fully removed in Dart 3.4 …

【定岗定编】某度假村酒店客房部定岗定编管理咨询项目纪实

该度假村酒店由于地域广阔,将客服部分为了四个不同区域,这样就导致了在不同的区域员工的接待量不均衡的状况,引起了员工的强烈不满。如何合理地配置客户部人员以及如何合理地鉴定员工的工作量成为该酒店所面临的两大难题。让我们来看看在人力…

vulhub中ThinkPHP5 SQL注入漏洞 敏感信息泄露

漏洞原理 传入的某参数在绑定编译指令的时候又没有安全处理,预编译的时候导致SQL异常报错。然而thinkphp5默认开启debug模式,在漏洞环境下构造错误的SQL语法会泄漏数据库账户和密码 启动后,访问http://your-ip/index.php?ids[]1&ids[]2…

即插即用篇 | YOLOv8 引入 NAM 注意力机制 | 《NAM: Normalization-based Attention Module》

论文名称:《NAM: Normalization-based Attention Module》 论文地址:https://arxiv.org/pdf/2111.12419.pdf 代码地址:https://github.com/Christian-lyc/NAM 文章目录 1 原理2 源代码3 添加方式4 模型 yaml 文件template-backbone.yamltemplate-small.yamltemplate-large…

C++之类型转换

C语言中的类型转换 在C语言中, 如果赋值运算符左右两侧类型不同, 或者形参与实参类型不匹配, 或者返回值类型与 接收返回值类型不一致时, 就需要发生类型转化, C语言中总共有两种形式的类型转换: 隐式类型转换和显式类型转换 1. 隐式类型转化是关联度很强, 意义相近的类型之间…

【CSP试题回顾】201512-2-消除类游戏

CSP-201512-2-消除类游戏 解题思路 输入棋盘大小和颜色: 首先,程序从标准输入读取两个整数n和m,分别代表棋盘的行数和列数。然后,程序读取接下来的n行输入,每行包含m个整数,代表棋盘上每个方格中的棋子颜色。 初始化…

[蓝桥杯 2017 省 A] 油漆面积 Java代码及一些个人理解

[蓝桥杯 2017 省 A] 油漆面积 题目描述 X 星球的一批考古机器人正在一片废墟上考古。 该区域的地面坚硬如石、平整如镜。 管理人员为方便,建立了标准的直角坐标系。 每个机器人都各有特长、身怀绝技。它们感兴趣的内容也不相同。 经过各种测量,每个…

【论文速读】 | AI驱动修复:漏洞自动化修复的未来

本次分享论文为:AI-powered patching: the future of automated vulnerability fixes 基本信息 原文作者:Jan Nowakowski, Jan Keller 作者单位:Google Security Engineering 关键词:AI, 安全性漏洞, 自动化修复, LLM, sanitiz…

Objective-C blocks 概要

1.block的使用 1.1什么是block? Blocks是C语言的扩充功能:带有自动变量(局部变量)的匿名函数。 “带有自动变量”在Blocks中表现为“截取自动变量" “匿名函数”就是“不带名称的函数” 块,封装了函数调用及调用…

全方位碾压chatGPT4的全球最强模型Claude 3发布!速通指南在此!保姆级教学拿脚都能学会!

🎉🎉欢迎光临,终于等到你啦🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏《Spring 狂野之旅:从入门到入魔》 &a…

Android开发岗还不会这些问题,温故而知新

前言 前前后后经历过大项目、小项目,跨平台,小程序,Nodejs服务等等,目前在做的Rom开发,定制各种手机中的奇葩需求,从应用层到Framework层,再到C层,再到驱动,最终到Linux&…

MybatisPlus入门详解

一、MyBatisPlus 简介 1.1 创建新模块 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version></dependency> 由于mp并未被收录到idea的系统内置配置,无法…

Solidity Uniswap V2 Pair中添加流动性

添加流动性的功能的用户入口&#xff0c;UniswapV2在UniswapV2Router中实现&#xff0c;它用来计算新的流动性并发行LP-Token&#xff0c;流动性管理简单地视为LP-Token管理。当你为一个pair增加流动性时&#xff0c;合约会创造LP Token;当你移除流动性时&#xff0c;LP-Token就…

【debug】element-ui时间控件回显后不可编辑且显示为空

问题&#xff1a;使用element-ui的时间控件回显数据&#xff0c;编辑数据没有反应&#xff1a;点时间和“确认”按钮都没反应。 输入框中会显示数据&#xff0c;但提交时的校验显示为空。 <el-form-item label"开始时间" prop"limitStartTime"><…

局部最小值问题

局部最小值问题&#xff1a; 条件&#xff1a;n个数的无序数组 array&#xff0c;相邻两个数一定不相等&#xff0c;找出其中的一个局部最小值。 如果array[0]< array[1] ,返回 array[0];如果array[n-1]<array[n-2]&#xff0c;返回array[n-1];其他的位置需要满足 array[…

xss.haozi.me:0X0D

alert(1) -> 记住要回车一下-->是js的一个注释符但是只能用在最前面前面有一个空格都不行

【LeetCode】升级打怪之路 Day 14:二叉树的遍历

今日题目&#xff1a; 144. 二叉树的前序遍历94. 二叉树的中序遍历145. 二叉树的后序遍历102. 二叉树的层序遍历107. 二叉树的层序遍历 II199. 二叉树的右视图637. 二叉树的层平均值429. N 叉树的层序遍历515. 在每个树行中找最大值116. 填充每个节点的下一个右侧节点指针117. …

【YOLO v5 v7 v8 v9小目标改进】RevCol:解决深度学习信息从低层(输入)传递至高层(输出)的过程中,信息会逐层丢失问题

RevCol&#xff1a;解决深度学习信息从低层&#xff08;输入&#xff09;传递至高层&#xff08;输出&#xff09;的过程中&#xff0c;信息会逐层丢失问题 学习解耦表示可逆列网络&#xff08;RevCol&#xff09;子特征1&#xff1a;多级可逆单元子特征2&#xff1a;可逆列架构…