0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

UART的原理以及驱动程序如何编写

GReq_mcu168 来源:玩转单片机 作者:玩转单片机 2020-12-09 16:14 次阅读

前言

Uart在一个嵌入式系统中是一个非常重要的模块,他承担了CPU与用户交互的桥梁。用户输入信息给程序、CPU要打印一些信息给终端都要依赖UART。

本文将以Exynos4412的UART控制器为基础,讲解UART的原理以及驱动程序如何编写。

UART是什么

UART是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种异步收发传输器,是设备间进行异步通信的关键模块。UART负责处理数据总线和串行口之间的串/并、并/串转换,并规定了帧格式;通信双方只要采用相同的帧格式和波特率,就能在未共享时钟信号的情况下,仅用两根信号线(Rx 和Tx)就可以完成通信过程,因此也称为异步串行通信。UART总线双向通信,可以实现全双工传输和接收。在嵌入式设计中,UART用于主机与辅助设备通信,如汽车音响与外接AP之间的通信,与PC机通信包括与监控调试器和其它器件,如EEPROM通信。

通常需要加入一个合适的电平转换器,如SP3232E、SP3485,UART还能用于RS-232、RS-485 通信,或与计算机的端口连接。UART 应用非常广泛,手机工业控制、PC 等应用中都要用到UART。

UART通信方式

UART使用的是 异步,串行通信方式。

串行通信

串行通信是指利用一条传输线将资料一位位地顺序传送。好比是一列纵队,每个数据元素依次纵向排列。如下图所示,传输时一个比特一个比特的串行传输,每个时钟周期传输一个比特,这种传输方式相对比较简单,速度较慢,但是使用总线数较少,通常一根接收线,一根发送线即可实现串行通信。

它的缺点是要增加额外的数据来控制一个数据帧的开始和结束。特点是通信线路简单,利用简单的线缆就可实现通信,降低成本,适用于远距离通信,但传输速度慢的应用场合。

并行通信

并行通信好比一排横队,齐头并进同时传输。这种通信方式每个时钟周期传输的数据量和其总线宽度成正比,但是实现较为复杂。

d62b13a0-2e2a-11eb-a64d-12bb97331649.png

异步通信

异步通信以一个字符为传输单位,通信中两个字符间的时间间隔多少是不固定的,然而在同一个字符中的两个相邻位间的时间间隔是固定的。

在异步通信技术中,数据发送方和数据接收方没有同步时钟,只有数据信号线,只不过发送端和接收端会按照协商好的协议(固定频率)来进行数据采样。数据发送方以每秒钟57600bits的速度发送数据,接收方也以57600bits的速度去接收数据,这样就可以保证数据的有效和正确。通常异步通信中使用波特率(Baud-Rate)来规定双方传输速度,其单位为bps(bits per second每秒传输位数)。

同步通信

在发送数据信号的时候,会同时送出一根同步时钟信号, 用来同步发送方和接收方的数据采样频率。如下图所示,同步通信时,信号线1是一根同步时钟信号线,以固定的频率进行电平的切换,其频率周期为t,在每个电平的上升沿之后进行对同步送出的数据信号线2进行采样(高电平代表1,低电平代表0),根据采样数据电平高低取得输出数据信息。如果双方没有同步时钟的话,那么接收方就不知道采样周期,也就不能正常的取得数据信息。

d684d200-2e2a-11eb-a64d-12bb97331649.png

帧格式

数据传送速率用波特率来表示,即每秒钟传送的二进制位数。例如数据传送速率为120字符/秒,而每一个字符为10位(1个起始位,7个数据位,1个校验位,1个结束位),则其传送的波特率为10×120=1200字符/秒=1200波特。数据通信格式如下图:

d6b52388-2e2a-11eb-a64d-12bb97331649.png

其中各位的意义如下:

起始位:先发出一个逻辑”0”信号,表示传输字符的开始。*数据位:可以是5~8位逻辑”0”或”1”。如ASCII码(7位),扩展BCD码(8位)。小端传输 *校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验) *停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。*空闲位:处于逻辑“1”状态,表示当前线路上没有资料传送。

注:异步通信是按字符传输的,接收设备在收到起始信号之后只要在一个字符的传输时间内能和发送设备保持同步就能正确接收。下一个字符起始位的到来又使同步重新校准(依靠检测起始位来实现发送与接收方的时钟自同步的)

关于RS-232、RS-422、RS-485等标准,大家可以参考文章《一篇文章了解什么是串口,UART、RS-232、RS-422、RS-485 》

Exynos4412 Uart

本文讨论UART 是基于Cortex-A9架构的Exynos4412 为例。

