外设接口之UART应用指南

通用异步接收器/发送器 (UART) 是一种硬件功能,可使用广泛采用的异步串行通信接口(例如 RS232、RS422 和 RS485)处理通信(即定时要求和数据帧)。 UART提供了一种广泛采用且廉价的方法来实现不同设备之间的全双工或半双工数据交换。

基础知识

每个 UART 控制器均可独立配置参数,如波特率、数据位长度、位顺序、停止位数量、奇偶校验位等。所有常规 UART 控制器均与各个制造商的支持 UART 的设备兼容 。

在UART通信中,两个UART直接相互通信。 发送UART将来自CPU等控制设备的并行数据转换为串行形式,将其串行发送到接收UART,然后接收UART将串行数据转换回并行数据以供接收设备使用。 只需两根线即可在两个 UART 之间传输数据。

数据从发送 UART 的 Tx 引脚流向接收 UART 的 Rx 引脚:

UART 异步传输数据,这意味着没有时钟信号来同步发送 UART 的位输出和接收 UART 的位采样。 发送 UART 向正在传输的数据包添加起始位和停止位,而不是时钟信号。 这些位定义数据包的开始和结束,以便接收 UART 知道何时开始读取这些位。

当接收 UART 检测到起始位时,它开始以称为波特率的特定频率读取传入位。 波特率是数据传输速度的度量,以每秒位数 (bps) 表示。 两个 UART 必须以大致相同的波特率运行。 在位时序相差太远之前,发送和接收 UART 之间的波特率只能相差约 10%。两个 UART 还必须配置为发送和接收相同的数据包结构。

工作原理

将要发送数据的UART从数据总线接收数据。 数据总线用于由 CPU、内存或微控制器等其他设备将数据发送到 UART。 数据以并行形式从数据总线传输到发送UART。 发送UART从数据总线获取并行数据后,添加起始位、奇偶校验位和停止位,创建数据包。 接下来,数据包在 Tx 引脚上逐位串行输出。 接收 UART 在其 Rx 引脚上逐位读取数据包。 然后,接收 UART 将数据转换回并行形式,并删除起始位、奇偶校验位和停止位。 最后,接收UART将数据包并行传输到接收端的数据总线。

框图

UART 框图由两个组件组成,即发送器和接收器,如下所示。

发送器部分包括三个块,即发送保持寄存器、移位寄存器和控制逻辑。 同样,接收器部分包括接收保持寄存器、移位寄存器和控制逻辑。 这两个部分通常由波特率发生器提供。 该发生器用于在发送器部分和接收器部分必须发送或接收数据时生成速度。

发送器中的保持寄存器包含要发送的数据字节。 发送器和接收器中的移位寄存器将位向右或向左移动,直到发送或接收一个字节的数据。 读(或)写控制逻辑用于告知何时读或写。

发送器和接收器之间的波特率发生器生成范围为 110 bps 至 230400 bps 的速度。 通常,微控制器的波特率为 9600 至 115200。

帧结构

UART 传输的数据被组织成数据包。 每个数据包包含 1 个起始位、5 至 9 个数据位(取决于 UART)、一个可选奇偶校验位以及 1 或 2 个停止位:

空闲状态:高电平,表示当前线路上无数据传送

起始位:UART 数据传输线在不传输数据时通常保持在高电压电平。 为了开始数据传输,发送 UART 将传输线从高电平拉至低电平,持续一个时钟周期。 当接收UART检测到高电压到低电压的转变时,它开始以波特率的频率读取数据帧中的位。

数据位: 数据帧包含正在传输的实际数据。 如果使用奇偶校验位,它的长度可以是 5 位到 8 位。 如果不使用奇偶校验位,数据帧可以是9位长。 在大多数情况下,数据首先以最低有效位发送。

奇偶校验位: 奇偶校验描述了数字的偶数或奇数。 奇偶校验位是接收 UART 判断数据在传输过程中是否发生变化的一种方式。 位可能因电磁辐射、不匹配的波特率或长距离数据传输而改变。 接收UART读取数据帧后,统计值为1的位数,并检查总数是偶数还是奇数。 如果奇偶校验位为 0(偶校验),则数据帧中的 1 位总数应为偶数。 如果奇偶校验位为 1(奇奇偶校验),则数据帧中的 1 位总计应为奇数。 当奇偶校验位与数据匹配时,UART 就知道传输没有错误。 但如果奇偶校验位为0,且总数为奇数; 或者奇偶校验位为 1,并且总数为偶数,UART 知道数据帧中的位已更改。

停止位:停止位位于数据包的末尾。 通常,该位为 2 位长,但经常仅使用一位。 为了停止广播,UART 保持数据线处于高电压。

波特率

线路中信号调制的频率,单位是bps或b/s(位每秒)。一个固定频率的时钟信号不断振荡,每一个时钟周期,发送一位数据信号。

