目录
1、前言
2、Vivado硬件工程
3、Xilinx SDK软件工程
4、测试结果
在使用zynq芯片的时候都会遇到PS端的2个串口不够用的情况,因此本文讲述了利用IP核在zynq7020芯片的PL端扩展一个串口。
硬件:黑金7020开发板
环境:Vivado2017
1)、新建一个zynq7020的工程,并在Block Design中添加串口IP核AXI UART16550,如下图所示。
2)、设置ZYNQ里面的参数设置。
添加PS端调试串口1
开启PL端中断
设置对应的内存型号
3)、自动连线完成之后,将AXI UART16550上的中断引脚连接到ZYNQ上,并且引出AXI UART16550上的接收和发送引脚
4)、设置好引脚约束,在生成bit文件,至此PL端设置完成,打开SDK软件。
1)、新建一个空白工程
2)、点击system.mss导入官方给的例程
从工程中可以看见我已经导入了两个工程,分别是发送Hello world和中断的例程。Hello world的简单一些,看一下就知道了,这里主要说明一下中断的例程。
3)、打开中断的例程,这个例程有个地方会报错,打开"xparameters.h"中找到XPAR_FABRIC_AXI_UART16550_0_IP2INTC_IRPT_INTR,替换报错的地方就行了,修改好的如下图所示。
4)、官方的代码有很多是我们不需要的,简单修改官方的代码。
/****************************************************************************** * * Copyright (C) 2002 - 2015 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ /******************************************************************************/ /** * * @file xuartns550_intr_example.c * * This file contains a design example using the UART 16450/16550 driver * (XUartNs550) and hardware device using interrupt mode. * * @note * * <pre> * MODIFICATION HISTORY: * * Ver Who Date Changes * ----- ---- -------- ---------------------------------------------------------- * 1.00b jhl 02/13/02 First release * 1.00b sv 06/08/05 Minor changes to comply to Doxygen and coding guidelines * 1.01a sv 05/08/06 Minor changes for supporting Test App Interrupt examples * 2.00a ktn 10/20/09 Updated to use HAL processor APIs and minor modifications * as per coding guidelines. * 2.01a ssb 01/11/01 Updated the example to be used with the SCUGIC in * Zynq. * 3.2 adk 15/10/14 Clear the global counters.If multiple instance of ip is * present in the h/w design without clearing these counters * will result undefined behaviour for the second ip * instance while running the peripheral tests. * 3.4 ms 01/23/17 Added xil_printf statement in main function to * ensure that "Successfully ran" and "Failed" strings * are available in all examples. This is a fix for * CR-965028. * </pre> ******************************************************************************/ /***************************** Include Files **********************************/ #include "xparameters.h" #include "xuartns550.h" #include "xil_exception.h" #ifdef XPAR_INTC_0_DEVICE_ID #include "xintc.h" #include <stdio.h> #else #include "xscugic.h" #include "xil_printf.h" #endif /************************** Constant Definitions ******************************/ /* * The following constants map to the XPAR parameters created in the * xparameters.h file. They are defined here such that a user can easily * change all the needed parameters in one place. */ #ifndef TESTAPP_GEN #define UART_DEVICE_ID XPAR_UARTNS550_0_DEVICE_ID #define UART_IRPT_INTR XPAR_FABRIC_AXI_UART16550_0_IP2INTC_IRPT_INTR #ifdef XPAR_INTC_0_DEVICE_ID #define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID #else #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID #endif /* XPAR_INTC_0_DEVICE_ID */ #endif /* TESTAPP_GEN */ /* * The following constant controls the length of the buffers to be sent * and received with the UART. */ #define TEST_BUFFER_SIZE 10 /**************************** Type Definitions ********************************/ #ifdef XPAR_INTC_0_DEVICE_ID #define INTC XIntc #define INTC_HANDLER XIntc_InterruptHandler #else #define INTC XScuGic #define INTC_HANDLER XScuGic_InterruptHandler #endif /* XPAR_INTC_0_DEVICE_ID */ /************************** Function Prototypes *******************************/ int UartNs550IntrExample(INTC *IntcInstancePtr, XUartNs550 *UartInstancePtr, u16 UartDeviceId, u16 UartIntrId); void UartNs550IntrHandler(void *CallBackRef, u32 Event, unsigned int EventData); static int UartNs550SetupIntrSystem(INTC *IntcInstancePtr, XUartNs550 *UartInstancePtr, u16 UartIntrId); static void UartNs550DisableIntrSystem(INTC *IntcInstancePtr, u16 UartIntrId); /************************** Variable Definitions ******************************/ #ifndef TESTAPP_GEN XUartNs550 UartNs550Instance; /* Instance of the UART Device */ INTC IntcInstance; /* Instance of the Interrupt Controller */ #endif /* * The following buffers are used in this example to send and receive data * with the UART. */ u8 SendBuffer[TEST_BUFFER_SIZE]; /* Buffer for Transmitting Data */ u8 RecvBuffer[1]; /* Buffer for Receiving Data */ /******************************************************************************/ /** * * Main function to call the UartNs550 interrupt example. * * @param None. * * @return XST_SUCCESS if successful, otherwise XST_FAILURE. * * @note None. * *******************************************************************************/ #ifndef TESTAPP_GEN int main(void) { u16 Options; /* * Initialize the UART driver so that it's ready to use. */ XUartNs550_Initialize(&UartNs550Instance, UART_DEVICE_ID); /* * Perform a self-test to ensure that the hardware was built correctly. */ XUartNs550_SelfTest(&UartNs550Instance); /* * Connect the UART to the interrupt subsystem such that interrupts can * occur. This function is application specific. */ UartNs550SetupIntrSystem(&IntcInstance, &UartNs550Instance, UART_IRPT_INTR); /* * Setup the handlers for the UART that will be called from the * interrupt context when data has been sent and received, specify a * pointer to the UART driver instance as the callback reference so * the handlers are able to access the instance data. */ XUartNs550_SetHandler(&UartNs550Instance, UartNs550IntrHandler, &UartNs550Instance); Options = XUN_OPTION_DATA_INTR | XUN_OPTION_FIFOS_ENABLE |XUN_OPTION_RESET_TX_FIFO; XUartNs550_SetOptions(&UartNs550Instance, Options); while (1) { } // /* // * Disable the UartNs550 interrupt. // */ // UartNs550DisableIntrSystem(IntcInstancePtr, UartIntrId); } #endif /*****************************************************************************/ /** * * This function is the handler which performs processing to handle data events * from the UartNs550. It is called from an interrupt context such that the * amount of processing performed should be minimized. * * This handler provides an example of how to handle data for the UART and * is application specific. * * @param CallBackRef contains a callback reference from the driver, * in thiscase it is the instance pointer for the UART driver. * @param Event contains the specific kind of event that has occurred. * @param EventData contains the number of bytes sent or received for sent * and receive events. * * @return None. * * @note None. * *******************************************************************************/ void UartNs550IntrHandler(void *CallBackRef, u32 Event, unsigned int EventData) { u8 Errors; XUartNs550 *UartNs550Ptr = (XUartNs550 *)CallBackRef; /* * All of the data has been sent. */ if (Event == XUN_EVENT_SENT_DATA) { xil_printf("send \r\n"); } /* * All of the data has been received. */ if (Event == XUN_EVENT_RECV_DATA) { XUartNs550_Recv(&UartNs550Instance, RecvBuffer, 1); //重新接收一下 xil_printf("recive: %s \r\n",RecvBuffer); } /* * Data was received, but not the expected number of bytes, a * timeout just indicates the data stopped for 4 character times. */ if (Event == XUN_EVENT_RECV_TIMEOUT) { xil_printf("timeout \r\n"); } } /******************************************************************************/ /** * * This function setups the interrupt system such that interrupts can occur * for the UART. This function is application specific since the actual * system may or may not have an interrupt controller. The UART could be * directly connected to a processor without an interrupt controller. The * user should modify this function to fit the application. * * @param IntcInstancePtr is a pointer to the instance of the Interrupt * Controller. * @param UartInstancePtr is a pointer to the instance of the UART. * @param UartIntrId is the interrupt Id and is typically * XPAR_<INTC_instance>_<UARTNS550_instance>_VEC_ID value from * xparameters.h. * * @return XST_SUCCESS if successful, otherwise XST_FAILURE. * * @note None. * *******************************************************************************/ static int UartNs550SetupIntrSystem(INTC *IntcInstancePtr, XUartNs550 *UartInstancePtr, u16 UartIntrId) { int Status; #ifdef XPAR_INTC_0_DEVICE_ID #ifndef TESTAPP_GEN /* * Initialize the interrupt controller driver so that it is ready * to use. */ Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID); if (Status != XST_SUCCESS) { return XST_FAILURE; } #endif /* TESTAPP_GEN */ /* * Connect a device driver handler that will be called when an interrupt * for the device occurs, the device driver handler performs the * specific interrupt processing for the device. */ Status = XIntc_Connect(IntcInstancePtr, UartIntrId, (XInterruptHandler)XUartNs550_InterruptHandler, (void *)UartInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } #ifndef TESTAPP_GEN /* * Start the interrupt controller such that interrupts are enabled for * all devices that cause interrupts, specific real mode so that * the UART can cause interrupts thru the interrupt controller. */ Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE); if (Status != XST_SUCCESS) { return XST_FAILURE; } #endif /* TESTAPP_GEN */ /* * Enable the interrupt for the UartNs550. */ XIntc_Enable(IntcInstancePtr, UartIntrId); #else #ifndef TESTAPP_GEN XScuGic_Config *IntcConfig; /* * Initialize the interrupt controller driver so that it is ready to * use. */ IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); if (NULL == IntcConfig) { return XST_FAILURE; } Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } #endif /* TESTAPP_GEN */ XScuGic_SetPriorityTriggerType(IntcInstancePtr, UartIntrId, 0xA0, 0x3); /* * Connect the interrupt handler that will be called when an * interrupt occurs for the device. */ Status = XScuGic_Connect(IntcInstancePtr, UartIntrId, (Xil_ExceptionHandler)XUartNs550_InterruptHandler, UartInstancePtr); if (Status != XST_SUCCESS) { return Status; } /* * Enable the interrupt for the Timer device. */ XScuGic_Enable(IntcInstancePtr, UartIntrId); #endif /* XPAR_INTC_0_DEVICE_ID */ #ifndef TESTAPP_GEN /* * Initialize the exception table. */ Xil_ExceptionInit(); /* * Register the interrupt controller handler with the exception table. */ Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)INTC_HANDLER, IntcInstancePtr); /* * Enable exceptions. */ Xil_ExceptionEnable(); #endif /* TESTAPP_GEN */ return XST_SUCCESS; } /*****************************************************************************/ /** * * This function disables the interrupts that occur for the UartNs550 device. * * @param IntcInstancePtr is the pointer to the instance of the Interrupt * Controller. * @param UartIntrId is the interrupt Id and is typically * XPAR_<INTC_instance>_<UARTNS550_instance>_VEC_ID * value from xparameters.h. * * @return None. * * @note None. * ******************************************************************************/ static void UartNs550DisableIntrSystem(INTC *IntcInstancePtr, u16 UartIntrId) { /* * Disconnect and disable the interrupt for the UartNs550 device. */ #ifdef XPAR_INTC_0_DEVICE_ID XIntc_Disconnect(IntcInstancePtr, UartIntrId); #else XScuGic_Disable(IntcInstancePtr, UartIntrId); XScuGic_Disconnect(IntcInstancePtr, UartIntrId); #endif }
左边通过上位机发送”112233“到ZYNQ,ZYNQ接收到之后通过PS端的串口打印出来,如右边所示。