特性

Exynos4412 中UART,有4 个独立的通道,每个通道都可以工作于中断模式或DMA 模式,即UART 可以发出中断或 DMA 请求以便在UART 、CPU 间传输数据。使用系统时钟时,Exynos4412 的 UART 波特率可以达到 4Mbps 。每个UART通道包含两个FIFO用来接收和发送:

通道 0有 256 字节的发送 FIFO 和 256 字节的接收FIFO

通道 1、4有 64 字节的发送 FIFO 和 64 字节的接收FIFO

通道 2、3有 16 字节的发送FIFO 和 16 字节 的接收 FIFO 。

UART include:

波特率可以通过编程进行 。

红外接收/发送

每个通道支持停止位有 1位、 2位

数据位有 5、6、7或 8位

每个UART还包括

波特率发生器、发送器、接收器、控制逻辑组成。

Uart控制器

功能模块

d6ead4e2-2e2a-11eb-a64d-12bb97331649.png

每个UART包含一个波特率产生器,发送器,接收器和一个控制单元,如上图所示:

发送数据 CPU 先将数据写入发送FIFO 中,然后 UART 会自动将FIFO 中的数据复制到“发送移位器” (Transmit Shifter )中,发送移位器将数据一位一位地发送到 TxDn 数据线上 (根据设定的格式,插入开始位 、较验和停止)。

接收数据 “移位器” (Receive Shifter )将 RxDn 数据线上的数据一位一位的接收进来,然后复制到FIFO 中, CPU即可从中读取数据。

UART是以异步方式实现通信的,其采样速度由波特率决定,波特率产生器的工作频率可以由PCLK(外围设备频率),FCLK/n(CPU工作频率的分频),UEXTCLK(外部输入时钟)三个时钟作为输入频率,波特率设置寄存器是可编程的,用户可以设置其波特率决定发送和接收的频率。发送器和接收器包含了64Byte的FIFO和数据移位器。UART通信是面向字节流的,待发送数据写到FIFO之后,被拷贝到数据移位器(1字节大小)里,数据通过发送数据管脚TXDn发出。同样道理,接收数据通过RXDn管脚来接收数据(1字节大小)到接收移位器,然后将其拷贝到FIFO接收缓冲区里。(1)数据发送 发送的数据帧可编程的,它的一个帧长度是用户指定的,它包括一个开始位,5~8个数据位,一个可选的奇偶校验位和1~2个停止位,数据帧格式可以通过设置ULCONn寄存器来设置。发送器也可以产生一个终止信号,它是由一个全部为0的数据帧组成。在当前发送数据被完全传输完以后,该模块发送一个终止信号。在终止信号发送后,它可以继续通过FIFO(FIFO)或发送保持寄存器(NON-FIFO)发送数据。(2)数据接收 同样接收端的数据也是可编程的,接收器可以侦测到溢出错误奇偶校验错误,帧错误和终止条件,每个错误都可以设置一个错误标志。• 溢出错误 :在旧数据被读取到之前,新数据覆盖了旧数据 • 奇偶校验错误:接收器侦测到了接收数据校验结果失败,接收数据无效 • 帧错误 :接收到的数据没有一个有效的停止位,无法判定数据帧结束 • 终止条件 :RxDn接收到保持逻辑0状态持续长于一个数据帧的传输时间

(3)自动流控AFC(Auto Float Control) UART0和UART1支持有nRTS和nCTS的自动流控。在AFC情况下,通信双方nRTS和nCTS管脚分别连接对方的nCTS和nRTS管脚。通过软件控制数据帧的发送和接收。在开启AFC时,发送端接收发送前要判断nCTS信号状态,当接收到nCTS激活信号时,发送数据帧。该nCTS管脚连接对方nRTS管脚。接收端在准备接收数据帧前,其接收器FIFO有大于32个字节的空闲空间,nRTS管脚会发送激活信号,当其接收FIFO小于32个字节的空闲空间,nRTS必须置非激活状态。

d7279346-2e2a-11eb-a64d-12bb97331649.png

选择时钟源

d754dd92-2e2a-11eb-a64d-12bb97331649.png

Exynos4412 UART的时钟源有八种选择:XXTI 、XusbXTI 、SCLK_HDMI24M 、SCLK_USBPHY0 、 SCLK_HDMIPHY 、SCLKMPLL_USER_T 、SCLKEPLL 、SCLKVPLL ,由 CLK_SRC_PERIL0 寄存器控制。选择好时钟源后,还可以通过 DIVUART0 ~4设置分频系数,由 CLK_DIV_PERIL0 寄存器控制。从分频器得到的时钟被称为SCLK UART 。SCLK UART 经过上图中的“ UCLK Generator”后,得到UCLK ,它的频率就是UART 的波特率。“ Generator UCLK Generator ”通过这 2个寄存器来设置:UBRDIVn(UART BAUD RATE DIVISOR) 、UFRACVALn 。

