嵌入式 - UART使用进阶

2023-11-07

UART – Advanced Features

概要 / Overview

最简单直接的使用UART接口的方式,是在轮循操作中来设置和处理UART接口。 轮询式UART的问题是轮询方式本身就是低效率的。 如果我们的UART被配置为115200的波特率和8N1,那么传输一个字符需要多长时间?  每个字节的数据需要10个符号来发送。 这意味着我们每秒钟可以传输11520个字符。 这意味着1个字符大约需要86微秒的时间来发送。

86微秒可能看起来并不长,但如果我们的微处理器以50Mhz的速度运行,这相当于每个字符发送需要4341个时钟周期。 这是一个相当多的时钟周期,为了发送一串字符中的下一个字符而要一直等待。

我们将研究一些硬件和软件技术,以减少我们等待数据传输或接收的时间。

中断 / Interrupts

减少等待UART的时钟周期数的最明显方法之一是让UART产生中断。 UART中断允许主应用程序在UART不活动时执行其他任务。 UART通常产生接收和发送中断。 当有新数据到达时,UART会产生一个接收中断。 对于接收中断,应用程序和ISR之间的交互是非常直接的。  中断服务例程将新数据放入SRAM,提醒主应用程序,并清除中断。 由于中断只在数据被接收时发生,处理器可以自由地进行其他操作。

发送中断有一点不同。  一些微控制器的UART在发送缓冲区为空时产生一个中断。 这个中断是为了指示应用程序可以通过UART发送下一个字节。  我们想要避免的是这样的情况,即应用程序没有传输数据,结果UART不断产生发送数据为空的中断。这种情况会使应用程序处于空转状态,因为UART处理程序会被不断执行。 如果你使用的微控制器在Tx硬件FIFO中没有数据时不断产生Tx空中断,你可以使用以下过程来消除主应用程序的空转:

1,当UART的循环发送缓冲区为空时,UART处理程序会禁用它自己的发送空中断。 这可以防止中断的连续产生。

2,当应用程序希望发送数据时,它将数据添加到UART FIFO中,然后重新启用发送数据为空的中断。

 管道 FIFOs

在某些情况下,仅靠中断是无法减少浪费的时钟周期的。 一个例子是打印出一长串的字符。 我们可以立即发送字符串中的第一个字符到UART暂存寄存器,但我们仍然要依次发送字符串中的一个个字符,发完一个等待发送下一个。 中断可以帮助我们确定何时可以发送下一个字符,但它们并不能消除这样一个事实,即在主程序传送完所有字符之前,应用程序不能继续往前跑。

一个可以减少等待发送(或接收)字符的时间的机制是UART FIFO。 具有硬件FIFO的UART允许应用程序向UART写入一个以上的字符。 UART将写入的字符放入队列,然后一个个发送,直到FIFO为空。 我们不再需要等待单个字符的传输。 我们可以向UART发送一个字符块并立即返回。

FIFO的结果是减少中断。 只有在传输/接收了一个数据块后才会出现传输和接收中断。 每个中断都会导致上下文切换和ISR的执行。 减少中断的数量可以减少对UART中断做出反应所占用的时钟周期。

在使用FIFO时,我们需要考虑的一个特殊情况是当UART产生一个接收中断时。 带有FIFO的UART只有在接收FIFO满(或接近满)时才可能产生中断。 那么,当收到一个单字节的数据,而FIFO被配置为只在FIFO满时产生中断时,会发生什么? 我们不希望发生的是数据被卡在接收FIFO中,因为FIFO没有满。 为了避免这种情况,通常有一个接收超时中断。 当数据在接收FIFO中,但没有足够的数据来触发FIFO满的中断时,这个中断会被定期触发。

Circular Buffers( Ring buffer) 环形缓冲区

