Xilinx Vitis中XUartPs_IsReceiveData检测UART接收数据失效问题
使用Xilinx Vitis SDK开发时,调用内置UART接口函数XUartPs_IsReceiveData判断UART端口是否存在可读取的有效字节,封装了UartHasMessage函数,预期逻辑为存在待读字节返回1,无待读字节返回0,实现代码如下:
u32 UartHasMessage(void){ if(XUartPs_IsReceiveData(&XUartPs_Main)){ return 1; } else{ return 0; } }
实际测试出现异常:即使UART端口存在待读取字节,该函数也始终返回false。单步调试时观测到:调用UartHasMessage()检测待读字节返回false,但紧接着执行UART字节读取函数,却能正确获取主机发送的有效字节。

对应测试代码片段:
u32 test = UartHasMessage(); UartGetByte(&HostReply);
API传参类型完全错误,且编译阶段未触发类型检查报错。XUartPs_IsReceiveData是Xilinx提供的底层寄存器级操作函数,函数原型为:
u32 XUartPs_IsReceiveData(u32 BaseAddress);
它的入参要求是UART外设的32位物理基地址,而非XUartPs类型的驱动实例结构体指针。
传入的&XUartPs_Main是驱动实例结构体在内存中的首地址,函数拿到这个值后会把它当作外设寄存器基地址去读取状态寄存器值,访问的是完全错误的内存位置,自然永远读不到正确的接收FIFO非空状态,始终返回false。
后续的UartGetByte能正常读取数据,是因为该函数(或其底层调用的XUartPs_Recv/XUartPs_RecvByte接口)是面向驱动实例的高层接口,会从传入的XUartPs_Main实例的配置结构体中读取正确的外设基地址访问寄存器,因此可以正常拿到接收FIFO中的数据。
如果工程没有开启严格编译告警,指针到32位整数的隐式转换不会触发编译报错,这也是这个问题没有在编译阶段被发现的原因。
修改UartHasMessage的传参,给XUartPs_IsReceiveData传入正确的外设基地址即可:
u32 UartHasMessage(void){ // 从初始化完成的驱动实例中取出正确的UART外设基地址 if(XUartPs_IsReceiveData(XUartPs_Main.Config.BaseAddress)){ return 1; } return 0; }
如果不想直接操作底层寄存器级API,也可以改用面向实例的接口判断接收FIFO状态,例如通过XUartPs_GetStatus(&XUartPs_Main)读取状态寄存器后,判断XUARTPS_SR_RXEMPTY标志位是否为0,这种写法传参是驱动实例指针,不容易出现传参错误。
内容的提问来源于stack exchange,提问作者29belgrade29