UART配置寄存器

d7819422-2e2a-11eb-a64d-12bb97331649.png

ULCONn

d7c19ac2-2e2a-11eb-a64d-12bb97331649.png

bite [6] 红外模式 选择串口0是否使用红外模式:0 = 正常通信模式 1 = 红外通信模式

bite [5:3] 校验模式 设置串口0在数据接收和发送时采用的校验方式:0xx = 无校验 100 = 奇校验 101 = 偶校验 110 = 强制校验/检测是否为1 111 = 强制校验/检测是否为0

[2] 停止位 设置串口0停止位数:0 = 每个数据帧一个停止位 1 = 每个数据帧二个停止位

[1:0] 数据位 设置串口0数据位数:00 = 5个数据位 01 = 6个数据位 10 = 7个数据位 11 = 8个数据位

该寄存器我们通用的配置是:

ULCON2=0x3;//Normalmode,Noparity,Onestopbit,8databits

UCONn

d7f44166-2e2a-11eb-a64d-12bb97331649.png

d8253ec4-2e2a-11eb-a64d-12bb97331649.png

d87a2b5a-2e2a-11eb-a64d-12bb97331649.png

d8af5136-2e2a-11eb-a64d-12bb97331649.png

[15:12]FCLK分频因子当UART0选择FCLK作为时钟源时,设置其FCLK的分频因子 UART0 工作时钟频率 = FCLK/ FCLK分频因子 + 6

[11:10] UART时钟源选择 选择UART0的工作时钟PCLK,UEXTCLK,FCLK/n:00,10 = PCLK 01 = UEXTCLK 11 = FCLK/n 当选择FCLK/n作为UART0工作时钟时还要做其它设置,具体请读者自行查看硬件手册

[9] 发送数据中断产生类型 设置UART0中断请求类型,在非FIFO传输模式下,一旦发送数据缓冲区为空,立即产生中断信号,在FIFO传输模式下达到发送数据触发条件时立即产生中断信号:0 = 脉冲触发 1 = 电平触发

[8] 接收数据中断产生类型 设置UART0中断请求类型,在非FIFO传输模式下,一旦接收到数据,立即产生中断信号,在FIFO传输模式下达到接收数据触发条件时立即产生中断信号:0 = 脉冲触发 1 = 电平触发

[7] 接收数据超时 设置当接收数据时,如果数据超时,是否产生接收中断:0 = 不开启超时中断 1 = 开启超时中断 10 = 7个数据位 11 = 8个数据位

[6] 接收数据错误中断 设置当接收数据时,如果产生异常,如传输中止,帧错误,校验错误时,是否产生接收状态中断信号:0 = 不产生错误状态中断 1 = 产生错误状态中断

[5] 回送模式 设置该位时UART会进入回送模式,该模式仅用于测试 0 = 正常模式 1 = 回送模式

[4] 发送终止信号 设置该位时,UART会发送一个帧长度的终止信号,发送完毕后,该位自动恢复为0 0 = 正常传输 1 = 发送终止信号

[3:2] 发送模式 设置采用哪个方式执行数据写入发送缓冲区 00 = 无效 01 = 中断请求或查询模式 10 = DMA0请求

[1:0] 接收模式 设置采用哪个方式执行数据写入接收缓冲区 00 = 无效 01 = 中断请求或查询模式 10 = DMA0请求

该寄存器通用配置为:

UCON2=0x5;//Interruptrequestorpollingmode

一般裸机情况下,采用轮询模式。

UTRSTATn

UTRSTAT n寄存器用来表明数据是否已经发送完毕、是否已经接收到数据,格式如下图所示,上面说的“缓冲区”,其实就是下图中的 FIFO ,不使用 FIFO 功能时可以认为其深度为 1。当我们读取数据时,就轮询检查bit[0]置1之后,然后再从URXHn寄存器读取数据;当我们读取数据时,就轮询检查bit[1]置1之后,然后再向UTXHn寄存器写入数据来发送数据;

d8da3dba-2e2a-11eb-a64d-12bb97331649.png

d906b3ea-2e2a-11eb-a64d-12bb97331649.png

UTXHn寄存器(UART TRANSMIT BUFFER REGISTER)

CPU 将数据写入这个寄存器, UART即会将它保存到缓冲区中,并自动发送出去。

URXHn寄存器(UART RECEIVE BUFFER REGISTER)

