RTT串口V1版本的使用分析及问题排查指南(一)

2023-05-16

本文由RT-Thread论坛用户123原创发布:https://club.rt-thread.org/ask/article/2894.html

RTT串口V1版本的使用分析及问题排查指南(一)

简述

无论是刚接触 RT-Thread 的新手,还是经验老道的大牛们,他们使用 RT-Thread 的时候,使用最频繁最广泛的外设,想必也非串口设备莫属。

回想大家在移植一个新的BSP或者芯片时,如何验证是否移植成功呢?是的,msh控制台窗口走一波 RTT 的 logo 信息,输出成功了就基本代表移植成功了。如下所示:

 \ | /
- RT -     Thread Operating System
 / | \     4.0.4 build Dec  32 2021
 2006 - 2021 Copyright by rt-thread team
msh >

例如 finsh 组件,以命令行的方式实现人机交互的功能,在项目开发调试中有着举足轻重的作用,也是开发者们使用最为频繁的组件。

又例如 ULOG组件,AT组件,ymodem组件,RT_Link组件等,其底层数据流都有串口的踪迹。因此,作为使用最频繁,覆盖面最广泛的串口设备,如果把它搞懂,那将会在你的项目开发中如虎添翼,或对嵌入式系统也会有更深刻的理解。

既然串口设备如此重要,受众人群又如此之多,使用范围如此之广,那么有必要去理一理串口框架,汇总一下问题所在,为广大开发者们指一下解决问题的方向。这也是这篇文章的主要工作。

本文会先结合STM32为平台,以串口V1版本做分析说明 (第一部分),并总结遇到串口方面的问题该如何解决的方法(第二部分)。

(在此需要解释一下,串口V1版本 这个名字非官方冠名,是本人为了区分串口V2版本 而临时起的名字,当然后续会有串口V2版本的介绍说明,马不停蹄更新中)

由于串口V1版本已经历经多年的开发与迭代,也被多数开发者整理成文,广为流传,本文若重新对其做细致的分析显然是在浪费各位看官的宝贵时间。因此,本文旨在总结串口使用过程中遇到的问题,弱化分析串口的执行流程,如需详细的串口流程分析,可移步文档中心串口章节,或者自行上网搜索,相信你一定能找到合适的答案。那么废话不多说,开整。

串口设备使用说明

串口流程分析分为两部分,一部分是串口驱动,另一部分是串口框架,用户(应用层)使用串口时,是按照下图的模型进行操作的:

image.png

首先需要使用 Device 框架(源码位置在 src/device.c 中),什么是Device 框架,比如用到的 rt_device_open/close/read/write/control() 等API操作接口,就是使用的 Device 框架的接口。本文中不做深入探讨,了解即可。

其次是 UART 设备驱动框架 (源码位置在 components\drivers\serial\serial.c),串口设备驱动框架实现了Device框架的操作方法的接口rt_serial_open/close/read/write/control()。举个例子,例如Device框架的rt_device_open() 接口是打开一个设备对象,而对应到串口框架上,就是对接到了 rt_serial_open()

然后是串口设备驱动(源码位置在 bsp/xxx/drivers/drv_usart.c),串口设备驱动负责实例化串口设备 。这一层调用了 rt_hw_serial_register() 函数注册串口设备到操作系统中,也是与串口硬件直接打交道的媒介,这一层将会看到串口硬件的配置、读写寄存器、中断的操作等。

下面这张图将介绍串口设备的使用序列:

image.png

串口各个模式的流程分析

串口框架目前适配了三种硬件工作模式,即串口轮询(发送/接收)、串口中断(发送/接收)、串口DMA(发送/接收)。下面分别对三种模式进行介绍:

一:轮询模式

轮询模式即调用串口 接收/发送 的 API 后将一直占用CPU资源直到数据收发完成才返回,使用时需要用户主动调用 接收/发送 的API接口才会执行相应的操作。

轮询接收

应用程序调用 rt_device_read() 接收数据,轮询接收模式下会调用到底层串口驱动提供的 getc 接口,每次接收一个字节,如果接收不到数据将一直占用CPU资源。

轮询发送

