昨天做了一个PS端利用EMIO对LED灯进行控制的实验,在XPS进行完系统的配置导出到SDK中后,发现EMIO口的映射地址为:0xe000a000,如下图
此时想起sheldon此前说过的xmd命令,可以利用命令行的模式,直接向地址中写入数据,从而对外设进行控制,于是,在烧写了FPGA后,没有编写应用程序,利用命令
mwr 0xe000a000 0xFF 进行LED灯的点亮,但是结果却并没有变化,此时考虑可能是没有对PS端应用程序编写的原因。由于本工程内还添加了一个自定义的IP核同样用于LED灯的控制,即上图中的axi_gpio_0,于是利用命令 mwr 0x41200000 0xFF进行测试,结果同样灯没亮,这样断定应该为没有进行应用程序编写的原因,于是,根据教程,敲入代码。具体代码如下:

/* * Copyright (c) 2009-2012 Xilinx, Inc. All rights reserved. * * Xilinx, Inc. * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. * */ /* * helloworld.c: simple test application * * This application configures UART 16550 to baud rate 9600. * PS7 UART (Zynq) is not initialized by this application, since * bootrom/bsp configures it to baud rate 115200 * * ------------------------------------------------ * | UART TYPE BAUD RATE | * ------------------------------------------------ * uartns550 9600 * uartlite Configurable only in HW design * ps7_uart 115200 (configured by bootrom/bsp) */ #include <stdio.h> #include "platform.h" #include "xparameters.h" #include "xuartps.h" #include "xgpio.h" #include "xgpiops.h" XUartPs Uart_Ps; int main() { XUartPs_Config* Config; int Status; int SentCount = 0; int RecvCount = 0; u8 HelloZynq[] = "Hello Zynq! "; u8 RecvBuf[3]; XGpio Gpio; /* 通过axi总线控制LED */ XGpioPs Gpiops; /* 通过EMIO控制LED */ XGpioPs_Config* ConfigPtr; u8 axi_Gpio_Data, ps_Gpio_Data; init_platform(); /* Look up the configuration in the config table and the initialize it*/ Config = XUartPs_LookupConfig(XPAR_PS7_UART_1_DEVICE_ID); if(NULL == Config) { return XST_FAILURE; } Status = XUartPs_CfgInitialize(&Uart_Ps, Config, Config->BaseAddress); if(Status != XST_SUCCESS) { return XST_FAILURE; } /* Send Hello Zynq*/ while(SentCount < (sizeof(HelloZynq) - 1)) { SentCount += XUartPs_Send(&Uart_Ps, &HelloZynq[SentCount], 1); } /* initialize the GPIO driver */ Status = XGpio_Initialize(&Gpio, XPAR_AXI_GPIO_0_DEVICE_ID); if(Status != XST_SUCCESS) { return XST_FAILURE; } /* Set the direction for all signals to be output */ XGpio_SetDataDirection(&Gpio, 1, 0x0); /* Initialize the PS GPIO driver */ ConfigPtr = XGpioPs_LookupConfig(XPAR_XGPIOPS_0_DEVICE_ID); Status = XGpioPs_CfgInitialize(&Gpiops, ConfigPtr, ConfigPtr->BaseAddr); if(Status != XST_SUCCESS) { return XST_FAILURE; } /* Set the direction for all signals to be outputs and Enable the Output enable for the LED pins */ XGpioPs_SetDirection(&Gpiops, 2, 0xF); XGpioPs_SetOutputEnable(&Gpiops, 2, 0xF); while(1) { /* Receive data and display data */ RecvCount = 0; while(RecvCount < 3) { while(!XUartPs_IsReceiveData(Config->BaseAddress)); XUartPs_Recv(&Uart_Ps, &RecvBuf[RecvCount], 1); if(RecvBuf[RecvCount] == 'r') { RecvBuf[RecvCount] = ' '; XUartPs_Send(&Uart_Ps, &RecvBuf[RecvCount], 1); break; } XUartPs_Send(&Uart_Ps, &RecvBuf[RecvCount++], 1); } /* Change ASCII char to number */ if(RecvBuf[0] >= '0' && RecvBuf[0] <= '9') axi_Gpio_Data = RecvBuf[0] - '0'; if(RecvBuf[0] >= 'a' && RecvBuf[0] <= 'z') axi_Gpio_Data = RecvBuf[0] - 'a' + 10; if(RecvBuf[0] >= 'A' && RecvBuf[0] <= 'Z') axi_Gpio_Data = RecvBuf[0] - 'A' + 10; XGpio_DiscreteWrite(&Gpio, 1, axi_Gpio_Data); if(RecvBuf[1] >= '0' && RecvBuf[1] <= '9') ps_Gpio_Data = RecvBuf[1] - '0'; if(RecvBuf[1] >= 'a' && RecvBuf[1] <= 'z') ps_Gpio_Data = RecvBuf[1] - 'a' + 10; if(RecvBuf[1] >= 'A' && RecvBuf[1] <= 'Z') ps_Gpio_Data = RecvBuf[1] - 'A' + 10; XGpioPs_Write(&Gpiops, 2, ps_Gpio_Data); } cleanup_platform(); return 0; }
而后运行应用程序,根据应用程序进行操作,可以很好的通过EMIO和自定义IP核对LED灯进行控制,此时再利用XMD命令行向自定义IP核写命令,发现可以控制LED灯,但在向EMIO写入命令时,依然没有作用。此时可以确定工程中并没有错误,唯一可能出错的地方就是XMD命令中的地址可能错误,于是去应用程序代码中进行寻找,看应用程序中是如何把数据写入的,根据应用程序中的写入程序,寻找地址。
应用程序中,进行写入数据的代码为:

if(RecvBuf[0] >= '0' && RecvBuf[0] <= '9') axi_Gpio_Data = RecvBuf[0] - '0'; if(RecvBuf[0] >= 'a' && RecvBuf[0] <= 'z') axi_Gpio_Data = RecvBuf[0] - 'a' + 10; if(RecvBuf[0] >= 'A' && RecvBuf[0] <= 'Z') axi_Gpio_Data = RecvBuf[0] - 'A' + 10; XGpio_DiscreteWrite(&Gpio, 1, axi_Gpio_Data); if(RecvBuf[1] >= '0' && RecvBuf[1] <= '9') ps_Gpio_Data = RecvBuf[1] - '0'; if(RecvBuf[1] >= 'a' && RecvBuf[1] <= 'z') ps_Gpio_Data = RecvBuf[1] - 'a' + 10; if(RecvBuf[1] >= 'A' && RecvBuf[1] <= 'Z') ps_Gpio_Data = RecvBuf[1] - 'A' + 10; XGpioPs_Write(&Gpiops, 2, ps_Gpio_Data);
代码中的前半部分为利用自定义IP核进行的写入,后半部分为利用EMIO接口进行的写入,进入函数XGpio_DiscreteWrite和XGpioPs_Write,去寻找地址
XGpio_DiscreteWrite:

void XGpio_DiscreteWrite(XGpio * InstancePtr, unsigned Channel, u32 Data) { Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertVoid((Channel == 1) || ((Channel == 2) && (InstancePtr->IsDual == TRUE))); XGpio_WriteReg(InstancePtr->BaseAddress, ((Channel - 1) * XGPIO_CHAN_OFFSET) + XGPIO_DATA_OFFSET, Data); }
发现在此函数中真正的数据写入由函数XGpio_WriteReg进行,此函数的第一个参数为基地址,根据第二个参数和偏移量进行计算具体的地址(此工程中偏移量为0,channel为1),可以看出此时数据的写入地址就为基地址,第三个参数为写入的数据,因此可以确定通过自定义IP核进行LED灯控制的外设地址就为基地址,即system.xml中显示的地址
另外分析XGpioPs_Write:

1 void XGpioPs_Write(XGpioPs *InstancePtr, u8 Bank, u32 Data) 2 { 3 Xil_AssertVoid(InstancePtr != NULL); 4 Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); 5 Xil_AssertVoid(Bank < XGPIOPS_MAX_BANKS); 6 7 XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr, 8 ((Bank) * XGPIOPS_DATA_BANK_OFFSET) + 9 XGPIOPS_DATA_OFFSET, Data); 10 }
同样数据的写入也由函数XGpioPs_WriteReg执行,其参数与上类似,但通过单步调试和分析可以发现,此时的地址偏移量并不为0,通过单步调试发现地址偏移量为0x48,因此在通过EMIO对LED灯进行控制时,写入数据的地址并不为system.xml中显示的基地址,而是基地址加上地址偏移量0x48,故通过XMD命令向地址0xe000a048写入数据,即
mwr 0xe000a048 0xFF, 执行命令后发现LED灯被电量,此时证明我们的猜测正确。
通过此例程发现在PS利用EMIO和PL进行通讯时,将PL端的配置当作外设进行映射到PS端时,外设的地址相对于基地址有偏移量,这里我猜测不同的地址偏移量跟ps端的system7总线有关系,但具体关系还不太清楚,现在地址的具体计算还不太清楚,有待进一步的了解,干巴蝶!!