ZYNQ PL 添加IP 串口UART AXI UART16550

目录

  • 开发环境、硬件
  • FPGA部分
  • SDK部分
  • PL串口相关寄存器

源代码下载

开发环境、硬件

vivado2018.3

正点原子领航者v2开发板
7020
ZYNQ PL 添加IP 串口UART AXI UART16550_第1张图片
使用管脚:COM2 对应PL的K14 M15

FPGA部分

open block design
添加PS部分
ZYNQ PL 添加IP 串口UART AXI UART16550_第2张图片
双击进行配置
ZYNQ PL 添加IP 串口UART AXI UART16550_第3张图片
配置PS串口
ZYNQ PL 添加IP 串口UART AXI UART16550_第4张图片
ZYNQ PL 添加IP 串口UART AXI UART16550_第5张图片
ZYNQ PL 添加IP 串口UART AXI UART16550_第6张图片
设置ddr内存
ZYNQ PL 添加IP 串口UART AXI UART16550_第7张图片
设置时钟,FCLK就是PL时钟
ZYNQ PL 添加IP 串口UART AXI UART16550_第8张图片
设置中断用于PL串口
ZYNQ PL 添加IP 串口UART AXI UART16550_第9张图片
添加uart IP核
ZYNQ PL 添加IP 串口UART AXI UART16550_第10张图片
Run Block Automation
ZYNQ PL 添加IP 串口UART AXI UART16550_第11张图片
Run Connection Automation
ZYNQ PL 添加IP 串口UART AXI UART16550_第12张图片
连接中断到IRQ_F2P(按照红线来)
ZYNQ PL 添加IP 串口UART AXI UART16550_第13张图片
uart ip点开加号,引出两个端口
ZYNQ PL 添加IP 串口UART AXI UART16550_第14张图片
搞好后是这个样子
ZYNQ PL 添加IP 串口UART AXI UART16550_第15张图片
编写XDC约束

set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
set_property -dict {PACKAGE_PIN K14 IOSTANDARD LVCMOS33} [get_ports sin_0]
set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports sout_0]

生成HDL Wrapper
ZYNQ PL 添加IP 串口UART AXI UART16550_第16张图片
然后生成Bit Stream
export->HARDWARE
ZYNQ PL 添加IP 串口UART AXI UART16550_第17张图片

SDK部分

新建一个project
查看其中后缀bsp的文件夹,system.mss为我们提供了范例
ZYNQ PL 添加IP 串口UART AXI UART16550_第18张图片
此处做修改
ZYNQ PL 添加IP 串口UART AXI UART16550_第19张图片
在串口中断函数中做修改,xuartns550_intr_example.c

/******************************************************************************
*
* 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
*
* 
* 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.
* 
******************************************************************************/
/***************************** Include Files **********************************/ #include "xparameters.h" #include "xuartns550.h" #include "xil_exception.h" #ifdef XPAR_INTC_0_DEVICE_ID #include "xintc.h" #include #else #include "xscugic.h" #include "xil_printf.h" #endif #include "sleep.h" /************************** 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) { print("running\r\n"); sleep(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); //重新接收一下 XUartNs550_Send(&UartNs550Instance, RecvBuffer, 1); xil_printf("r:%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___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___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 }

实现效果:发给com2的内容直接从com2返回,并打印到ps端串口
ZYNQ PL 添加IP 串口UART AXI UART16550_第20张图片

PL串口相关寄存器

在xparameters.h中
ZYNQ PL 添加IP 串口UART AXI UART16550_第21张图片


/* Definitions for driver UARTNS550 */
#define XPAR_XUARTNS550_NUM_INSTANCES 1U
#define XPAR_XUARTNS550_CLOCK_HZ 50000000U

/* Definitions for peripheral AXI_UART16550_0 */
#define XPAR_AXI_UART16550_0_DEVICE_ID 0U
#define XPAR_AXI_UART16550_0_BASEADDR 0x43C00000U
#define XPAR_AXI_UART16550_0_HIGHADDR 0x43C0FFFFU
#define XPAR_AXI_UART16550_0_CLOCK_FREQ_HZ 50000000U


/******************************************************************/

/* Canonical definitions for peripheral AXI_UART16550_0 */
#define XPAR_UARTNS550_0_DEVICE_ID 0U
#define XPAR_UARTNS550_0_BASEADDR 0x43C00000U
#define XPAR_UARTNS550_0_HIGHADDR 0x43C0FFFFU
#define XPAR_UARTNS550_0_CLOCK_FREQ_HZ XPAR_AXI_UART16550_0_CLOCK_FREQ_HZ

//中断寄存器
/* Definitions for Fabric interrupts connected to ps7_scugic_0 */
#define XPAR_FABRIC_AXI_UART16550_0_IP2INTC_IRPT_INTR 61U

/******************************************************************/

/* Canonical definitions for Fabric interrupts connected to ps7_scugic_0 */
#define XPAR_FABRIC_UARTNS550_0_VEC_ID XPAR_FABRIC_AXI_UART16550_0_IP2INTC_IRPT_INTR

/******************************************************************/

主要的库函数均在这些文件之中 pluartbsp/ps7_cortexa9_0/libsrc/uartns550_v3_5之下
ZYNQ PL 添加IP 串口UART AXI UART16550_第22张图片
主要调用的函数

	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);

options在xuartns550.h中定义

/** @name Configuration options
 * @{
 */
/**
 * These constants specify the options that may be set or retrieved
 * with the driver, each is a unique bit mask such that multiple options
 * may be specified.  These constants indicate the function of the option
 * when in the active state.
 */
#define XUN_OPTION_RXLINE_INTR		0x0800 /**< Enable status interrupt */
#define XUN_OPTION_SET_BREAK		0x0400 /**< Set a break condition */
#define XUN_OPTION_LOOPBACK		0x0200 /**< Enable local loopback */
#define XUN_OPTION_DATA_INTR		0x0100 /**< Enable data interrupts */
#define XUN_OPTION_MODEM_INTR		0x0080 /**< Enable modem interrupts */
#define XUN_OPTION_FIFOS_ENABLE		0x0040 /**< Enable FIFOs */
#define XUN_OPTION_RESET_TX_FIFO	0x0020 /**< Reset the transmit FIFO */
#define XUN_OPTION_RESET_RX_FIFO	0x0010 /**< Reset the receive FIFO */
#define XUN_OPTION_ASSERT_OUT2		0x0008 /**< Assert out2 signal */
#define XUN_OPTION_ASSERT_OUT1		0x0004 /**< Assert out1 signal */
#define XUN_OPTION_ASSERT_RTS		0x0002 /**< Assert RTS signal */
#define XUN_OPTION_ASSERT_DTR		0x0001 /**< Assert DTR signal */
/*@}*/

你可能感兴趣的:(tcp/ip,fpga开发,网络协议,单片机,嵌入式硬件)