• PS利用EMIO控制LED灯


      昨天做了一个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;
    }
    View Code

      而后运行应用程序,根据应用程序进行操作,可以很好的通过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);
    View Code

      代码中的前半部分为利用自定义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);
    }
    View Code

      发现在此函数中真正的数据写入由函数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 }
    View Code

      同样数据的写入也由函数XGpioPs_WriteReg执行,其参数与上类似,但通过单步调试和分析可以发现,此时的地址偏移量并不为0,通过单步调试发现地址偏移量为0x48,因此在通过EMIO对LED灯进行控制时,写入数据的地址并不为system.xml中显示的基地址,而是基地址加上地址偏移量0x48,故通过XMD命令向地址0xe000a048写入数据,即

      mwr 0xe000a048 0xFF, 执行命令后发现LED灯被电量,此时证明我们的猜测正确。

        通过此例程发现在PS利用EMIO和PL进行通讯时,将PL端的配置当作外设进行映射到PS端时,外设的地址相对于基地址有偏移量,这里我猜测不同的地址偏移量跟ps端的system7总线有关系,但具体关系还不太清楚,现在地址的具体计算还不太清楚,有待进一步的了解,干巴蝶!!

  • 相关阅读:
    l1-013
    将博客搬至CSDN
    Educational Codeforces Round 25
    大组合数取余模板【Lucas定理】
    Exams(二分求左界+贪心)
    Cutting (暴力 + 滚动哈希判字符串匹配)
    Cubes(DFS+剪枝)
    Codeforces Round #409 (Div. 2)
    【复习挖坑】dp + 图
    n & n-1 和 n & -n
  • 原文地址:https://www.cnblogs.com/GOFpag/p/Zedboard_EMIO.html
Copyright © 2020-2023  润新知