[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_SDK入门篇连载-20 PL UART-Lite实验

文档创建者:FPGA课程
浏览次数:138
最后更新:2024-09-27
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-SOC » 1_SDK应用方案(仅旗舰型号) » 1-SDK基础入门方案
本帖最后由 FPGA课程 于 2024-9-27 16:24 编辑

​ 软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!



1概述
工业场合RS232/RS422/RS485这种低速接口往往大量实用,但是对于ARM一般只能支持2个PS串口,如果需要更多的串口扩展起来就比较困难了。但是对于SOC来说,通过AXI-UART就能非常方便扩展串口。理论上,只要FPGA的资源够用,可以扩展任意路串口。
本文不再对UART串口通信协议做介绍,如果有不清楚的读者,可以阅读前面的实验“PS UART串口通信”。
本文实验目的:
1:通过阅读pg142-axi-uartlite.pdf熟悉AXI-UartLite控制器的硬件资源(配套工程的soc_prj/06_doc路径)
2:通过VIVADO搭建axi-uartlite的SOC工程
3:使用VITIS-SDK编写axi-uartlite测试程序,实现类似PS-UART中断接收的环路测试程序
2系统框图
3ea52889190d4346b62a858dbffdc461.jpg
3AXI-UartLite IP概述
d5ba3bd928f5477fae646df0ff2b9aae.jpg
3.1特性
-AXI-Lite接口接到ZYNQ IP
-全双工模式
-16个字符的发送和接收fifo
-可配置的数据位宽5~8bits
-可配置奇偶校验或无校验
-波特率可配置
3.2寄存器概述
61da138bf9164d1cb61399ba86668b5a.jpg
1:RX FIFO寄存器(offset=0h)
d61dbb39d7134303ab1f19d3965aadc9.jpg
e1e6f3d5b13244b183dae8b560fb1ecc.jpg
2:TX FIFO寄存器(offset=04h)
079181a636084f348a3ae0abafa216d1.jpg
40791bb5112a45a0be49a5bae74644cd.jpg
3:CTRL_REG控制寄存器(offset=0CH)
658214561f094ea79ad55e7bd82f4107.jpg
275b26ead44e41f3993b8272e8d130cb.jpg
4:STAT_REG控制寄存器(offset=08H)
f5b371114d2941d88d8bd012860f81f8.jpg
b4596683f0f74807941d0c3ef23abc85.jpg
4硬件电路分析
开发板上有2个串口一个接入到PS的ARM;另外一个接入到PL的FPGA,本实验使用接入到ARM的串口
配套工程的FPGA PIN脚定义路径为soc_prj/uisrc/04_pin/ fpga_pin.xdc。
6b4f2e456e344bd88604f58399bf4d6a.jpg
5搭建SOC系统工程
详细的搭建过程这里不再重复,对于初学读者如果还不清楚如何创建SOC工程的,请学习“01Vitis Soc开发入门”这篇文章。
5.1SOC系统工程
349eb4e871484bdfb3f5177ab5d1ad21.jpg
1:中断设置
3aabe5ea90e14235b845bfcb9eab9ae9.jpg
2:设置GP Master接口
3aa72534273949228e78b0fe8d14fd67.jpg
3:设置复位输出
1569bb2007804a458d96e4bfe9f20943.jpg
4:设置PL时钟
22d1b1081f1f4d3eaebe5379ac35795f.jpg
5:UART-Lite IP
a73fcb252eb04531b323d160cb7eb663.jpg
5.2设置AXI外设地址分配
只要添加的AXI总线外设都要正确分配地址,这一步不能遗漏。
b87dc50d453947c987d256ae45a19f48.jpg
5.3编译并导出平台文件
以下步骤简写,有不清楚的看第一篇文章。
1:单击Block文件à右键àGenerate the Output ProductsàGlobalàGenerate。
2:单击Block文件à右键à Create a HDL wrapper(生成HDL顶层文件)àLet vivado manager wrapper and auto-update(自动更新)。
3:添加配套工程路径下uisrc/04_pin/fpga_pin.xdc约束文件
4:生成Bit文件。
5:导出到硬件: FileàExport HardwareàInclude bitstream
6:导出完成后,对应工程路径的soc_hw路径下有硬件平台文件:system_wrapper.xsa的文件。根据硬件平台文件system_wrapper.xsa来创建需要Platform平台。
fe75cac854914b06b84610a31cd3ac56.jpg
6搭建Vitis-sdk工程
创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。
6.1创建SDK Platform工程
890a429dcb9540609df2e157e54f4722.jpg
右击soc_base编译,编译的时间可能会有点长
6.2创建APP工程
a5cfa0338b2449eca3a2df667d192e5b.jpg
7程序分析
7.1uartlite_pl_intr.c主程序
  1. #include "sys_intr.h"
  2. #include "uartlite_pl_intr.h"

  3. void init_intr_sys(void)
  4. {
  5.         Init_Intr_System(&Intc);//初始化全局中断
  6.         UartLite_Init(&UartLiteInst,UARTLITE_DEVICE_ID); //初始化串口
  7.         UartLite_setup_IntrSystem(&Intc, &UartLiteInst, UARTLITE_IRPT_INTR); //初始化串口中断
  8.         Setup_Intr_Exception(&Intc);
  9. }

  10. int main(void)
  11. {
  12.         init_intr_sys();
  13.         XUartLite_Recv(&UartLiteInst, RecvBuffer, UART_BUFFER_SIZE); //首先启动一次接收
  14.     while(1);
  15.         return 0;
  16. }
复制代码

主程序中,首先对中断系统以及PL的UART中断进行初始化,然后启动一次100个字节的接收。这主要是为了启动传输,如果单次传输的数据可能大于100可以把buf设置大一些。当FIFO有数据就会产生中断。
7.2uartlite_pl_intr.c程序
  1. #include "uartlite_pl_intr.h"

  2. u8 *SendBuffer = (void*)0x08000000;
  3. u8 *RecvBuffer = (void*)0x08100000;
  4. volatile int TotalSentCount;
  5. volatile int TotalRecvCount;

  6. static void UartLiteSendHandler(void *CallBackRef, unsigned int EventData);

  7. static void UartLiteRecvHandler(void *CallBackRef, unsigned int EventData);

  8. static void UartLiteSendHandler(void *CallBackRef, unsigned int EventData)
  9. {
  10.         //TotalSentCount = EventData;
  11. }

  12. //串口接收中断回调函数
  13. static void UartLiteRecvHandler(void *CallBackRef, unsigned int EventData)
  14. {
  15.         int i;
  16.         XUartLite * Uartpl = (XUartLite *) CallBackRef;
  17.         TotalRecvCount = EventData;

  18.         for(i=0;i < TotalRecvCount;i++)//把接收缓存中数据保存到发送缓存
  19.                 SendBuffer[i] = RecvBuffer[i];

  20.         XUartLite_Send(Uartpl, SendBuffer, TotalRecvCount); //启动发送
  21.         XUartLite_Recv(Uartpl, RecvBuffer, UART_BUFFER_SIZE); //再次启动接收
  22. }

  23. void UartLiteDisableIntrSystem(XScuGic *IntcInstancePtr,u16 UartLiteIntrId)
  24. {
  25.         XScuGic_Disable(IntcInstancePtr, UartLiteIntrId);
  26.         XScuGic_Disconnect(IntcInstancePtr, UartLiteIntrId);
  27. }

  28. //串口中断设置函数
  29. int UartLite_setup_IntrSystem(XScuGic * IntcInstancePtr , XUartLite *UartLiteInstPtr ,u16 UartLiteIntrId)
  30. {
  31.         int Status;

  32.         XScuGic_SetPriorityTriggerType(IntcInstancePtr, UartLiteIntrId,0xA0, 0x3); //设置串口PL中断

  33. //设置串口中断回调函数,会在XUartLite_InterruptHandler函数中继续产生回调,读者可以去看下
  34.         Status = XScuGic_Connect(IntcInstancePtr, UartLiteIntrId,(Xil_ExceptionHandler)XUartLite_InterruptHandler,UartLiteInstPtr);
  35.         if (Status != XST_SUCCESS) return Status;

  36.         XUartLite_EnableInterrupt(UartLiteInstPtr); //使能串口中断

  37.         XScuGic_Enable(IntcInstancePtr, UartLiteIntrId); //使能全局中断

  38.         return XST_SUCCESS;
  39. }

  40. int UartLite_Init(XUartLite *UartLiteInstPtr,u16 UartLiteDeviceId)
  41. {
  42.         int Status;

  43.         Status = XUartLite_Initialize(UartLiteInstPtr, UartLiteDeviceId);
  44.         if (Status != XST_SUCCESS) return XST_FAILURE;

  45. //设置串口的发送中断回调函数
  46.         XUartLite_SetSendHandler(UartLiteInstPtr, UartLiteSendHandler,UartLiteInstPtr);
  47. //设置串口的接收中断回调函数
  48.         XUartLite_SetRecvHandler(UartLiteInstPtr, UartLiteRecvHandler,UartLiteInstPtr);

  49.         return XST_SUCCESS;
  50. }
复制代码

1:XScuGic_SetPriorityTriggerType(XScuGicPtr, UartLiteIntrId,0xA0, 0x3)函数
这个函数用于设置PL中断的触发方式,
参数UartLiteIntrId =61代表了PL的第一个中断。
参数0xA0代表了中断的优先级,这个值越小代表拥有越高的优先级
参数0x3代表输入的PL信号上升沿触发中断
读者如果感兴趣可以继续追踪一下这个函数,看下如何设置中断寄存器的配置。
2:UartLiteRecvHandler(void *CallBackRef, unsigned int EventData)函数
当接收到数据后,把数据从接收buf复制到发送buf然后通过调用XUartLite_Send(Uartpl, SendBuffer, TotalRecvCount)函数把数据输送出去。这样我们就能验证发送给UART的数据和我们在串口控制台接收的数据是否一致。
3:XUartLite_Recv(Uartpl, RecvBuffer, UART_BUFFER_SIZE)函数

e9c55ba7a56140a0a713123af8cb7200.jpg
这个函数主要调用了XUartLite_ReceiveBuffer(InstancePtr)函数用于接收数据,这个函数中有如下代码,只要ReceivedCount < InstancePtr->ReceiveBuffer.RemainingBytes,并且判断到RX_FIFO中有数据,就会持续接收。
34c1fe9ab6dd4f8b8bebe78b854ad14b.jpg
4:XUartLite_Send(Uartpl, SendBuffer, TotalRecvCount)函数

3b803d68695b4c8f8be7af80c27a5d26.jpg
继续调用XUartLite_SendBuffer(InstancePtr)完成数据的发送, XUartLite_SendBuffer(InstancePtr)中有这么一段程序。这个程序中把buf中的数据写入到FIFO中。
0e186f90dcb24820a606bb877e4ede8b.jpg
5:XUartLite_InterruptHandler(XUartLite *InstancePtr)
5060175623724255a44ba41fa288963b.jpg
当接收FIFO变为非空或当发送FIFO变为空时产生中断。这里主要时接收FIFO有数据后产生中断。还记得我们前面设置接收长度为100吗?当第一次中断发生后,只要FIFO数据有效,就读继续FIFO,之后回调接收函数。
6:修改ReceiveDataHandler(XUartLite *InstancePtr)库函数
为了提高传输效率以及实现不定长度数据的接收,我们需要对XILINX 官方SDK的驱动做简单改进,把库函数uartlite_intr.c复制出来,放到我们代码路径下,这样整个程序会被有效于库函数调用。
22371624130141ca8f41489a3bdc2d07.jpg
8方案演示

8.1硬件准备
本实验需要用到 JTAG 下载器、USB 转串口外设,另外需要把核心板上的 2P 模式开关设置到 JTAG 模式,即 ON ON(注意新版本的 MLK_H3_CZ08-7100-MZ7100FC),支持 JTAG 模式,对于老版本的核心板,JTAG 调试的时候 一定要拔掉 TF 卡,并且设置模式开关为 OFF OFF)
5232718759bd46c588406a092ae7f608.jpg
8.2实验结果

3230bbcd187f45df9d3acd0b76720449.jpg

























您需要登录后才可以回帖 登录 | 立即注册

本版积分规则