软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! 9.1 概述 串口自诞生以来由于其简单可靠的传输方式,被大量使用,对于现在这个充满高速通信设备的时代来说,串口依然不过时。老早以前的台式机和笔记本可都是有串口的,虽然现在很多台式机串口没有了,笔记本也没有串口了,但是串口从来没有被丢弃,只是以另外一种形式存在,这就是USB转串口芯片。串口只需要2根线就可以实现一收一发,使用简单,可靠方便,在低速场合大量使用。比如一些工控的人机界面、我们用的一些单片机的USB下载器都是用USB转串口来实现的。 本课详细的分析了UART中断的实现过程,在PL_PS中断和定时器中断的基础上进行UART中断开发,因此本课有难度。建议在学习PL_PS中断和定时器中断后,再来学习本课内容。硬件工程可以直接使用定时器中断的硬件工程,因此实验直接讲述SDK软件部分。 通过PL_PS中断、定时器中断、UART中断内容学习,应对中断的使用得心应手,重点需要掌握分析问题的方法。 9.2串口通信介绍在进行具体的串口设计之前,先了解串口通信协议。通常串口的一次发送或接收由四个部分组成:起始位S(“一般为逻辑‘0’)、数据位D0~D7(一般为6位~8位之间可变,数据低位在前)、校验位(奇校验、偶检验或不需要校验位)、停止位(通常为1位、1.5位、2位)。停止位必须为逻辑1。在一次串口通信过程中,数据接收与发送双方没有共享时钟,因此,双方必须协商好数据传输波特率。波特率即数据传输速率。根据双方协议好的传输速率,接收端即可对发送端的数据进行采样。常见的波特率标准为300bps,600bps,800bps,9600bps,19200bps等。当然更块的速度意味着对采样的要求更高,有可能误码率会逐渐提高。 通常对串口进行数据采样,采用更高频的时钟。这样做的目的是采用高频时钟来锁存低频时钟,减少数据的误码率,增加接收模块的自纠错能力。 具体的工作流程为: 发送端按照预先设定好的波特率,发送起始位(Start)+数据位(data)+奇偶校验位+结束位。其中,起始位为逻辑0,结束位为逻辑1,发送端在空闲状态为1。发送数据包格式如下图所示。 • 接收端通过检测电平‘1’到‘0’的跳变来确定一个数据包的开始。确定开始位接收完成之后,依次接收数据,使用更高的采样时钟,完成数据采集。接收完数据位后,继续接收奇偶校验位和停止位。 • 串口的接收与发送,其主要时序设计包括两个部分:1、波特率的产生时序;2、数据传输时序,包括接收与发送。 • 波特率产生时序设计:FPGA输入时钟50Mhz,为得到常用的波特率,仍然采用计数分频来得到。BAUD_DIV=50_000000/波特率。其中采样中心点为发送或接收时钟的中心点,即BAUD_DIV_CAP=50_000000/(2*波特率)。该部分在数据接收和发送部分均单独完成。 • 数据接收模块:在设置好传输波特率的情况下,根据串口传输时序,进行解串。空闲状态时,接收 数据为逻辑高电平,等待起始位逻辑低电平的到来。当起始位到达后,由低位到高位,依次采集8位数据,并进行相应的解串,存入临时寄存器。接收有效数据完成后,判断结束位,接收完毕。 • 数据发送模块:设置发送使能信号和待发送的数据。通过计数器,表示10个数据发送的周期。这10个数据,依次为起始位+8位数据位+1位结束位,实现数据位的逐个发送。 • 本设计中,采用PC机的串口调试助手,发送数据位至FPGA,FPGA接收到数据位之后,立即回传至PC机。具体的设计原理和代码思路,在后续章节逐一介绍。 9.2 搭建FPGA BD工程Step1:新建一个名为为Miz_sys的工程。 Step2:创建一个BD文件,并命名为system,添加并且配置好ZYNQ IP。读者需要根据自己的硬件类型配置好输入时钟频率、内存型号、串口,连接时钟等。新手不清楚这些内容个,请参考“CH01 HelloWold/DDR/网口测试及固化”这一节课。 做这个实验,ZYNQ IP中关键设置至少包括 DDR型号配置、串口配置,以及PS时钟配置,不再啰嗦重复描述。 注意:UART的IO是1.8V如下图 另外可以看到本IP比较简洁,少了GP接口和时钟输出接口如下图设置,可以去掉没有用的GP接口和时钟输出接口。 Step5:单击窗口上的运行按钮,运行程序。 9.5 实验结果系统运行结果如下图所示: 可以发送并且接收任意长度数据。 9.6 程序分析9.6.1 Uart控制器ZYNQ 的ARM具备2路UART,分辨率为UART0和UART1,我们例子中用到了UART1。每个UART控制器(UART 0和UART 1)具有以下功能: 可编程波特率发生器 64字节接收和发送FIFO 可编程协议: 6,7或8个数据位 1,1.5或2个停止位 奇数,偶数,空格,标记或无奇偶校验 奇偶校验,帧和溢出错误检测 断行生成 中断生成 RxD和TxD模式:通过模式设置,可以支持Normal/echo and diagnostic loopbacks模式 9.6.2 uartps_intr.c
通过前面两节课详细的介绍,大家应该已经掌握如何分析库函数的办法,实际上采用库函数都可以不需要了解寄存器的具体配置过程,本课程不再对寄存器的详细配置做介绍,如果读者想去了解寄存的配置可以参考前面两节课的内容,参考ug585自行分析。 9.6.2.1Init_UartPsIntr函数此函数负责初始化 PS UART寄存器。 1 、XUartPs_LookupConfig(DeviceId) 首先依然是通过查找配置程序来获取串口的硬件配置。我们跟踪这个程序,看看他获取的配置是什么。 这个程序还是从一个配置表数组中查找的配置文件,继续往下剥离,看一看这个数组中的内容。 可以看到,这个数组里存放的是UART的设备ID,UART的基地址,时钟频率和一个不知道什么作用的对象。后两个参数是我们没用到的,因此就略过了。前两个都是我们在硬件工程中添加了中断后,系统自动生成的。 2、XUartPs_CfgInitialize(UartInstPtr, Config, Config->BaseAddress) 这个结构体中的内容比较多,第一个对象是我们UART硬件的一些配置,它指向的是一个结构体。那么就来看看这个结构体吧。 可以看到,这些就是刚才我们查找配置程序获取到的硬件参数。 回到XUartPs结构体的分析。第二个对象是输入时钟频率,第三个是设备是否初始化并准备好,第四个是波特率,第五个是两个buffer,一个发送的一个接收的。挑选一个参看一下。 接着第七个是一个Hander,第八个是一个回掉函数,最后一个是platform具体是什么意思不得而知。 回到初始化程序。我们来看看这个函数与之前有什么不同了。 一开始是一长串的初始化,如下图所示: 接下来的这个函数是一个用于判断芯片类型的函数。 接下来,程序将Instance(也就是我们的UART硬件)的标志设置为XIL_COMPONENT_IS_READY,表明此时UART已经可以使用了。 接下来,程序将UART的波特率设置为了115200。 接下来的这一句是读取UART的模式寄存器。 我们可以来看看读取的什么内容,把鼠标停放在这个函数的上方,看到函数显示出了这个函数的原函数。 与定时器实验中讲到的读写寄存器的函数差不多,第一个参数是UART的基地址,这在一开始的分析中就提到过,反回去看看UART的基地址。 可以知道,此处的基地址为0xE000100,直接计算:E0001000+0x0004= E0001004。打开ug585查看下这个寄存器的介绍。 可以看到,这是一个UART的模式寄存器,通过这个寄存器可以设置串口的数据位宽,有无停止位和奇偶校验位等信息。 再来看看下一句程序。这句是对刚才读出的寄存器的一个运算。 首先得到方框中这三个参数的值。这里我们已经查看程序得知这三个值分别为:6,A0,38。然后进行运算:ModeRegister=E0001004 & (~(6|A0|38))=E0001004 & 11 =0。 接下来的这一句也是一个运算,不多讲,直接运算。ModeRegister=0|(0|0|20)=20。 这段程序就是一个写寄存器的功能了。看看这个函数的原函数。 由此得出,这个函数读写的地址为刚才模式寄存器的地址,写入的数据就是运算得出的20h。参照刚才ug585里的模式寄存器说明,显而易见,经过这段程序之后,把UART设置为了8个数据位,1个停止位和无奇偶校验位的模式。 接下来的还有3个写寄存器的程序,分析方法与刚才的一致。这里就只给出它们实现的功能。分别是:设置UART的RX FIFO在8byte处触发、设置UART的超时为1(4个字符时间)、禁止所有中断轮询模式为默认的样式。 回到main函数的分析当中,接下来的函数实现的是建立起中断的功能,这个函数在我们上一章也进行过详细的讲解 3、XUartPs_SetHandler(UartInstPtr, (XUartPs_Handler)UartPs_Intr_Handler, UartInstPtr) 函数负责设置中断产生后的回调函数为UartPs_Intr_Handler。 4、XUartPs_SetInterruptMask(UartInstPtr, IntrMask) 函数负责配置中断类型 5、XUartPs_SetRecvTimeout(UartInstPtr, 8) 函数设置了空闲超时等待的时间为8x4 = 32 为32个波特率采样时钟,意思就是当串口上超过32个波特率采样时钟没有数据的时候,就会触发一次超时中断,这样可以通知用户程序去读取已经接收到的数据。 以下是寄存器说明 9.6.2.2 UartPs_Setup_IntrSystem函数此函数初始化PS Uart回调的函数XUartPs_InterruptHandler,并且在最后启动PS UART中断。 9.6.2.3 UartPs_Intr_HandlerPS Uart中断产生后的回调函数,在此回调函数中会去调用mian函数里面的中断处理函数。 9.6.3 main.c
为了正常启动接收,不管有没有数据到来,需要先启动一次接收函数XUartPs_Recv(&UartPs, RecvBuffer, TEST_BUFFER_SIZE)。 |
扫描关注,了解最新资讯