应用程序调用 rt_device_write() 发送数据,轮询发送模式下会最终会调用到底层串口驱动提供的 putc 接口,每次发送一个字节,循环发送直到待发送的数据发送完成。

轮询接收和发送调用关系如下图所示:

image.png

二:中断模式

中断模式下收发数据时,将数据的收发过程放在中断中进行,不再持续占用CPU资源,应用程序只用负责将数据写入串口数据寄存器,然后线程就会让出资源,空出了程序等待串口硬件收发数据的时间。注意一点:中断接收和发送时,每次在中断中操作的还是单个字节。

中断接收

串口硬件接收到一个字节的数据后会触发中断并调用串口驱动框架的 rt_hw_serial_isr() 函数,此函数会将这一字节数据写入环形缓冲区,用户设置的回调函数也会被调用。应用程序读取数据实际是从环形缓冲区读取。

中断接收调用关系如下图所示:

image.png

中断发送

串口框架负责调用底层 putc 接口向串口寄存器写入待发送的数据,然后等待此数据发送完成的信号,此时当前线程会被挂起。上一个数据发送完成后会调用串口驱动框架的 rt_hw_serial_isr() 函数,此函数会发送完成信号唤醒发送数据线程,并重置完成信号状态为未完成。线程运行后会向串口寄存器写入下一个数据,然后等待完成信号,重复上一个流程,直到缓冲区数据发送完成。

该过程与中断接收流程很相像,再次不再贴图赘叙。

三:DMA模式

DMA模式下收发数据与中断模式很相像,可以粗略的认为,两种模式唯一不同的就是,中断模式每次收发数据为单字节,而DMA模式则是多个字节进行收发的。

DMA接收

使用 DMA 接收模式时,首先应用程序打开串口设备会指定打开标志为 RT_DEVICE_FLAG_DMA_RX,此时串口驱动框架会创建环形缓冲区并调用串口驱动层 control 接口使能 DMA 接收完成中断。

DMA接收调用关系如下图所示:

image.png

这里再啰嗦一句,在DMA中断处理流程中,有三种DMA接收中断,分别是DMA空闲中断(IDLE)、DMA半满中断(HFIT)和 DMA满中断(TCIT),这三个中断相辅相成,最后统一交由串口框架中断处理函数 rt_hw_serial_isr(RT_SERIAL_EVENT_RX_DMA_DONE)中做处理。其中DMA空闲中断是在uart_isr中触发的,另外两个是在DMA接收回调中触发的,这两个接收回调是在DMA接收使能启动的时候,由HAL库注册的,用户无需关心这两个DMA接收回调的注册逻辑,只需知道,如果用户不想使用这两个DMA接收回调的时候,只要把函数里面的执行代码注释掉即可。类似下图这样 :

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    struct stm32_uart *uart;
    RT_ASSERT(huart != NULL);
    // uart = (struct stm32_uart *)huart;
    // dma_isr(&uart->serial);
}

void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
    struct stm32_uart *uart;
    RT_ASSERT(huart != NULL);
    // uart = (struct stm32_uart *)huart;
    // dma_isr(&uart->serial);
}

(至于为什么会有用户无需使用该回调函数的应用场景,这里先按下不表,后边会具体详细分析,而且这部分会很重要,该机制在串口V2上照样使用)

DMA发送

应用程序发送数据流程如下图所示,应用程序调用 rt_device_write() 发送数据,最终待发送数据的地址和大小会被放入数据队列,如果此时 DMA 空闲,就会开始发送数据。当 DMA 发送完成触发中断时,rt_hw_serial_isr() 函数会判断数据队列是否有待传输的数据并开始下次 DMA 传输,用户设置的回调函数也会被调用。

image.png

由上图我们可以看出,在使用DMA发送时,串口框架并未使用环形缓冲区,然而我们又知道,DMA发送时,肯定是需要缓冲区来存放数据的,那么DMA发送时候的数据块,存放在哪里呢?这里就需要注意了,DMA发送时候,数据缓冲区是由用户应用层定义的,在传给串口框架的时候,是将应用层定义的数据缓冲区的指针传递过来。如果在发送过程中,该缓冲区的内容被意外修改了,那么将会导致DMA发送的数据出现错误。我们可以再结合下面的图继续说明:

image.png

串口相关问题解析