当 UART 接收到数据时,读取这个寄存器,即可获得数据。

UFRACVALn 计算波特率

d9394922-2e2a-11eb-a64d-12bb97331649.png

根据给定的波特率、所选择时钟源频率,可以通过以下公式计算 UBRDIVn 寄存器 (n 为 0~4,对应 5个 UART 通道 )的值。

UBRDIVn=(int)(UARTclock/(buadratex16))–1

上式计算出来的 UBRDIVn 寄存器值不一定是整数, UBRDIVn 寄存器取其整数部分,小部分由 UFRACVALn 寄存器设置, UFRACVALn 寄存器的引入,使产生波特率更加精确。【举例】当UART clock为100MHz时,要求波特率为115200 bps,则:

100000000/(115200x16)–1=54.25–1=53.25 UBRDIVn=整数部分=53 UFRACVALn/16=小数部分=0.25 UFRACVALn=4

电路图

外设电路图:

d96576aa-2e2a-11eb-a64d-12bb97331649.png

SP3232EEA 用来将TTL电平转换成RS232电平。我们使用的是COM2。

外设与核心板连接电路图

d98ffde4-2e2a-11eb-a64d-12bb97331649.jpg

可见UART的收发引脚连接到了GPA上,打开exynos4412芯片手册:

d9b90734-2e2a-11eb-a64d-12bb97331649.png

我们只需要将GPA1 的低8位设置为0x22。

实例代码

裸机代码,主要实现uart_init()、putc()、getc()这三个函数。

uart_init()

该函数主要配置UART的,波特率115200,数据位:8,奇偶校验位:0,终止位:1,不设置流控。如下图:是运行在windows下常用的串口工具配置信息,配置信息必须完全一致。

putc()

该函数是向串口发送一个数据data,他的实现逻辑就是轮询检查寄存器UART2.UTRSTAT2 ,判断其bite【1】是否置1,如果置1,则向UART2.UTXH2存入要发送的数据即可。

getc()

该函数是从串口接收一个数据data,他的实现逻辑就是轮询检查寄存器UART2.UTRSTAT2 ,判断其bite【0】是否置1,如果置1,说明数据准备好,则可以从寄存器UART2.URXH2取出数据。

/* *UART2 */ typedefstruct{ unsignedintULCON2; unsignedintUCON2; unsignedintUFCON2; unsignedintUMCON2; unsignedintUTRSTAT2; unsignedintUERSTAT2; unsignedintUFSTAT2; unsignedintUMSTAT2; unsignedintUTXH2; unsignedintURXH2; unsignedintUBRDIV2; unsignedintUFRACVAL2; unsignedintUINTP2; unsignedintUINTSP2; unsignedintUINTM2; }uart2; #defineUART2(*(volatileuart2*)0x13820000) /*GPA1*/ typedefstruct{ unsignedintCON; unsignedintDAT; unsignedintPUD; unsignedintDRV; unsignedintCONPDN; unsignedintPUDPDN; }gpa1; #defineGPA1(*(volatilegpa1*)0x11400020) voiduart_init() {/*UART2initialize*/ GPA1.CON=(GPA1.CON&~0xFF)|(0x22);//GPA1_0:RX;GPA1_1:TX UART2.ULCON2=0x3;//Normalmode,Noparity,Onestopbit,8databits UART2.UCON2=0x5;//Interruptrequestorpollingmode //Baud-rate:src_clock:100Mhz UART2.UBRDIV2=0x35; UART2.UFRACVAL2=0x4; } voidputc(constchardata) {while(!(UART2.UTRSTAT2&0X2)); UART2.UTXH2=data; if(data==) putc(); } chargetc(void) {chardata; while(!(UART2.UTRSTAT2&0x1)); data=UART2.URXH2; if((data==)||(data==)) { putc(); putc(); }else putc(data); returndata; } voidputs(constchar*pstr) {while(*pstr!=') putc(*pstr++); } voidgets(char*p) {chardata; while((data=getc())!=) {if(data==') {p--; } *p++=data; } if(data==) *p++=; *p='; }

责任编辑:lq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 转换器
    +关注

    关注

    27

    文章

    8206

    浏览量

    141809
  • ARM
    ARM
    +关注

    关注

    134

    文章

    8651

    浏览量

    361781
  • uart
    +关注

    关注

    22

    文章

    1159

    浏览量

    99961

原文标题:基于ARM UART裸机驱动详解

