ZYNQ-UART串口中断测试

简介: ZYNQ-UART串口中断测试

学习内容


本文主要介绍关于ZYNQ芯片的串口中断功能,并编写相关读写测试代码,完成串口中断的读写测试。

开发环境


vivado 18.3&SDK,PYNQ-Z2开发板。

UART控制器


简介


UART控制器是一个全双工异步接收和发送,支持可编程波特率和I/O信号格式。 该控制器可实现奇偶校验自动生成和多主检测模式。UART操作由配置和模式寄存器控制。

FIFO、调制解调器信号和其他控制器功能的状态是使用状态、中断状态和调制解调器状态寄存器读取的。UART控制器有独立的RX和TX数据路径。每个路径包括一个64字节的FIFO。 控制器TX和RX FIFO中的数据进行串行化和反串行化,并包括一个模式开关,以支持RXD和TXD信号的各种环回配置。(RXD和TXD使用模式:正常模式、各种环回诊断测试模式)

FIFO中断状态位支持轮询或中断驱动的处理程序。 软件使用RX和TX数据端口寄存器读取和写入数据字节。当在类似于调制解调器

应用程序中使用UART时,调制解调器控制模块检测并生成调制解调器握手信号,并且还根据握手协议控制接收和发送器路径。(调制解调器控制信号:CTS, RTS, DSR, DTR, RI和DCD只有在EMIO接口可用

系统框图


UART控制器的系统框图如下图所示:

image.png

在图中,SLCR寄存器(系统级控制寄存器(SLCR)由用于控制PS行为的各种寄存器组成。这些寄存器可以通过中央互连使用加载和存储指令访问。)包括控制位用于UART时钟,复位和MIO-EMIO信号映射。软件可以使用APB 32位的从接口访问UART控制器寄存器。每个控制器的IRQ(中断号为59,82)连接到PS中断控制器,并连接到PL。UART控制器由参考时钟( UART REF_CLK)驱动,同时控制器也需要连接APB 总线时钟( CPU_1x clock), UART REF_CLK 和 CPU_1x clock 都是来自于 PS 时钟子系统。

内部框图


UART控制器内部框图如下图所示。

image.png

由上图可知,UART控制器使用PS AXI interconnect 进行数据交互,通过APB Slave接口来接收PS端口的配置信息和一些数据信息。假设要发送数据,则系统先将发生的字符串缓存到TxFIFO下,然后经Transmitter模块实现并转串,如果工作在正常模式下,则数据之间接到MIO/EMIO引脚上,正常向接收设备发送;假设要接收其他设备传来的串口信息,则首先通过串口接收引脚接收串行数据,然后经过receiver模块实现串转并,转换过后存入到RxFIFO下,经过APB从接口传输到PS端,即可对接收数据进行处理。


通过控制状态寄存器可以对UART控制器进行控制,而这些引脚只能连接到EMIO。UART控制器内部包括一个中断模块,所以可以和其他模块一样正常接收到来自系统的中断信号。对于UART的参考时钟在控制器内部首先进行了一个八分频,接着再产生波特率时钟。

Transmit FIFO


Transmit FIFO (Tx FIFO)存储由APB从接口写入的数据,发送模块收到FIFO中的数据后删除FIFO的数据然后进行串并转换,并装入其移位寄存器。TxFIFO的最大数据宽度为8位。数据通过写入TxFIFO寄存器加载到TxFIFO。

当数据加载到TxFIFO时,TxFIFO空标志将被清除并保持在这个Low状态,直到TxFIFO中的最后一个字符被删除并加载到发送器移位寄存器中。TxFIFO满中断状态(TFULL)表明TxFIFO已经完全写满了,并且阻止数据被写入到TxFIFO中。如果对TxFIFO执行另一个APB写入操作,则触发溢出,写入数据不会加载到TxFIFO中。

发送 FIFO接近满标志(TNFULL)表明在FIFO中没有足够的空间来进行一次程序大小的写入,这是由模式寄存器的WSIZE位控制的。TxFIFO接近满标志(TNFULL)表示TxFIFO中只有字节空闲。

可以在TxFIFO填充级别上设置一个阈值触发器(TTRIG)。发射器触发寄存器可以用来设置这个值,这样当TxFIFO填充深度达到设定的阈值时触发可以设置。

Receiver FIFO


Receiver FIFO和Transmit FIFO类似。RxFIFO存储由接收器串行移位寄存器接收的数据。RxFIFO的最大数据宽度是8位。当数据加载到RxFIFO时,RxFIFO空标志被清除,并且这种状态保持为低,直到RxFIFO中的所有数据通过APB接口传输完毕。空标志重新置位为高,如果接着读FIFO的话,则会从空的RxFIFO读取返回0。

RxFIFO满状态(Chnl_int_sts_reg0 [RFUL]和Channel_sts_reg0 [RFUL]位)表明RxFIFO满了,阻止数据被加载到RxFIFO。同时也可以在RxFIFO上设置一个阈值触发器(RTRIG)。接收器触发级别寄存器(Rcvr_FIFO_trigger_level0)可以用来设置这个值,取值范围是1 ~ 63。

I / O模式切换


这里的模式切换即为内部框图中的 Mode Switch 模块,如下图所示。

image.png

该模式由mode_reg0 [CHMODE]寄存器设置控制,总共分为四种模式,分别

为:正常模式( Normal Mode)、自动回音模式( Automatic Echo Mode)、本地环回模式( Local Loopback Mode)和远程环回模式( Remote Loopback Mode)。

image.png

正常模式( Normal Mode) :用于标准UART操作,就是发送接收功能。

自动回音模式( Automatic Echo Mode) :Automatic Echo Mode模式在RxD上接收数据,模式开关将数据连接到接收端和UARTx_TxD。而PS的TXD端口的数据无法正常发出。

本地环回模式( Local Loopback Mode) :本地环回模式不连接到RxD或TxD引脚,而是直接把PS发送的数据传输到PS的接收端。

远程环回模式( Remote Loopback Mode) :远程环回模式将RxD信号连接到TxD信号。在这种模式下,控制器不能在TxD上发送任何内容,也不能在RxD上接收任何内容。

UART启动顺序


UART 的启动顺序如下:

  1. 复位UART控制器,在PS进行系统复位时进行控制器的复位。
  2. 配置 IO 引脚信号。
  3. 配置 UART 参考时钟(可以保护默认)。
  4. 配置控制器功能( UART 控制器初始化)。
  5. 配置中断,通过中断来管理 RxFIFO 和 TxFIFO。
  6. 配置串口模式控制(可选)。
  7. 管理发送和接收的数据,采用轮询或中断驱动处理两种方式。

配置控制器功能步骤


在UART控制器中,控制器可以配置字符帧、波特率、FIFO触发级别、Rx超时机制,并使能控制器。所有步骤都必须在复位之后。

配置控制器的功能步骤如下:

  1. 配置 UART 数据帧格式。 数据位长度、停止位、校验方式、 IO 模式等。
  2. 设置波特率。
  3. 设置 RxFIFO 触发器等级,可以选择启用或禁用该功能。
  4. 使能 UART 控制器。
  5. 配置接收器的超时机制,可以选择启用或禁用该功能。

发送数据步骤


编写软件程序时,可以通过使用轮训和中断的方式控制RxFIFO和TxFIFO中的数据流。

使用轮询方式发送数据顺序


  1. 检查TxFIFO是否为空。直到uart.Channel sts rego[TEMPTY] =1,执行后续步骤。
  2. 用数据填充TxFIFO。向uart.TX_RX_FIFO0寄存器写入64字节的数据。
  3. 向TxFIFO写入数据。有两种方法:方法一: 可以等待 TxFIFO 为空之后再写入 64 个字节,即执行第 2 步;方法一: 可以检测 TxFIFO 是否写满,即不停的读取 TFUL 标志和写单个字节的数据。

使用中断方法发送数据的顺序


  1. 禁用 TxFIFO 空状态中断。
  2. 写入数据到TxFIFO中。
  3. 检测TxFIFO是否还有足够的空间容纳数据。
  4. 重复2和3操作。
  5. 使能中断。
  1. 等待TxFIFO为空,然后从步骤 1 重新开始。

接收数据步骤


使用轮询方式发送数据顺序


  1. 等待RxFIFO被填满到触发器级别。
  2. 从RxFIFO读取数据。
  3. 重复步骤2,直到FIFO为空。
  4. 设置Rx超时中断状态位时清除。

使用中断方法发送数据顺序


  1. 使能中断。
  2. 等待RxFIFO被填满到触发级别或Rx超时。
  3. 从RxFIFO读取数据。
  4. 重复步骤2和3,直到FIFO为空。
  1. 如果设置了中断状态位,则清除中断状态位。

系统框图


这里仅仅使用了UART部分,所以可以利用前文的helloworld工程,不需要进行特殊的配置。通过串口的中断功能把发送的数据再接收到PS端进行一个回环显示。

image.png

硬件平台搭建


新建工程,创建 block design。添加ZYNQ7 ip,根据本次工程需要对IP进行配置。勾选本次工程使用的uart资源

image.png

将ZYNQ无用资源进行取消勾选:

image.png

image.png

硬件系统构建完成如下:

image.png

然后我们进行generate output product 然后生成HDL封装。这里只用到了UART,是MIO引脚,所以不需要进行管脚分配。点击导出硬件资源(可以不包含bit流文件,因为只用到了PS资源),接着launch SDK。

SDK软件部分


打开SDK后,新建application project。

在system.mss中可以打开相关参考文档辅助设计。

image.png

这里使用串口中断可以参考赛灵思提供的例程代码进行修改设计:

image.png

这里导入uart_intr_example例程模板在main.c中输入以下代码:

#include "xparameters.h"
#include "stdio.h"
#include "xuartps.h"
#include "xuartps_hw.h"
#include "xscugic.h"
#define UART_0_DEVICE_ID XPAR_PS7_UART_0_DEVICE_ID
#define INTR_DEVICE_ID    XPAR_SCUGIC_SINGLE_DEVICE_ID
#define UART_INT_IRQ_ID   XPAR_XUARTPS_0_INTR
XUartPs Uart_Inst;
XScuGic ScuGic_Inst;
int uart_init();
void intr_init(XScuGic *intr, XUartPs *uart);
void UartIntr_Handler(void *call_back_ref);
int main(){
  //uart初试化函数
  uart_init();
  xil_printf("intr\n");
  //中断初始化
  intr_init(&ScuGic_Inst,&Uart_Inst);
  while(1);
  return 0;
}
//uart初始化
int uart_init(){
  XUartPs_Config *UartPs_Cfg;
  int Status;
  //查找配置信息
  UartPs_Cfg= XUartPs_LookupConfig(UART_0_DEVICE_ID);
  //对uart控制器进行初始化
  XUartPs_CfgInitialize(&Uart_Inst, UartPs_Cfg, UartPs_Cfg->BaseAddress);
  //检测硬件搭建是否正确
  Status = XUartPs_SelfTest(&Uart_Inst);
  if (Status != XST_SUCCESS) {
    return XST_FAILURE;
  }
  //设置波特率
  XUartPs_SetBaudRate(&Uart_Inst,115200);
  //设置RXFIFO触发阈值
  XUartPs_SetFifoThreshold(&Uart_Inst,1);
  //设置操作模式
  XUartPs_SetOperMode(&Uart_Inst, XUARTPS_OPER_MODE_NORMAL);
  return XST_SUCCESS;
}
//中断初始化
void intr_init(XScuGic *intr, XUartPs *uart){
  XScuGic_Config *IntcConfig;
  //中断控制器初始化
  IntcConfig = XScuGic_LookupConfig(INTR_DEVICE_ID);
  XScuGic_CfgInitialize(intr,IntcConfig,IntcConfig->CpuBaseAddress);
  Xil_ExceptionInit();
  Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
          (Xil_ExceptionHandler) XScuGic_InterruptHandler,
          (void *)intr);
  Xil_ExceptionEnable();
  //为中断设置中断处理函数
  XScuGic_Connect(intr, UART_INT_IRQ_ID,
            (Xil_ExceptionHandler) UartIntr_Handler,
            (void *) uart);
  //设置触发类型
  XUartPs_SetInterruptMask(uart, XUARTPS_IXR_RXOVR);
  //使能中断
  XScuGic_Enable(intr, UART_INT_IRQ_ID);
}
//中断处理函数
void UartIntr_Handler(void *call_back_ref){
  XUartPs *uartinst =(XUartPs *)call_back_ref;
  u32 read_data = 0;
  u32 intr_status;
  //读取中断ID寄存器
  intr_status = XUartPs_ReadReg(uartinst->Config.BaseAddress,
      XUARTPS_IMR_OFFSET);//读取掩码
  intr_status &= XUartPs_ReadReg(uartinst->Config.BaseAddress,
      XUARTPS_ISR_OFFSET);//读取状态
  if(intr_status & (u32)XUARTPS_IXR_RXOVR){
    read_data = XUartPs_RecvByte(XPAR_PS7_UART_0_BASEADDR);//接收发送的字节
    XUartPs_WriteReg(uartinst->Config.BaseAddress,XUARTPS_ISR_OFFSET,
        XUARTPS_IXR_RXOVR);//清除中断状态
  }
  //设置发送
  XUartPs_SendByte(XPAR_PS7_UART_0_BASEADDR,read_data);
}