UART通信双方要求具有相同的波特率。但是,由于UART是异步通信,即没有一根时钟线连接通信双方,各自按照自己内部的时钟调制出一个理论上相等的波特率,但是由于硬件本身不可避免的误差,实际上的波特率往往不可能严格等于理论值,但是要求双方波特率的误差不能超过10%,否则会导致接收方读取到的是乱码数据。

硬件流控

流控,即流量控制。

任何通信协议的双方,都会分配有存储空间有限的缓冲区,用来接收对方发送的数据。一旦对方发送数据过快,而己方处理速度较慢,就可能出现缓冲区满无法处理、甚至丢数据的严重情况。

此时流量控制则显得尤为重要,接收方无法接收更多数据时,通知发送方暂停数据发送,当可以接收数据后,再通知发送发继续发送数据。

硬件流控引脚的UART接口连接图,相对于前面,多了RTS和CTS两个引脚,此二者UART硬件接口的常规功能引脚。

RTS:输出功能,连接对方的CTS,当己方RTS拉高时,则通知对方UART暂停发送数据,当RTS恢复低电平时,通知对方继续发送数据 。

CTS:输入功能,连接对方的RTS,当己方CTS检测到高电平时,则暂停发送数据,当己方CTS检测到低电平时,则继续发送数据。

FIFO

FIFO(First-In, First-Out)是一种基本的数据结构,其核心思想是:先进入的数据先出去。FIFO可以在硬件和软件中实现,且有同步和异步之分(本节仅介绍同步FIFO)。

软件FIFO:

  • 定义:在软件中使用编程数据结构(如数组、链表)实现的FIFO。

  • 应用:常见于操作系统中的任务调度、网络中的数据包处理或任何需要队列的场合。

  • 操作:主要操作包括入队(添加到队列尾部)和出队(从队列头部移除)。

  • 优点:灵活,可以轻松地调整大小或实现优先级排队等高级功能。

  • 缺点:由于它是在软件中实现的,因此可能不如硬件FIFO那样快。

实现:

软件FIFO最熟悉的就是环形buffer→ ringbuffer。

环形buffer相比与线性buffer,我们不用频繁的分配内存,内存反复使用也使得我们能用更少的内存块做更多的事,并且对内存的管理更加方便更加安全。一般应用在我们频繁的对数据buffer进行读写的时候。

环形缓冲区并不是指物理意义上的一个首尾相连成“环”的缓冲区,而是逻辑意义上的一个环,因为内存空间是线性结构,所以实际上环形缓冲区仍是一段有长度的内存空间,是一个先进先出功能的缓冲区,具备实现通信进程对该缓冲区的互斥访问功能。

实现原理:

环形缓冲区的长度是固定的,在使用该缓冲区时,不需要将所有的数据清除,只需要调整指向该缓冲区的head、write pointer和tail指针位置即可。write pointer指针最先指向head指针位置(环形缓冲区开头位置),数据从write pointer指针处开始存储,每存储一个数据,write pointer指针位置向后移动一个长度 ,随着数据的添加,write pointer指针随移动数据长度大小个位置。当write pointer指向tail尾部指针,write pointer重新指向head指针位置(折行处理),并且覆盖原先位置数据内容直到数据存储完毕。环形缓冲区的好处是可以减少内存分配继而减少系统的开销,减少内存碎片数量,有利于程序长期稳定的运行。

一般构建一个环形缓冲区需要一段连续的内存空间以及4个指针:head指针:指向内存空间中的首地址;tail指针:指向内存空间的尾地址;read pointer:指向内存空间存储数据的起始位置(读指针);write pointer:指向内存空间存储数据的结尾位置(写指针)。

当申请完内存以及指针定义完毕后,环形缓冲区说明及使用如下:

  • 该段内存空间的长度是Len = tail-head;

  • read pointer是读数据的起始位置,当读取完N数据之后要移动N个单位长度的偏移,当有addlen长度的数据要存入到环形缓冲区,若addlen + write pointer > tail时,write pointer将存入len1 = tail - write pointer个数据长度,然后write pointer回到head位置,将剩下的len2 = addlen - len1个数据从head开始存储并覆盖到原来的数据内容。

  • write pointer是写数据的起始位置,当存入N个数据之后要移动N个单位长度的偏移,read pointer是读数据的起始位置,当读取N个数据之后要移动N个单位长度的偏移。当要addlen长度的数据要从环形缓冲区读取,若addlen + read pointer > tail时,read pointer 将读取len1 = tail - read pointer 个数据长度,然后read pointer 回到head位置,将剩下的len2 = addlen - len1个数据从head开始读取完毕。

硬件FIFO

  • 定义:在硬件中,特别是在数字电路中实现的FIFO。

  • 应用:常见于通信接口(如UART、SPI等)中,用于数据缓冲。

  • 实现:通常使用寄存器阵列或双口RAM实现,具有读指针和写指针。

  • 优点:速度快,可以与其他硬件模块并行工作,提供高效的数据流。

  • 缺点:大小固定,不如软件FIFO灵活。

目前QuecPython系列模组均使用硬件FIFO,用于模块间的数据缓冲、跨异步传输数据等。 是由芯片设计者使用硬件电路实现的数据缓存。