篇幅有限,本节内容见 RTT串口V1版本的使用分析及问题排查指南(二)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RTT串口V1版本的使用分析及问题排查指南(一) 的相关文章

  • 制作一个舵机云台【内附资料下载链接】

    1 运动功能说明 舵机云台下方的舵机可以提供一个左右摆动的动作 xff0c 同时上方横置的关节模组可以提供一个上下摆动的动作 在这两部分的配合下 xff0c 云台的执行端端 xff08 即 xff1a 关节模组的U型支架 xff09 可以灵
  • UART控制器LIN功能模式(NUC029LAN阅读笔记)

    UART控制器LIN功能模式 xff08 NUC029LAN阅读笔记 xff09 LIN总线帧格式字节域格式 xff08 LIN标准 xff09 帧头 xff08 Header xff09 同步间隔域 xff08 Break Field x
  • 关于新唐NUC029LAN库函数操作无法打开定时器2和定时器3的问题(库函数中的bug)

    结论 xff1a 问题 xff1a 使用NUC029LAN库函数中的设备时钟使能函数时 xff0c 无法正常打开定时器TMR2和TMR3 原因 xff1a clk h中 xff0c 定时器2模块 xff08 TMR2 MODULE xff0
  • STC12系列单片机的1T模式和12T模式

    STC12系列单片机的1T模式和12T模式 总结STC12系列单片机的1T模式和12T模式基本原理以定时器为例 总结 1T 模式 不分频 1个系统基本时钟 xff0c 执行一个动作 xff1b 12T模式 12分频 12个系统基本时钟 xf
  • 函数指针及其定义和用法,C语言函数指针详解

    声明 xff1a 转载 函数指针及其定义和用法 xff0c C语言函数指针详解 版权归原作者所有 xff0c 若有侵权请联系删除 函数指针及其定义和用法 xff0c C语言函数指针详解 函数指针大家了解一下就行了 xff0c 用得不多 xf
  • Python md5、sha256、sha1、加密方法

    需要使用 hashlib 这个库 xff0c python 自带的 xff0c 可以直接用 要加密的数据需要先使用 encode 进行编码 import hashlib data 61 34 你好 34 要进行加密的数据 data sha
  • 通信方式、通信接口、通信总线、通信协议的关系

    通信方式通信接口通信总线通信协议接口 总线 协议之间的关系 通信方式 通信方式是指通信双方之间的工作方式或信号传输方式 终端与其他设备 xff08 例如其他终端 计算机和外部设备 xff09 通过数据传输进行通信 xff0c 根据数据的传输
  • 通信方式的分类(串行通信和并行通信)

    通信方式的分类串行通信和并行通信串行通信同步通信和异步通信单工 半双工和双工 并行通信 通信方式的分类 通信方式是指通信双方之间的工作方式或信号传输方式 终端与其他设备 xff08 例如其他终端 计算机和外部设备 xff09 通过数据传输进
  • 为什么需要使用栈结构?

    在以往学习高级语言时 xff0c 提到栈 xff0c 下意识都会反映上来FILO xff0c 它是暂存数据的一种数据结构 xff0c 但是为什么会用到栈 xff1f 却一直讳莫如深 xff0c 这是高级语言不会涉及到的底层的实现 xff0c
  • C语言中define的用法

    define顾名思义 xff0c 就是下定义 xff0c 那么在C中它也发挥着下定义的作用 1 提前定义变量 include lt stdio h gt define N 100 int main int a 61 10 printf 34
  • C++编译时出现未定义的引用问题解决

    未定义的引用 xff08 undefined reference xff09 出现的原因是生成可执行文件所在的cpp包含头文件时 xff0c 头文件中声明的函数定义未被可执行文件所识别 xff0c 解决办法如下 xff1a add libr
  • 【仿真】手把手学会基于Simulink下的模糊控制系统(上)

    目录 前言 xff1a 什么是模糊控制 1 模糊控制器MATLAB教程 xff08 初级 xff09 1 1 模糊PD控制器 前言 xff1a 什么是模糊控制 控制专业并且写过论文的同学想必一定听说过模糊控制 xff0c 但多数人对于什么是
  • 【STM32CubeMX】STM32H7-RTOS-SPI-W5500

    工程源码下载 xff1a 基于裸机和Freertos的W5500网络通信工程 目录 1 移植W5500步骤 2 Cobemx配置步骤 2 1 时钟配置Clock Configuration 2 2 Trace and Debug配置 2 3
  • 【PADS】PADS覆铜技巧

    目录 重要快捷键 基础设置 层设置 电源层分割处理 给自己喜欢的网络上个颜色 TOP层覆铜 验证设计是否有问题 PADS开窗 PADS为分割层模拟数字地覆网格铜 PADS 快捷键 Ctrl 43 鼠标滚轮失灵 Ctrl 43 鼠标滚轮造成P
  • 【Cadence16.6】安装教程

    初识安装包文件 我们cadence16 6的安装包是这样的 xff0c 详细请去https www fanyedu com index mulitcourse video html id 61 1008 1008观看 首先我们打开这个文件夹
  • 【硬件】芯片温度/功耗计算

    本博客参考 xff1a 一纸沙漏的博客 芯片的四个温度 内核温度 封装表面温度 空气周边温度以及PCB板温度 TJ xff08 Die Junction Temp xff09 芯片的硅核温度 xff0c 就是芯片内部核心的温度 xff0c
  • Python unicode 字符串 转 list

    unicode 字符串 转 list unicodeList 61 u 39 100 100 100 100 100 100 39 1 方法一 list 61 eval unicodeList 2 方法二 int value for val
  • 【硬件】AD623单电源供电差分放大

    1 前言 检测电机电流运用检流电阻的方法在往期已经介绍过 详情请见 xff1a 检流电阻计算电流 2 需求分析 2 1 电机流过电流 已知电机的峰值堵转电流为4 6A xff0c 连续堵转电流为3 2A xff0c 以上信息可以得知需要采样
  • 【电路】PT1000/PT100温度采集电路

    目录 原理图下载链接 xff1a https download csdn net download Roger 717 33823983https download csdn net download Roger 717 33823983h
  • 【QT】手把手制作一个QT网络调试助手(准备阶段)

    目录 1 新建一个工程 2 mainwindow ui设计 2 1 对窗口主体进行栅格化布局 2 2 添加网络通信配置GroupBox 2 2 1 填充内容 2 2 2 栅格布局GroupBox 2 3 总结 3 Pro程序配置 4 头文件