部分代码讲解


在整体的代码设计中,代码思路如下:

  1. 初始化UART控制器
  2. 初始化UART中断
  3. 编写中断服务函数

对于初始化UART部分,在#include "xuartps.h" 头文件中可以找到很多配置的函数,调用即可对uart的波特率,中断触发阈值等参数进行设置。

对于中断的配置可以类比GPIO的中断配置函数,先在初始化SGIC,然后进行异常初始化,完成注册异常并使能,接着需要连接SGIC和UART,最后设置中断类型并使能完成中断整体操作配置。

在中断服务函数中,实现的功能为回环读写,所以要在中断函数中进行检测中断类型,当进入相应的中断时进行数据的读取,读取到上位机的发送数据,然后清除中断标志,最后把读到的数据进行发送。

Reference


  1. 正点原子视频教程
  2. UG585
目录
相关文章
|
6月前
com串口通信测试代码
com串口通信测试代码
55 0
|
6月前
|
移动开发 开发者
LabVIEW或MAX下的VISA测试面板中串口无法工作
LabVIEW或MAX下的VISA测试面板中串口无法工作
180 1
LabVIEW或MAX下的VISA测试面板中串口无法工作
|
6月前
|
传感器 Linux 测试技术
xenomai 在X86平台下中断响应时间测试
该文讨论了实时操作系统中断响应时间的重要性,并介绍了x86中断机制和Xenomai的中断管理,包括硬件中断和虚拟中断的处理。Xenomai通过I-Pipe确保实时性,中断优先级高的Xenomai先处理中断。文中还提到了中断响应时间的测试设计,分别针对I-Pipe内核间虚拟中断和硬件中断进行了测试,并给出了在不同负载下的测试结果。
146 0
xenomai 在X86平台下中断响应时间测试
|
Linux 测试技术 Windows
可编程 USB 转串口适配器开发板应用于电子设备开发测试
可编程 USB 转串口适配器开发板应用于电子设备开发测试
可编程 USB 转串口适配器开发板应用于电子设备开发测试
|
6月前
|
监控 物联网 Linux
python测试串口最大通信速率
【4月更文挑战第5天】
155 3
|
6月前
|
Ubuntu Linux Windows
串口模拟工具实现测试
串口模拟工具实现测试
157 0
【单片机期中测试】13.串口通信的应用(2)—— 超声波通过串口返回数据
【单片机期中测试】13.串口通信的应用(2)—— 超声波通过串口返回数据
103 0
|
监控 Java 测试技术
我的小工具,java版串口读写卡测试工具
我的小工具,java版串口读写卡测试工具
|
XML 传感器 数据格式
可编程 USB 转串口适配器开发板主要开发测试作用
上面写的东西不少,其实这个模块用法特别简单,拿到套件和专门的工具软件后一分钟都不需要就完全明白了,如果想编写自己的xml驱动,随便打开一个照葫芦画瓢,然后另存就行。
|
9天前
|
JSON Java 测试技术
SpringCloud2023实战之接口服务测试工具SpringBootTest
SpringBootTest同时集成了JUnit Jupiter、AssertJ、Hamcrest测试辅助库,使得更容易编写但愿测试代码。
39 3