同步FIFO

  • 定义:同步FIFO的读和写操作都是在相同的时钟下进行的。

  • 工作原理:使用一个共同的时钟信号来控制数据的读写。当有新的数据可写入时,写指针移动;当有数据可读时,读指针移动。

  • 应用:常见于同一时钟域中的数据流缓冲。

写入操作: FIFO可以根据w_en信号在时钟的每个位置存储/写入wr_data,直到数据满。 写入指针在FIFO存储器中的每个数据写入时都会递增。

读取操作: 根据rd_en信号在时钟的每个位置从FIFO取出或读取数据,直到数据为空。从FIFO存储器读取的每个数据时,读取指针都会递增。

FIFO内部通过对写请求、读请求计数产生读、写指针,读写指针即为memory的读、写地址。写指针指向下一个要写入的地址,读指针指向下一个要读取的地址,写请求使写指针递增,读请求使读指针递增。

FIFO模块输出empty和full信号指示其状态,fifo_full表示FIFO内空间已满不能再写入数据,fifo_empty表示FIFO内没有可供读取的下一个有效数据。

同步FIFO空满信号的产生:

复位时FIFO读、写指针都归零。此时fifo_empty拉高,只能写不能读,一旦有数据写入,会将fifo_empty拉低,允许读取数据。当fifo的写指针指向fifo_depth-1时,此时进行一个写操作会使写指针归零(此时无读操作),拉高fifo_full。

在读写指针相等时,FIFO要么空要么满,所以需要对这两种情况进行区分。

  • FIFO满信号产生

FIFO满状态是由写操作触发的:“在写操作使读、写指针在下个时钟保持相等时,FIFO满”,更为通俗的解释是“写操作让写指针追上了读指针,即写指针套了读指针一圈(跑步的角度)

  • FIFO空信号产生

FIFO空状态是由读操作触发的:“在读操作使读、写指针在下个时钟保持相等时,FIFO空”,更为通俗的解释是“读操作让读指针追上了写指针

异步FIFO

  • 定义:异步FIFO的读和写操作在不同的时钟域中进行。

  • 工作原理:使用两个独立的时钟,一个用于写操作,另一个用于读操作。这需要特殊的设计,以确保跨时钟域的数据完整性和同步。

  • 应用:用于两个有不同操作频率或来自不同源的时钟域之间的数据传输。

DMA

DMA(Direct Memory Access)是一种技术,

允许外部设备(如硬盘、音频接口、网络适配器等)直接与系统内存进行数据交换,而无需中央处理单元(CPU)的干预。这种机制可以显著提高数据传输效率,因为它允许设备在不占用CPU时间的情况下进行数据传输。

特点:

DMA和cpu之前并不是一个并行关系,因为主存只有一个,cpu和DMA无法同时访问主存,只能通过交替访问的方式,访问主存,DMA之所以效率高速度快是因为省去现场保护和现场恢复

DMA传输本身并不会中断程序,但它会占用系统资源:比如IO或RAM。这样一旦CPU需要访问相同的IO或RAM时,就需要长时间等待,直到DMA传输完毕、释放资源。从软件角度来看,这和中断程序非常相似,但其内核截然不同:因为CPU一直在工作,从未有过任务切换,只是偶尔暂停,所以无需现场保护。

此外,如果CPU拥有一定容量的cache,而DMA传输的颗粒度又恰到好处,那么即使访问同一块RAM,软件也是感觉不到程序停止的.

工作过程:

  1. 请求与授权

    • 当一个外部设备(如硬盘控制器)需要与内存交换数据时,它会发出一个DMA请求(DMA Request, 也称为 DRQ)给DMA控制器。

    • DMA控制器在收到请求后,会等待合适的时机来执行数据传输,即当系统总线处于空闲状态时。

    • 一旦准备好,DMA控制器向CPU发出一个DMA授权信号(DMA Grant, 也称为 DACK)。这通常会导致CPU在当前指令执行完毕后暂停,并释放总线控制权。

  2. 传输数据

    • DMA控制器接管总线并开始数据传输。根据设置,它可以是单个字节的传输,或一整块数据的传输。

    • DMA控制器更新源和目的地址,以及还需传输的字节计数。

    • 在数据传输过程中,CPU是不活跃的,或者说被“隔离”了,不参与数据传输过程。

  3. 传输完成

    • 一旦DMA控制器完成了所有的数据传输,它会取消DMA授权信号。

    • DMA控制器会向CPU发送一个中断信号(如果已经设置了中断),告知数据传输已完成。这样,CPU可以恢复其操作,可能是处理数据,或执行其他任务。

  4. 中断服务

    • 如果启用了DMA完成的中断,CPU在数据传输完成后会接收到一个中断请求。

    • CPU随后会调用相应的中断服务程序来处理传输后的任务,例如数据后处理、错误检查或其他相关任务。

  5. 重置与准备下一次DMA

    • DMA控制器重置其状态,并准备响应下一个DMA请求。