硬件FIFO也不能解决我们所有的等待问题。 硬件FIFO的大小是固定的。 如果打印的字符串超过了硬件FIFO的容量,应用程序仍将忙于等待。 由于我们不能动态地增加硬件FIFO的大小,我们将在内存中创建一个软件的数据结构来缓冲运往UART的字符。 最常用的软件结构是一个循环缓冲器。

那么,为什么我们要使用循环缓冲器而不是链表呢? 链表让我们可以自由地缓冲字符,直到SRAM用完。  我们不使用链表的原因是内存利用率。 对于存储在链接列表中的每一个字节,我们还必须分配一个下一个指针,这需要消耗4个字节。  这大概是在一个链接列表中存储字符的80%的内存开销。 由于我们的微处理器(microprocessor)中只有几KB的SRAM,这不是一个可以接受的解决方案。

另一方面,循环缓冲器的开销很小。 循环缓冲区必须存储一些关于在哪里插入下一个字符的信息,但总的来说,循环缓冲区只是一个数组。 循环缓冲区的缺点是,我们不能轻易地动态增加缓冲区的大小。 如果向循环缓冲区添加数据的速度大于从循环缓冲区删除数据的速度,数据就会被覆盖并丢失。

Producer Consumer Model 生产消费者模型

我们的UART实现将包括硬件FIFO、软件循环缓冲器、中断处理程序和主应用程序。 我们将使用生产者-消费者模型来确定何时以及如何在应用程序和中断服务程序之间进行数据通信。 发送和接收操作都需要各自的循环缓冲器,并独立检查。

  • Receive 接收

当接收数据时,UART中断服务例程将作为生产者,将字符插入到接收循环缓冲器中。 当接收或接收超时中断被激活时,ISR将从硬件FIFO中移除数据,直到硬件FIFO为空。 每个数据条目都被放入接收循环缓冲区。 当硬件FIFO为空时,ISR将清除接收中断并返回。

主应用程序充当接收FIFO的消费者。 该应用程序不直接从UART抓取数据。循环缓冲器不为空时,应用程序处理接收循环缓冲器的数据,然后删除里面的数据条目。 如果循环缓冲器中没有数据,应用程序可以选择等待(阻塞)直到数据到达,或继续进行其他操作。

我们必须考虑的一个设计问题是,当接收循环缓冲区满了,发生接收中断的情况。 当接收数据的速度超过主程序的消耗速度时,就会出现这种情况。 这种情况总是会导致数据丢失。 问题是,哪些数据会被丢弃? 最老的数据还是最新的数据? 根据我的经验,最古老的数据会被丢弃,但这个问题没有正确的答案。 在这种情况下,我们唯一真正的解决方案是实施一种流量控制(flow control)。

Application Receive Routine Flow Diagram 应用程序接收数据的流程图

ISR Receive Flow Diagram 接收中断流程图

  • Transmit 发送

当发送数据时,应用程序通过将字符插入发送循环缓冲器来提供数据。 当一个发送数据为空的中断发生时,UART ISR作为消费者,从发送循环缓冲区中取得然后删除数据。

当使用循环缓冲器发送数据时,当循环缓冲器满了会发生什么? 我们可以覆盖最旧的数据,但在大多数情况下,你应该持续等待,直到循环缓冲区不再满。 持续等待并不是最佳选择,但总比丢失数据要好。

我们要解决的另一个情况是,如果发送数据为空的中断被禁用,数据如何被发送。 如上所述,在应用程序没有数据要发送时,发送数据为空的中断被禁用。 这避免了UART ISR的不断调用。 如果我们的应用程序将数据添加到发送循环缓冲区,并且发送数据为空的中断被禁用,那么发送数据为空的中断就不会被触发,循环缓冲区中的数据也不会被UART消耗。

当我们发送数据时,应用程序将检查循环缓冲区。 如果循环缓冲区是空的,而且硬件FIFO没有满,我们将把数据直接放入硬件FIFO,并重新启用发送空中断。 其结果是UART传输硬件FIFO中的字符,当硬件FIFO为空时将产生一个新的传输中断。 然后UART ISR将检查发送循环缓冲器。 如果循环缓冲区内有数据,ISR会消耗字符,直到硬件FIFO满或循环缓冲区空。 UART将继续发送字符并产生中断,直到UART ISR检测到发送循环缓冲区为空,此时UART ISR将禁用发送空中断。