文章出处:【微信号:mcu168,微信公众号:硬件攻城狮】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    怎么编写Framebuffer驱动程序

    Framebuffer 驱动程序框架 分为上下两层: fbmem.c:承上启下 实现、注册 file_operations 结构体 把 APP 的调用向下转发到具体的硬件驱动程序
    的头像 发表于 03-22 09:13 158次阅读
    怎么<b class='flag-5'>编写</b>Framebuffer<b class='flag-5'>驱动程序</b>

    ch341a驱动程序无法使用

    随着计算机技术的不断发展,各种外部设备的驱动程序成为了保证硬件正常工作的重要一环。然而,有时我们可能会遇到ch341a驱动程序无法使用的问题。本文将详细解释该问题的原因,并提供详实、细致的解决方法
    的头像 发表于 12-26 14:17 1320次阅读

    linux驱动程序的主要流程和功能

    驱动程序是用于控制和管理硬件设备的软件模块,它主要负责与设备进行交互,通过操作设备的寄存器和接口,实现对硬件的控制和访问。在Linux系统中,驱动程序是实现与硬件设备交互的一个关键部分。本文将详细
    的头像 发表于 12-08 14:56 778次阅读

    linux的uart驱动示例剖析

    底层串行硬件的驱动程序负责向serial核心驱动程序提供由struct uart_port定义的端口信息和一组由struct uart_ops定义的控制方法,底层
    的头像 发表于 11-09 14:27 691次阅读
    linux的<b class='flag-5'>uart</b><b class='flag-5'>驱动</b>示例剖析

    如何用c语言编写arduino虚拟串口的驱动程序?

    用c语言编写arduino虚拟串口的驱动程序
    发表于 10-25 08:29

    OpenHarmony:全流程讲解如何编写Watchdog平台驱动以及应用程序

    1、程序介绍本程序是基于OpenHarmony标准系统编写的平台驱动案例:Watchdog目前已在凌蒙派-
    的头像 发表于 09-19 10:54 606次阅读
    OpenHarmony:全流程讲解如何<b class='flag-5'>编写</b>Watchdog平台<b class='flag-5'>驱动</b><b class='flag-5'>以及</b>应用<b class='flag-5'>程序</b>

    OpenHarmony:全流程讲解如何编写RTC平台驱动以及应用程序

    1、程序介绍本程序是基于OpenHarmony标准系统编写的平台驱动案例:RTC目前已在凌蒙派-RK3568开发板跑通。
    的头像 发表于 09-19 10:14 504次阅读
    OpenHarmony:全流程讲解如何<b class='flag-5'>编写</b>RTC平台<b class='flag-5'>驱动</b><b class='flag-5'>以及</b>应用<b class='flag-5'>程序</b>

    Windows驱动程序——07.703.06.00

    电子发烧友网站提供《Windows驱动程序——07.703.06.00.zip》资料免费下载
    发表于 08-28 11:44 0次下载
    Windows<b class='flag-5'>驱动程序</b>——07.703.06.00

    vmware驱动程序

    电子发烧友网站提供《vmware驱动程序.txt》资料免费下载
    发表于 08-24 14:27 0次下载
    vmware<b class='flag-5'>驱动程序</b>

    分享Windows驱动程序

    电子发烧友网站提供《分享Windows驱动程序.zip》资料免费下载
    发表于 08-04 11:46 2次下载
    分享Windows<b class='flag-5'>驱动程序</b>

    如何编写ADX122驱动程序

    大概是能看的出来兼容adx112的,采用的是spi的接口,在这个章节我们主要讲是如何编写驱动程序,所以先跳过一些重要信息。
    发表于 08-02 14:59 582次阅读
    如何<b class='flag-5'>编写</b>ADX122<b class='flag-5'>驱动程序</b>?

    Windows驱动程序案例

    电子发烧友网站提供《Windows驱动程序案例.zip》资料免费下载
    发表于 07-28 11:42 0次下载
    Windows<b class='flag-5'>驱动程序</b>案例

    Windows驱动程序分享

    电子发烧友网站提供《Windows驱动程序分享.zip》资料免费下载
    发表于 07-26 17:43 0次下载
    Windows<b class='flag-5'>驱动程序</b>分享

    Windows驱动程序

    电子发烧友网站提供《Windows驱动程序.zip》资料免费下载
    发表于 07-26 17:17 0次下载
    Windows<b class='flag-5'>驱动程序</b>

    几种常见的单片机驱动程序设计模式

    单片机开发人员需要掌握的一项基本技能是,了解如何编写驱动程序。在嵌入式系统中,通常有两种类型的驱动程序:单片机外围设备驱动程序和通过I2C,SPI或
    的头像 发表于 07-10 11:09 3276次阅读
    几种常见的单片机<b class='flag-5'>驱动程序</b>设计模式