首页 > 其他分享 >zynq串口接收超时加软件FIFO

zynq串口接收超时加软件FIFO

时间:2023-03-14 23:36:10浏览次数:41  
标签:obj uart FIFO 中断 zynq 串口 vu32

zynq的PS端裸跑时,其串口带有硬件FIFO,可大大降低中断频率。配合接收超时中断,可实现任意长度数据的非阻塞收发。

应用与驱动解耦

为实现驱动层与应用层解耦,不在中断服务函数中执行处理操作,串口的收发均使用软件环形队列解耦。

发送时:应用层将数据流写入发送队列,驱动层不是立刻发送,而是闲时从队列中取得,发出(发送至硬件FIFO)

接收时:驱动层将串口数据从硬件FIFO中取出,送入接收队列。应用层不是立刻处理,而是闲时从队列中取得,进行处理。

这样,驱动层中断服务函数仅操作队列,而应用层完全由主函数调用。

串口设备初始化

本来想使用Xilinx的固件库,可是他这库和STM32的固件库一样臃肿,串口本身非常简单,直接自己写了:

定义寄存器:(参考ug585)

 1 #pragma pack(1)
 2 typedef struct
 3 {
 4     vu32 CR; //使能收发
 5     vu32 MR; //停止位等
 6     vu32 IER; //写1中断使能
 7     vu32 IDR; //写1中断失能
 8     vu32 IMR; //中断是否使能
 9     vu32 ISR; //中断状态
10     vu32 BAUD;
11     vu32 RX_TO; //接收超时,单位4bit
12     vu32 RX_WM; //接收FIFO触发数
13     vu32 MODEMCR; 
14     vu32 MODEMSR;
15     vu32 SR; //状态寄存器:
16         //RXFIFO超限,RX空,RX满,TX空,TX满
17     vu32 FIFO; //最多64
18     vu32 BAUD_DIV;
19     vu32 FLOW_DELAY;
20     vu32 TX_TR; //发送FIFO触发数
21 } UART_TypeDef;
22 #pragma pack()
23 
24 #define UART0 ((UART_TypeDef*)0xe0000000)
25 #define UART1 ((UART_TypeDef*)0xe0001000)

然后就能用UART0这样的方式来访问寄存器了。然后初始化寄存器:

 1 void uart_initial(S_UART *obj,int b)
 2 {
 3     int irq=XPAR_XUARTPS_0_INTR;
 4     if(obj->uart==UART0)
 5     {
 6         Queue_ini(uart0_tx_buf,sizeof(uart0_tx_buf),&(obj->que_tx));
 7         Queue_ini(uart0_rx_buf,sizeof(uart0_rx_buf),&(obj->que_rx));
 8     }
 9     if(obj->uart==UART1)
10     {
11         Queue_ini(uart1_tx_buf,sizeof(uart1_tx_buf),&(obj->que_tx));
12         Queue_ini(uart1_rx_buf,sizeof(uart1_rx_buf),&(obj->que_rx));
13         irq=XPAR_XUARTPS_1_INTR;
14     }
15     obj->uart->BAUD_DIV=6; //默认15误差大
16     obj->uart->BAUD=100000000/b/(obj->uart->BAUD_DIV+1);
17     obj->uart->CR = 0x14; //使能收发
18     obj->uart->MR = 0x20; //n81
19     obj->uart->RX_TO = 200; //单位4bit
20     obj->uart->RX_WM = 60; //接收FIFO触发数
21     obj->uart->TX_TR = 60; //发送FIFO触发数
22 //    obj->uart->IER = (1<<8) | //RX_TO
23 //                    (0<<3) | //TX空
24 //                    (1<<0); //接收
25     obj->uart->IER = 0x101; //接收
26     obj->uart->IER = 0x101; //接收,需要写两遍
27 
28     irq_reg(irq,uart_irq,obj);
29     irq_enable(irq,1); //使能GIC中的串口中断
30 }

其中波特率为频率除以分频数再除以BAUD寄存器的值,为了保证精度,分频数需要选的比较小,默认为15(15+1分频),出115200波特率的时候误差比较大,无法正确接收数据。

收发FIFO触发数可以选择比较大,在不到FIFO触发数量时,通过接收超时机制来读数据。

其中IER不知道为啥需要写2遍,才能把接收超时的中断打开。

配置好串口寄存器后,通过GIC开串口中断。

串口发送流程

串口的发送是通过发送FIFO空中断实现的,机制与STM32的串口发送一样:

1、当无数据需要发送时,发送缓冲区空中断是关闭的。

2、当应用层需要发送数据时,所需发送的数据入队列,开发送缓冲区空中断,发送函数返回,不阻塞应用层调用。

3、由于发送缓冲区无数据,所以立刻进入中断,在中断中,从队列中取得数据,填入发送FIFO,直到FIFO接近满

4、中断返回

5、待FIFO中的数据发送完成,继续进发送空中断

6、中断中继续发送,或判断发送完成了,关闭发送空中断。

对比STM32的每个字节一个中断,zynq通过发送FIFO,可以实现60多字节一次中断,降低了中断频率。