Application Transmit Routine Flow Diagram 应用程序发送数据的流程图

ISR Transmit Routine Flow Diagram 发送数据中断处理程序流程图

Race condition 竞争条件

当应用程序从循环缓冲区移除(或添加)数据时,我们必须确保修改循环缓冲区的操作是原子性的(atomic)。 原子操作的意思是,所有涉及到修改循环缓冲区的操作不能被打断。  如果我们不确保这些操作是原子的,那么就会出现一个race condition,当主程序试图修改循环缓冲区的内容时,发生UART中断,也去修改循环缓冲区内容。

由于一个指令序列只能被更高优先级的中断打断,我们不需要担心UART ISR会被应用程序打断。 另一方面,我们确实需要防止应用程序在向循环缓冲区添加或移除数据时被中断。 我们可以使用某种形式的信号semaphore,但最简单的方法是让主程序在修改循环缓冲区之前暂时禁用中断,然后在修改数据后重新启用中断。

参考:

1,UART使用进阶

UART – Advanced Features – ECE353: Introduction to Microprocessor Systems – UW–Madison

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

嵌入式 - UART使用进阶 的相关文章

随机推荐

  • 将一个项目发布到Tomcat上并进行运行

    1 下载任意版本的Tomcat 我这里是9的版本 应该是当前我认为比较好用的一个版本了 有需要的话可以到公众号自取 微信公众号搜索 是短短吖 后台回复 Tomcat 即可 2 在webapp下部署一个项目Test 名字自选 英文即可 新建项
  • Python爬虫入门3:使用google浏览器获取网站访问的http信息

    前往老猿Python博客 https blog csdn net LaoYuanPython 一 开启开发者工具 为了简单处理 本次介绍的内容是基于网站已经登录的情况下去获取网页访问的http信息 首先需要使用谷歌浏览器登录指定网站 并访问
  • 分治法时间复杂度求解:主定理、代换法和递归树

    分治策略 分解 将原问题划分成形式相同的子问题 规模可以不等 对半或2 3对1 3的划分 解决 对于子问题的解决 很明显 采用的是递归求解的方式 如果子问题足够小了 就停止递归 直接求解 合并 将子问题的解合并成原问题的解 这里引出了一个如
  • error: DIV usage mismatch between xx and output

    使用NDK编译代码的时候 常常需要导入预编译库 然而使用预编译库的时候报错了 因为库文件是android源码编译出来或者是其他NDK版本产生的 库版本存在了不兼容的情况 这里明显看出DIV 函数不兼容 home u android ndk
  • 【ESP-Matter】matter协议学习笔记--以乐鑫方案为例

    matter协议学习笔记 以乐鑫方案为例 0 写在前边的话 1 matter 协议基本概念 2 设备间的本地自动化交互 2 1 同步控制的实例 2 2 异步通知 订阅 报告 3 桥接设备 4 thread 边界路由器 5 专业名词 0 写在
  • 小目标检测 改进 拆分拼接

    小目标Trick 论文链接 https paperswithcode com paper slicing aided hyper inference and fine tuning 代码链接 https github com obss sa
  • 内网IP使用Https小记

    本文章记录使用Nginx 给内网IP地址提供Https协议功能 1 使用openssl生成自签证书 2 将证书配置在Nginx中 3 使用443端口 出现的一些问题 1 Chrome浏览器 会提示不安全 可以忽略 或者本地浏览器添加证书信任
  • cout保留两位小数

    cout保留两位小数 include
  • 简单方便的 JavaScript 逆向辅助模拟方法

    这是 进击的Coder 的第 419 篇技术分享 作者 崔庆才 来源 崔庆才丨静觅 阅读本文大概需要 3 分钟 在 JavaScript 逆向过程中 我们可能找到了一些入口 但是深入追踪下去 就发现这个过程过于复杂 调用层级越来越深 最终很
  • Obsidian 编译第三方插件

    起因 obsidian spaced repetition 是Obsidian 间隔重复插件 它可以帮助你定期复习自建的知识卡片 但功能上不是很全面 碰巧看到 Felix Luo 维护的obsidian spaced repetition插
  • 一分钟教你看懂蓝屏代码,轻松解决电脑蓝屏问题

    微软为了我们电脑中的资料安全可以说煞费苦心设计了很多有效的防护机制 其中蓝屏就是一个很好的给保护机制 接下来小编就提供一些经常出现的电脑蓝屏代码给大家 电脑蓝屏问题可以说只要使用过电脑朋友都遇到过 导致电脑蓝屏的原因有很多种 所有蓝屏代码也
  • 基于SM2密码算法的环签名方案的研究与设计

    摘要 环签名算法种类很多 大多数算法设计基于双线性对或大素数难分解 在安全性和运算速度方面有待提高 与基于椭圆曲线离散对数相比 双线性对的优势并不明显 因为它无法运用一样长度的密钥提供同样的安全性能 为了能够提升方案的安全性以及能够保证签名
  • JDK源码系列 & JAVA语言数据类型Byte

    目录 类的继承结构图 类的Diagram图 类 类的注释 源码分析 全局变量 静态内部类 构造方法 静态方法 parseByte 静态方法 valueOf 静态方法 toString 静态方法 hashCode 静态方法 decode 静态
  • 简述osi参考模型各层主要功能_OSI与TCP/IP简述

    OSI与TCP IP 二者区别 OSI参考模型定义计算机通信每层的功能 不是协议 TCP IP协议是具体的协议 实现了OSI参考模型规定的功能 参考下图 OSI参考模型每层功能 应用层 根据互联网中需要通信的应用程序的功能 定义客户端和服务
  • Android 显示提示框

    本文档为个人博客文档系统的备份版本 作者 小游 作者博客 点击访问 代码如下 Toast makeText context things happened Toast LENGTH SHORT show
  • go 命名与包;关于 ++/--;接收键盘输入/终端输入;switch;for 循环;函数;init 函数;匿名函数;闭包;defer;时间日期;内置函数;defer+recover 机制处理错误

    文章目录 命名与包 关于 接收键盘输入 终端输入 switch for 循环 函数 init 函数 匿名函数 闭包 defer 时间日期 内置函数 defer recover 机制处理错误 数组 代码 输出 命名与包 关于 接收键盘输入 终
  • drawio界面自定义配置

    1 适用的 drawio 版本 单机版 drawio 带有配置选项的单机版本 2 配置使用方法 点击配置 将json代码复制到弹窗中 点击应用即可 如果代码有错误 将无法应用 3 相关json代码 官方json配置参考 https www
  • Internet Download Manager2023最好用的HTTP下载神器

    Internet Download Manager 介绍2023最佳下载利器 Internet Download Manager 简称IDM 是一款Windows 平台功能强大的多线程下载工具 国外非常受欢迎 支持断点续传 支持嗅探视频音频
  • 一个 Go 开发的快速、简洁、美观、前后端分离的个人博客系统

    大家好 我是你们的章鱼猫 我们从来不含糊说推荐就推荐 所以今天给大家推荐一个 go echo vue 开发的快速 简洁 美观 前后端分离的个人博客系统 blog 同时基于这个系统也可以方便二次开发为 CMS 内容管理系统 和各种企业门户网站
  • 嵌入式 - UART使用进阶

    UART Advanced Features 概要 Overview 最简单直接的使用UART接口的方式 是在轮循操作中来设置和处理UART接口 轮询式UART的问题是轮询方式本身就是低效率的 如果我们的UART被配置为115200的波特率