本帖最后由 LINUX课程 于 2024-9-11 10:23 编辑
软件版本:vitis2021.1(vivado2021.1) 操作系统:WIN10 64bit 硬件平台:适用XILINX Z7/ZU系列FPGA
1 概述 串口自诞生以来由于其简单可靠的传输方式,被大量使用,对于现在这个充满高速通信设备的时代来说,串口依然不过时。老早以前的台式机和笔记本可都是有串口的,虽然现在很多台式机串口没有了,笔记本也没有串口了,但是串口从来没有被丢弃,只是以另外一种形式存在,这就是USB转串口芯片。串口只需要2根线就可以实现一收一发,使用简单,可靠方便,在低速场合大量使用。比如一些工控的人机界面、我们用的一些单片机的USB下载器都是用USB转串口来实现的。 实验目的: - 熟悉UART串口通信协议,包括数据格式、波特率、起始位、停止位、奇偶校验位等
- 熟悉ZYNQ的UART串口的功能单元以及寄存器功能
- 实现串口的中断接收,发出
2 系统框图 3 UART串口通信协议介绍 我们先了解串口通信协议。通常串口的一次发送或接收由四个部分组成:起始位S(“一般为逻辑‘0’)、数据位D0~D7(一般为6位~8位之间可变,数据低位在前)、校验位(奇校验、偶检验或不需要校验位)、停止位(通常为1位、1.5位、2位)。停止位必须为逻辑1。在一次串口通信过程中,数据接收与发送双方没有共享时钟,因此,双方必须协商好数据传输波特率。波特率即数据传输速率。根据双方协议好的传输速率,接收端即可对发送端的数据进行采样。常见的波特率标准为300bps,600bps,800bps,9600bps,19200bps,38400bps,115200bps等。当然更块的速度意味着对采样的要求更高,有可能误码率会逐渐提高。 通常对串口进行数据采样,采用更高频的时钟。这样做的目的是采用高频时钟来锁存低频时钟,减少数据的误码率,增加接收模块的自纠错能力。 具体的工作流程为: 发送端按照预先设定好的波特率,发送起始位(Start)+数据位(data)+奇偶校验位+结束位。其中,起始位为逻辑0,结束位为逻辑1,发送端在空闲状态为1。发送数据包格式如下图所示。 数据的奇偶校验位是可以选择的,如果不使用奇偶,那么就没有这个数据位,我们本课程中没有用到奇偶校验位。 接收端通过检测电平‘1’到‘0’的跳变来确定一个数据包的开始。确定开始位接收完成之后,依次接收数据,使用更高的采样时钟,完成数据采集。接收完数据位后,继续接收奇偶校验位和停止位。 ZYNQ的UART控制器可以完成发送数据的编码和接收数据的界面,关于更多UART的硬件知识可以阅读以下ZYNQ UART串口部分介绍。 4 ZYNQ UART串口控制介绍 4.1UART控制器概述 ZYNQ的UART控制器支持全双工异步收发,支持多种可编程波特率和I/O信号格式支持自动奇偶校验和多主机检测模式。 通过配置和模式寄存器控制UART,通过读取FIFO状态寄存器、中断状态寄存器、调制解调状态寄存器、其他功能状态寄存器获取UART的工作状态。 UART的TX和RX路径是异步独立的,TX路径和RX路径各有一个64字节的FIFO。控制寄存器可以对UART中的TX和RX FIFO数据序列化和反序列化,另外还包含一个模式开关可以设置TX到RX的环路设置。 在类似调制解调器的应用中使用UART时,调制解调器控制模块会检测并生成调制解调器握手信号,并根据握手协议控制接收器和发送器路径。 4.2UART控制器特性 - 具有可编程波特率发生器
- 具有可配置的接收和发送FIFO,具有字节,两个字节或四个字节的APB访问机制
- 支持6、7或8个数据位
- 支持1、1.5或2个停止位
- 支持奇数,偶数,空格,标记或无奇偶校验
- 支持奇偶校验,成帧和溢出错误检测
- 具有断行的生成和检测
- 支持自动回显,本地环回和远程环回通道模式
- 支持中断产生
- 具有调制解调器控制信号:CTS,RTS,DSR,DTR,RI和DCD
- UART有两个时钟:高级外围总线(APB)的时钟频率高达100 MHz。 uart_ref_clock的范围是1 MHz至100 MHz。
4.3UART控制器功能描述 1:UART控制器框图 2:波特率发生器 UART的sel_clk时钟: 该时钟为UART_REF_CLKk或者UART_REF_CLK/8 波特率采样时钟使能baud_sample: baud_sample=sel_clk/CD 波特率baud_rate: baud_rate = baud_sample/ (BDIV + 1) CD的值范围为1~65535,BDIV的值范围为4~255 以下给出了UG585中常用波特率的计算参数 3:TX发送FIFO 软件需要发送的数据首先会填入到TX的FIFO。 4:TX发送串行发送模块 发送模块从TxFIFO中移除数据,并将其加载到发送器移位寄存器中,以便可以对其进行串行化。发送模块将起始位,数据位,奇偶校验位和停止位移出为串行数据流。在发送波特率时钟使能(baud_tx_rate)的下降沿发送数据,最低有效位在前。 下图中的数据包含了PA奇偶校验位,很多情况下没有这位数据,那么数据就是一共需要10个发送时钟。 5:RX接收FIFO 当RX串行接收模块接收到数据后,数据移入RX接收FIFO。 6:RX串行接收模块 UART使用UART_REF_CLK和时钟使能(baud_sample)连续对UARTx_RxD信号进行过采样。当在中间位置连续监测到3次低电平代表收到RX的起始位。如下所示,采样速度是16倍的波特率。 当检测到有效的起始位时,接收器波特率时钟使能(baud_rx_rate)将重新同步,以便在每个位的理论中点附近对输入的UART RxD信号进行进一步采样。 7:I/O模式切换 模式开关控制控制器内RxD和TxD信号的路由,共有四种工作模式如下图所示,除非只是测试UART软件代码,否则我们都是使用普通模式。 8:UART中断与状态控制器 UART的中断和状态控制器在下面的寄存器介绍中介绍 9:UART调制解调器控制 这部分功能我们不涉及。 4.4UART寄存器概述 XUARTPS_CR寄存器XUARTPS_CR_OFFSET (0x00U) Field Name | Bits | Type | Reset Value | Description | | | | | 31~9bit:保留 8bit:暂停并发送停止位(STOPBRK) 1-当传输一个字节后,设置该位产生停止位,输出12bit的高电平。 0-无影响 7bit:暂停并发送起始位(STARTBRK) 1-当FIFO中已经填入需要发送的数据,并且TX发送移位寄存器已经传输完毕,启动发送起始位。必须在STOPBRK=0的情况下有效。 0-无影响 6bit:重启接收超时计数器(TORST) 1-使能接收超时计数 0-无影响 5bit:禁止发送(TX_DIS) 1-禁止发送 0-使能 4bit:使能发送(TX_EN) 1-使能发送,需要确保TX_DIS=0 0-禁止发送 3bit:禁止接收(RX_DIS) 1-禁止接收,不管RXEN的值 0-使能 2bit:使能接收(RX_EN) 1-使能接收,RX_DIS=0有效 0-禁止接收 1bit:软件复位(TXRST) 1-复位发送逻辑,复位完成后自动清零 0-无影响 0bit:软件复位(RXRST) 1-复位接收逻辑,复位完成后自动清零 0-无影响 |
XUARTPS_MR寄存器XUARTPS_MR_OFFSET (0x04U) Field Name | Bits | Type | Reset Value | Description | | | | | 31~12bit:保留(只读) 11~10bit:保留(可以读写,但是不要修改) 9~8bit:通道模式(CHMODE) 00-正常模式 01-echo模式 10-本地环路 11-远程环回 7~6bit:停止位(NBSTOP) 00-1bit停止位 01-1.5bit停止位 10-2个停止位 11-保留 5~3bit:奇偶校验位(PAR) 000-偶校验 001-奇校验 010-奇偶校验强制为0 011-奇偶校验强制为1 1xx-无校验 2~1bit:字符长度(CHRL) 11-6bits 10-7bits 0x-8bits 0-时钟源选择(CLKSEL) 0-uart_ref_clk 1-uart_ref_clk/8 |
XUARTPS_IER寄存器XUARTPS_IER_OFFSET (0x08U) 中断使能寄存器,设置1使能相关中断 Field Name | Bits | Type | Reset Value | Description | | | | | 31~13bit:保留(只读) 12bit:FIFO溢出中断使能(TOVR) 11bit:FIFO将满中断使能(TNFUL) 10bit:FIFO发送器FIFO出发中断使能(TTRIG) 9bit:Delta调制解调器状态指示器中断使能(IXR_DMS) 8bit:接收超时错误中断使能(IXR_TOUT) 7bit:接收奇偶校验错误中断使能(IXR_PARITY) 6bit:接收帧错误中断使能(IXR_FRAMING) 5bit:接收溢出中断使能(IXR_OVER) 4bit:发送FIFO满中断使能(IXR_TXFULL) 3bit:发送FIFO空中断使能(IXR_TXEMPTY) 2bit:接收FIFO满中断使能(IXR_RXFULL) 1bit:接收FIFO空中断使能(IXR_RXEMPTY) 0bit:接收FIFO中断触发使能(IXR_RXOVR) |
XUARTPS_IDR寄存器XUARTPS_IDR_OFFSET (0x0CU) 中断禁用寄存器,设置1禁用相关中断 Field Name | Bits | Type | Reset Value | Description | | | | | 31~13bit:保留(只读) 12bit:FIFO溢出中断禁用(TOVR) 11bit:FIFO将满中断禁用(TNFUL) 10bit:FIFO发送器FIFO出发中断禁用(TTRIG) 9bit:Delta调制解调器状态指示器中断禁用(IXR_DMS) 8bit:接收超时错误中断禁用(IXR_TOUT) 7bit:接收奇偶校验错误中断禁用(IXR_PARITY) 6bit:接收帧错误中断禁用(IXR_FRAMING) 5bit:接收溢出中断禁用(IXR_OVER) 4bit:发送FIFO满中断禁用(IXR_TXFULL) 3bit:发送FIFO空中断禁用(IXR_TXEMPTY) 2bit:接收FIFO满中断禁用(IXR_RXFULL) 1bit:接收FIFO空中断禁用(IXR_RXEMPTY) 0bit:接收FIFO中断触发禁用(IXR_RXOVR) |
XUARTPS_IMR寄存器XUARTPS_IMR_OFFSET (0x10U) 中断掩码寄存器,是只读寄存器1代表相关中断使能,0代表相关中断禁用 Field Name | Bits | Type | Reset Value | Description | | | | | 31~13bit:保留(只读) 12bit:FIFO溢出中断掩码(TOVR) 11bit:FIFO将满中断掩码(TNFUL) 10bit:FIFO发送器FIFO出发中断掩码(TTRIG) 9bit:Delta调制解调器状态指示器中断掩码(IXR_DMS) 8bit:接收超时错误中断掩码(IXR_TOUT) 7bit:接收奇偶校验错误中断掩码(IXR_PARITY) 6bit:接收帧错误中断掩码(IXR_FRAMING) 5bit:接收溢出中断掩码(IXR_OVER) 4bit:发送FIFO满中断掩码(IXR_TXFULL) 3bit:发送FIFO空中断掩码(IXR_TXEMPTY) 2bit:接收FIFO满中断掩码(IXR_RXFULL) 1bit:接收FIFO空中断掩码(IXR_RXEMPTY) 0bit:接收FIFO中断触发掩码(IXR_RXOVR) |
XUARTPS_ISR寄存器XUARTPS_ISR_OFFSET (0x14U) 中断状态寄存器,1代表相关中断产生,读该位会清除中断状态 Field Name | Bits | Type | Reset Value | Description | | | | | 31~13bit:保留(只读) 12bit:FIFO溢出中断状态(TOVR) 11bit:FIFO将满中断状态(TNFUL) 10bit:FIFO发送器FIFO出发中断状态(TTRIG) 9bit:Delta调制解调器状态指示器中断状态(IXR_DMS) 8bit:接收超时错误中断状态(IXR_TOUT) 7bit:接收奇偶校验错误中断状态(IXR_PARITY) 6bit:接收帧错误中断状态(IXR_FRAMING) 5bit:接收溢出中断状态(IXR_OVER) 4bit:发送FIFO满中断状态(IXR_TXFULL) 3bit:发送FIFO空中断状态(IXR_TXEMPTY) 2bit:接收FIFO满中断状态(IXR_RXFULL) 1bit:接收FIFO空中断状态(IXR_RXEMPTY) 0bit:接收FIFO中断触发状态(IXR_RXOVR) |
XUARTPS_BAUDGEN寄存器XUARTPS_BAUDGEN_OFFSET (0x18U) Field Name | Bits | Type | Reset Value | Description | | | | | 31~16bit:保留(只读) 15~0bit:波特率分频器 0-禁止波特率采样 1-Bypass (baud_sample = sel_clk) 2-2~65535分频 |
XUARTPS_RXTOUT寄存器XUARTPS_RXTOUT_OFFSET (0x1CU) Field Name | Bits | Type | Reset Value | Description | | | | | 31~8bit:保留(只读) 7~0bit:接收超时寄存器 0-禁用接收超时 1~255个baud_sample 时钟周期作为超时检测 |
XUARTPS_RXWM寄存器XUARTPS_RXTOUT_OFFSET (0x20U) Field Name | Bits | Type | Reset Value | Description | | | | | 31~6bit:保留(只读) 5~0bit:接收FIFO触发值 0-禁用触发 1~63 FIFO当FIFO已经有了相应数据产生接收触发中断 |
XUARTPS_MODEMCR寄存器XUARTPS_MODEMCR_OFFSET (0x24U) Modem控制寄存器该寄存器本实验不涉及不介绍 XUARTPS_MODEMSR寄存器XUARTPS_MODEMSR_OFFSET (0x28U) Modem状态寄存器该寄存器本实验不涉及不介绍 XUARTPS_SR寄存器XUARTPS_SR_OFFSET (0x2CU) 只读通道状态寄存器,可以对 UART设计的原始未屏蔽状态信息的持续监控。 Field Name | Bits | Type | Reset Value | Description | | | | | 31~15bit:保留(只读) 14bit:发送FIFO满连续状态(TNFUL) 1-TX FIFO未使用的空间大于1 0-TX FIFO就剩1个未使用空间 13bit:发送FIFO触发连续状态(TTRIG) 1-TX FIFO的数据量大于或等于触发值 0-TX FIFO的数据量小于触发值 12bit:接收流延迟触发连续状态(FLOWDEL) 1-RX FIFO的数据量大于或者等于FDEL 0-RX FIFO的数据量小于FDEL 11bit:发送状态机激活(TACTIVE) 1-激活 0-未激活 10bit:接收状态机激活(RACTIVE) 1-激活 0-未激活 9~5bit:保留(只读) 4bit:发送FIFO满连续状态(TXFULL) 1-TX FIFO满 0-TX FIFO未满 3bit:发送FIFO空连续状态(TXEMPTY) 1-TX FIFO空 0-TX FIFO非空 2bit:接收FIFO满连续状态(RXFULL) 1-RX FIFO满 0-RX FIFO未满 1bit:接收FIFO空连续状态(RXEMPTY) 1-RX FIFO空 0-RX FIFO非空 0bit:接收FIFO触发连续状态(RXOVR) 1-RX FIFO的数据量大于或等于触发值 0-RX FIFO的数据量小于触发值 |
XUARTPS_FIFO寄存器XUARTPS_FIFO_OFFSET (0x30U) Field Name | Bits | Type | Reset Value | Description | | | | | 31~8bit:保留(只读) 7~0bit:发送或者接收FIFO |
Baud_rate_divider_reg0寄存器Baud_rate_divider_reg0 (0x34U) baud_sample被分频成多少产生波特率 Field Name | Bits | Type | Reset Value | Description | | | | | 31~8bit:保留(只读) 7~0bit: 0~3:保留 4~255:用于波特率分频 |
Flow_delay_reg0寄存器Flow_delay_reg0 (0x38U)本实验用不到该寄存器只有在调制解调器控制寄存器的 FCM 字段中启用了自动流控制模式时,才使用流控制延迟寄存器。 当使能自动流控制模式时,该寄存器指定EMIOUARTxRTSN输出被取消置位的接收器FIFO级别。 EMIOUARTxRTSN 输出仅在填充水平降至低于 FDEL 的 4 倍以下时才会再次置位。 Tx_FIFO_trigger_level0寄存器Tx_FIFO_trigger_level0 (0x3CU) baud_sample被分频成多少产生波特率 Field Name | Bits | Type | Reset Value | Description | | | | | 31~6bit:保留(只读) 5~0bit: 0:禁用FIFO触发功能 1~63:设置FIFO触发的数据量 |
5 搭建SOC系统工程 本实验无须搭建新工程,可运行于任意系统之上。若无可运行系统请参考“[米联客-XILINX-H3_CZ08_7100] LINUX基础篇连载-05 恢复出厂及固化至eMMC内系统”,重新制作系统。 6 程序分析 在Linux系统中,串口可以作为字符驱动调用,此处不再赘述字符驱动,若不熟悉请看第一章内容。 - #include <stdio.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <termios.h>
- int main(int argc, char **argv)
- {
- int fd = open("/dev/tty", O_RDWR | O_NOCTTY);
- if (fd < 0)
- {
- //打开串口失败,退出
- printf("open failed\n");
- return -1;
- }
- while (1)
- {
- unsigned char buffer[1024] = {0};
- int ret = read(fd, buffer, sizeof(buffer));
- if (ret > 0)
- {
- printf("Printf: %s", buffer);
- int n = write(fd, buffer, ret);
- if (n != ret)
- printf("send failed\n");
- if (buffer[0] == 81 || buffer[0] == 113)
- break;
- }
- else
- usleep(1000 * 50);
- }
- close(fd);
- return 0;
- }
复制代码行8,打开串口设备。 行16,使用while反复检测是否有输入。 行19,使用read函数读取串口数据。 行22,使用printf打印出收到的数据。 行24,使用串口输出收到的串口数据。 7 演示结果 将与资料对应的demo拷贝至sd卡文件系统的/home/uisrc/内。 弹出sd卡插入开发板。 SD2.0 启动 01 而模式开关为 ON OFF(7100 需要先将系统烧录进qspi,然后才能从qspi启动sd卡,“[米联客-XILINX-H3_CZ08_7100] LINUX基础篇连载-04 从vitis移植Ubuntu实现二次开发”) 将 PS 端串口线连接电脑,如果要使用 ssh 登录,将网口线同样连接至电脑,最后给开发板通电。每次重新上电,需要重新插拔 PS 串口,否则会登录失败。 登录板卡后,cd至demo的位置: 运行sudo ./psuart查看结果,root的密码为root: 输入一些字符测试,输入完毕按回车。这里输入了test作为测试,test输出了两遍,第一遍为printf输出,第二遍为串口输出。输入Q、q或者ctrl+c可退出程序。 若想自己编译,可使用gcc命令: 可以看到编译完多了一个文件,gcc编译的默认输出名称为a.out。 |