发送函数:

 1 void uart_send(u8 *p,int n,S_UART *obj) //串口发送
 2 {
 3     int i;
 4     OS_CLOSE_INT;
 5     for(i=0;i<n;i++)
 6     {
 7         Queue_set_1(p[i],&(obj->que_tx));
 8     }
 9     obj->uart->IER = (1<<3);//TXE使能
10     OS_OPEN_INT;
11 }

在发送函数中,先关闭中断,进入临界区,才能操作队列。

串口接收流程

串口的接收使用FIFO触发中断,设置触发数量为60,则串口接收满60字节才会触发中断。若串口需接收的字节数少于60个,则不会触发此中断。因此,还需要串口接收超时中断实现短帧接收。

串口接收超时机制需要在串口中断结束时人工复位:CR 的 bit6置位,然后才会产生新的计时

串口接收超时中断使能会被串口发送空中断失能信号清除,所以要注意在中断中使能此中断。

最后不能忘了清除中断标志,否则会一直出不来。中断服务函数:

 1 void uart_irq(void *para)
 2 {
 3     u8 t;
 4     S_UART *obj=(S_UART*)para;
 5     //u32 irq=obj->uart->ISR;
 6     obj->uart->ISR=0xfff; //清中断
 7     obj->uart->ISR=0xfff; //清中断,为什么需要清两次?
 8 
 9     while((obj->uart->SR & 0x02)==0)//接收非空
10     {
11         t=(u8)(obj->uart->FIFO);
12         Queue_set_1(t,&(obj->que_rx));
13     }
14     if(obj->uart->SR & 8)//发送空TXE
15     {
16         while((obj->uart->SR & (1<<14))==0) //TX 没有接近满
17         {
18             if(Queue_get_1(&t,&(obj->que_tx))==0)
19             {
20                 obj->uart->FIFO=t;
21             }
22             else
23             {
24                 obj->uart->IDR = (1<<3);//TXE失能,会导致接收超时的中断失能
25                 obj->uart->IER |= (1<<8); //接收超时
26                 break;
27             }
28         }
29     }
30     obj->uart->CR = 0x14 | (1<<6); //使能收发,超时重置
31 }

应用层队列访问

在应用层访问队列时,需要通过临界区实现队列的互斥:

1 int get_que_data(u8 *p,Queue *q)
2 {
3     int rst=1;
4     OS_CLOSE_INT;
5     rst=Queue_get_1(p,q);
6     OS_OPEN_INT;
7     return rst;
8 }

在主循环中查询接收队列:

1 if(uart0.que_rx.dlen>0) //这个只读不用锁
2 {
3     while(get_que_data(&tt,&uart0.que_rx)==0)
4     {
5         rec_head(tt,&apptest_syn_obj);
6     }
7 }

 

标签:obj,uart,FIFO,中断,zynq,串口,vu32
From: https://www.cnblogs.com/yangzifb/p/17216883.html

相关文章

  • 华普物联WIFI串口服务器HP-ERSWIFI-T200关于智能水务解决方案
    水务数据在智慧水务应用项目中起着关键作用,无法及时准确地获取管网、水表等设备的状态及信息数据。智能水务可以对城市水源、供水管网进行实时监控;利用大数据对城市供水分......
  • 一个网络和串口全双工通信的c++库
    欢迎指正概述该库是https://github.com/ZLMediaKit/ZLToolKit和https://github.com/itas109/CSerialPort的集合这是一个通信库,包括网络和串口通信网络包括:TCP客户端......
  • 串口登录提示"Login incorrect"
    为了安全起见,需要给串口设置登录限制,即需要正确输入用户名和密码以后才能正常使用串口命令行。这里实现的方法是在/etc/inittab里面加入以下内容:ttyS3::respawn:/sbin/g......
  • 串口服务器接入阿里云MQTT协议的软件配置教程
    在之前的文章中我们了解到虚拟串口软件作为TCP客户端来结合串口服务器使用,这一期我们来看一下串口服务器怎样接入阿里云物模型。步骤详尽,一文读懂。1.阿里云MQTT环境配置......
  • 教你E103-W10串口转WiFi模块的无线透传应用教程
    以下为E103-W10作为softAP实现UDP串口服务器无线数据透传的举例,E103-W10作为station可同理实现透传。1.透传默认仅在TCP client单连接或UDP传输模式时,支持透传。1.......
  • 服务器-串口通信
    在服务器自动化测试开发中,服务器sut是如何跟host主机进行通信的?网络通信就不多说了,这里说说如何用串口实现将usbtoconsole线(一端usb口,插host,一端类似网口,接sut)接到su......
  • 汉源高科RS232数据光端机串口转光纤延长器收发器工业控制光猫光电转换器
    ......
  • RS485串口通讯!
     RS485接口组成的半双工网络,一般是两线制,多采用屏蔽双绞线传输,这种接线方式为总线式拓扑结构在同一总线上最多可以挂接32个结点。我们知道,最初数据是模拟信号输......
  • STM32串口通信
    STM32串口通信目录STM32串口通信串口常用寄存器串口配置的步骤和函数完整程序串口常用寄存器USART_SR 状态寄存器USART_DR数据寄存器USART_BRR波特率寄存器......
  • 串口通信原理详解232、422、485,入门必看!
    串口通信原理详解232、422、485,入门必看!混说Linux ​关注他 53人赞同了该文章本文介绍了串口通讯的基本概念、数据格式、通讯方式、典型的串口通讯......