IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> Zynq 【SDK裸机开发之PS】——串口接收缓存 -> 正文阅读

[嵌入式]Zynq 【SDK裸机开发之PS】——串口接收缓存

最近项目上在使用Zynq开发,也是第一次使用,期间会遇到各种各样的问题,属于Zynq本身问题的我会更新到我的另一篇博客《Zynq开发调试踩坑指南》中,这个版块将会陆续记录我自身在程序开发中的问题。

这次的问题是串口收数据问题,众所周知,我在一个月前就已经把串口调通了,收发试着也没啥问题。现在正在加一个通过串口远程升级的功能,也就是发的数据量大了,几十毫秒一帧数据,每一帧都有个一百多字节,然后就发现偶尔收的数据CRC校验对不上,仔细核对发现是少收了一个字节了。

我一开始是怀疑收数据的软件层驱动不对。毕竟整个软件层都是我自己写的,也没大量验证过,于是直接看串口收的memory中数据确实是少一个字节。

于是就怀疑串口线的问题,因为我现在跑的波特率是2Mbps,就单独拿串口线自发自收,倒是没有问题,说明硬件链路是没问题的。

这时候我就开始合理推测了,我看到丢字节的数组位置大概在第64这个位置,心里一个不成熟的想法就浮出水面。

我的Zynq串口收数据是使用FIFO溢出中断+超时中断的方式来获取数据的。超时中断大家都懂,stm32单片机里有这个概念。就是单个字节发完后多长时间内如果没有新的比特进来,就认为是超时了,这时候你想要的数据就都已经在缓存区里了。不同于stm32超时中断需要配置DMA,Zynq本身有FIFO,中断后直接读FIFO就可以了。但是这个FIFO是有空间限制的,收发缓存都只有64字节的大小。如果一次收到的数据不足64字节,倒是可以直接读完一帧,那如果收到的数据比64字节多呢?

这时候就需要FIFO溢出中断和超时中断一起配合使用了。我开辟一个空间,FIFO溢出后我把FIFO里的数据全部读走,再来数据在之前的空间上叠加数据,当产生超时中断时,则认为数据全部收完了。收完这些数据,再把数据放进环形缓存区,供再上一层软件调用。

以下是我串口中断的配置方法,注意,其中有一处是需要改动的,下面再提

/**
 * 配置超时中断。如果设置为N,则超时时间为N*4个比特时钟。
 * 例如115200波特率,每比特时钟为0.00000868s,即8.68us。
 * 如果N=8,则8.68us * 8 *4 = 277.76us
 */
XUartPs_SetRecvTimeout(&Uart0Ps, 40);
/*设置FIFO触发条件 */
/**
 * FIFO最大值64,此处的值是FIFO溢出的中断,也即RXOVR中断
 * 设置为最大值,和timout配合,如果接受字节小于64则在TOUT
 * 中断里读走数据。如果接受字节大于64字节,则首先由RXOVR
 * 中断接收前64字节数据,再由TOUT中断接受剩下的字节,两者配合。
 */
XUartPs_SetFifoThreshold(&Uart0Ps, 64 - 1) ;
/* 设置中断触发类型 */
XUartPs_SetInterruptMask(&Uart0Ps, XUARTPS_IXR_RXOVR | XUARTPS_IXR_TOUT);

可以看到上面我把缓存溢出的阈值设置为了64,也就是Zynq本身硬件上的最大串口缓存大小。

下面是我串口中断函数里做的操作,注意,recv函数我传递的参数是100,实际这个数填大点都没事,他只会返回缓存区有的数据长度,并不会溢出。

    //接收fifo满
    if (UartSrValue & XUARTPS_IXR_RXOVR)   /* check if receiver FIFO trigger */
    {
        u32 Len = XUartPs_Recv(UartInstPtr, Usart1DataRcevSture.RecvOffsetPtr, 100);
        Usart1DataRcevSture.RecvOffsetPtr += Len;
        
        /* clear trigger interrupt */
        UART_PS_INTR_CLEAR(UartInstPtr->Config.BaseAddress, XUARTPS_IXR_RXOVR);
    }
    //空闲中断
    else if (UartSrValue & XUARTPS_IXR_TOUT)
    {
        gpio_toggle(PL_LED_PIN);

        u32 Len = XUartPs_Recv(UartInstPtr, Usart1DataRcevSture.RecvOffsetPtr, 100);
        Usart1DataRcevSture.RecvOffsetPtr += Len;
  
        Usart1DataRcevSture.RecvDataLen = Usart1DataRcevSture.RecvOffsetPtr - &Usart1DataRcevSture.RecvBuffer[0];
        Usart1DataRcevSture.RecvOffsetPtr = &Usart1DataRcevSture.RecvBuffer[0];

        Usart1DataRcevSture.RecvFlg |= 0x01;
        /* clear trigger interrupt */
        UART_PS_INTR_CLEAR(UartInstPtr->Config.BaseAddress, XUARTPS_IXR_TOUT) ;
    }

这样的配置和接收方法本身没什么问题,但是当像我这样高速率通信,高频率发帧时候就会出现我上面说的,丢字节的情况。为什么会丢呢?恰恰就是因为我们把缓存区的大小设置的和硬件允许的缓存一样大,当我们产生FIFO溢出中断时,如果中断没来得及把所有数据读走,这时候再来一个新数据,他就没有地方可存放了,就会丢失字节。当然,这种事情发生的概率取决于硬件对中断的响应速度和程序执行中断的时间。

我现在波特率太高,则会更容易出现这样的问题。

XUartPs_SetFifoThreshold(&Uart0Ps, 50 - 1) ;

所以我们只需要更改这里,把FIFO溢出的阈值设置稍小一点,就可以给硬件留出一定的裕量了。

改完之后测试就再没出现过问题。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-29 12:18:17  更:2022-04-29 12:19:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 2:53:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码