随机推荐

  • 【PR】PR视频剪辑实用技巧

    1 两个视频叠加 1 首先 xff0c 找到要导入的视频所在文件夹 xff0c 将视频拖动到项目面板中 按住Ctrl拖动视频再复制两个视频 2 将素材视频分别拖入到序列的 视频轨道1 2 3 3 点击选中轨道1上的视频 xff0c 在源面板
  • 【Project】项目管理软件学习笔记

    一 前言 使用Project制定项目计划步骤大致如下 xff1a 以Project2013为例 xff0c 按照上图步骤指定项目计划 二 实施 2 1 创建空白项目 点击文件 新建 空白项目 xff0c 即完成了空白项目的创建 xff0c
  • 【硬件】P沟道和N沟道MOS管开关电路设计

    场效应管做的开关电路一般分为两种 xff0c 一种是N沟道 xff0c 另一种是P沟道 xff0c 如果电路设计中要应用到高端驱动 的话 xff0c 可以采用PMOS来导通 P沟道MOS管开关电路 PMOS的特性 xff0c Vgs小于一定
  • 多线程基础之七:多线程遇上printf的“延迟写”策略

    0 运行库提供的IO读写函数采用 延迟写 策略的原因 编程时经常会用到printf 函数 xff0c 但是由于printf 函数涉及到和显示器或磁盘等外设进行交互 xff0c 所以操作涉及到从 用户态 gt 内核态 gt 返回用户态 的一系
  • VC和VS区别

    S是Visual Studio xff0c 它是微软提供的一个工具集 xff0c 由各种各样的工具组成 VS可以支持C C 43 43 VB JAVA C 编程 然了一次只能支持一种编程方式 在VS安装完成 xff0c 第一次运行的时候会让
  • 【potplayer安装及设置LAV Splitter】

    potplayer安装及设置LAV Splitter 下载及安装Lav Splitter解码器配置Lav Splitter解码器 potplayer是一款windows平台上一款轻量功能强大的播放器 xff0c 它界面简洁 xff0c 功能
  • 关于头文件的相互包含

    编程过程中 xff0c 经常会碰到头文件的相互包含 xff0c 如果处理不慎 xff0c 就会报错 比如在头文件A h中有如下代码 xff08 代码中的B Handle是在头文件B h中定义的 xff09 xff1a span class
  • Python list中去重的多种方法

    去重之后顺序会改变 set去重 列表去重会让列表改变原来的顺序 l1 61 1 4 4 2 3 4 5 6 1 l2 61 list set l1 print l2 1 2 3 4 5 6 但是 xff0c 可以通过列表中索引 xff08
  • TI学习笔记之“振动补偿算法”

    一些应用中 xff0c 负载和机械角度有关 xff0c 比如空调压缩机 典型压缩机应用的负载曲线如下图所示 xff0c 不难发现 xff0c 在一个机械周期内 xff0c 负载和机械角度存在一定的关系 xff0c 这种情况在转子式压缩机中尤
  • “compilerPath“的问题

    在c cpp properties josn文件中 xff0c complierPath的问题解决如下 如果正在编译c 43 43 文件 xff0c 先在终端输入which g 43 43 我的弹出了 usr bin g 43 43 把这个
  • Digest Authentication Response 如何计算

    Session Initiation Protocol NOTIFY Request Line NOTIFY sip 192 168 125 130 5060 SIP 2 0 Method NOTIFY Request URI sip 19
  • ROS-Melodic 编译Moveit全过程记录和错误解决方案

    ROS Melodic 编译Moveit全过程记录和错误解决方案 在Ros Melodic版本下 xff0c 直接运行sudo apt get install ros melodic moveit会出现以下错误 xff1a 下列软件包有未满
  • Jetson TX2在ROS下使用Realsense D435i跑rtabmap、octomap、VINS-Mono和ORB-SLAM2

    使用环境 xff1a Ubuntu 16 04 JetPack 3 3 xff0c ROS Kinetic硬件设备 xff1a 英伟达Jetson TX2 xff0c 英特尔Realsense D435i 安装Realsense相关的相机驱
  • C++实现流式socket聊天程序

    目录 协议设计 消息的类型 消息的语法 消息的语义 消息的处理 发送消息 接收消息 程序设计 模块的划分和功能 Client客户端 Server服务器 模块流程图 程序实现 辅助代码 client cpp server cpp 程序测试 本
  • STM32 串口 FIFO

    使用FIFO实现串口数据的收发功能 FIFO的相关实现参照链接 xff1a CSDN https mp csdn net mp blog creation editor 120448361 1 Cubemx串口配置 使用Cubmx对串口进行
  • C Primer Plus

    C Primer Plus作为一本被人推崇备至的c入门经典 xff0c C primer plus绝非浪得虚名 应该算得上C教材里最好的入门书了 在知识广度上 xff0c 很少有书能匹及 它能为你系统学习c提供一个良好的平台 作者对c的见解
  • Python 如何处理大文件

    Python作为一门程序设计语言 xff0c 在易读 易维护方面有独特优势 xff0c 越来越多的人使用 Python 进行数据分析和处理 xff0c 而 Pandas 正是为了解决数据分析任务而创建的 xff0c 其包含大量能便捷处理数据
  • C++构造DHCP Discovery报文并使用socket发送

    DHCP由BOOTP协议发展而来 xff0c 而后者基于UDP IP协议 xff0c 这使得使用socket发送DHCP报文成为可能 本文示例构造了DHCP Discovery报文并调用socket接口发送 xff0c 值得注意的是 xff
  • pycharm 常用快捷键整理

    pycharm常用快捷键 1 编辑 xff08 Editing xff09 Ctrl 43 Space 基本的代码完成 xff08 类 方法 属性 xff09 Ctrl 43 Alt 43 Space 快速导入任意类 Ctrl 43 Shi
  • RTT串口V1版本的使用分析及问题排查指南(一)

    本文由RT Thread论坛用户123原创发布 xff1a https club rt thread org ask article 2894 html RTT串口V1版本的使用分析及问题排查指南 一 简述 无论是刚接触 RT Thread