• 驱动学习3.1:获取zynqled的物理地址


    自己想要打印EMIO管脚的物理地址,在SDK提供的头文件中加入printf是无法打印的,基于此

    我将需要打印地址的几个函数提取出来,放在main函数中,然后在里面加入printf打印这些用户管脚的地址:

    Ps_SetDirectionPin   //设置方向,原函数XGpioPs_SetDirectionPin
    Ps_SetOutputEnablePin//设置使能,原函数XGpioPs_SetOutputEnablePin
    Ps_WritePin          //写入值,原函数XGpioPs_WritePin

    将其修改为自定义函数,目的就是利用串口打印物理地址

    #include <stdio.h>
    #include "xgpiops.h"
    #include "sleep.h"
    
    
    /****************************************************************************/
    /**
    *
    * Set the Direction of the specified pin.
    *
    * @param    InstancePtr is a pointer to the XGpioPs instance.
    * @param    Pin is the pin number to which the Data is to be written.
    *        Valid values are 0-117 in Zynq and 0-173 in Zynq Ultrascale+ MP.
    * @param    Direction is the direction to be set for the specified pin.
    *        Valid values are 0 for Input Direction, 1 for Output Direction.
    *
    * @return    None.
    *
    *****************************************************************************/
    void Ps_SetDirectionPin(XGpioPs *InstancePtr, u32 Pin, u32 Direction)
    {
        u8 Bank;
        u8 PinNumber;
        u32 DirModeReg;
    
        Xil_AssertVoid(InstancePtr != NULL);
        Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
        Xil_AssertVoid(Pin < InstancePtr->MaxPinNum);
        Xil_AssertVoid(Direction <= (u32)1);
    
        /* Get the Bank number and Pin number within the bank. */
        XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);
    
        DirModeReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
                          ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                          XGPIOPS_DIRM_OFFSET);
    
        if (Direction!=(u32)0) { /*  Output Direction */
            DirModeReg |= ((u32)1 << (u32)PinNumber);
        } else { /* Input Direction */
            DirModeReg &= ~ ((u32)1 << (u32)PinNumber);
        }
        printf("Direction:%lx,%lx,%lx
    ",InstancePtr->GpioConfig.BaseAddr,((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                 XGPIOPS_DIRM_OFFSET,DirModeReg);
    
        XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
                 ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                 XGPIOPS_DIRM_OFFSET, DirModeReg);
    }
    
    
    /****************************************************************************/
    /**
    *
    * Set the Output Enable of the specified pin.
    *
    * @param    InstancePtr is a pointer to the XGpioPs instance.
    * @param    Pin is the pin number to which the Data is to be written.
    *        Valid values are 0-117 in Zynq and 0-173 in Zynq Ultrascale+ MP.
    * @param    OpEnable specifies whether the Output Enable for the specified
    *        pin should be enabled.
    *        Valid values are 0 for Disabling Output Enable,
    *        1 for Enabling Output Enable.
    *
    * @return    None.
    *
    * @note        None.
    *
    *****************************************************************************/
    void Ps_SetOutputEnablePin(XGpioPs *InstancePtr, u32 Pin, u32 OpEnable)
    {
        u8 Bank;
        u8 PinNumber;
        u32 OpEnableReg;
    
        Xil_AssertVoid(InstancePtr != NULL);
        Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
        Xil_AssertVoid(Pin < InstancePtr->MaxPinNum);
        Xil_AssertVoid(OpEnable <= (u32)1);
    
        /* Get the Bank number and Pin number within the bank. */
        XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);
    
        OpEnableReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
                           ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                           XGPIOPS_OUTEN_OFFSET);
    
        if (OpEnable != (u32)0) { /*  Enable Output Enable */
            OpEnableReg |= ((u32)1 << (u32)PinNumber);
        } else { /* Disable Output Enable */
            OpEnableReg &= ~ ((u32)1 << (u32)PinNumber);
        }
        printf("OutputEn:%lx,%lx,%lx
    ",InstancePtr->GpioConfig.BaseAddr,((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                  XGPIOPS_OUTEN_OFFSET,OpEnableReg);
    
        XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
                  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                  XGPIOPS_OUTEN_OFFSET, OpEnableReg);
    }
    
    
    /****************************************************************************/
    /**
    *
    * Write data to the specified pin.
    *
    * @param    InstancePtr is a pointer to the XGpioPs instance.
    * @param    Pin is the pin number to which the Data is to be written.
    *        Valid values are 0-117 in Zynq and 0-173 in Zynq Ultrascale+ MP.
    * @param    Data is the data to be written to the specified pin (0 or 1).
    *
    * @return    None.
    *
    * @note        This function does a masked write to the specified pin of
    *        the specified GPIO bank. The previous state of other pins
    *        is maintained.
    *
    *****************************************************************************/
    void Ps_WritePin(XGpioPs *InstancePtr, u32 Pin, u32 Data)
    {
        u32 RegOffset;
        u32 Value;
        u8 Bank;
        u8 PinNumber;
        u32 DataVar = Data;
    
        Xil_AssertVoid(InstancePtr != NULL);
        Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
        Xil_AssertVoid(Pin < InstancePtr->MaxPinNum);
    
        /* Get the Bank number and Pin number within the bank. */
        XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);
        printf("bank=%d,PinNumber=%d
    ",Bank,PinNumber);
        if (PinNumber > 15U) {
            /* There are only 16 data bits in bit maskable register. */
            PinNumber -= (u8)16;
            RegOffset = XGPIOPS_DATA_MSW_OFFSET;
        } else {
            RegOffset = XGPIOPS_DATA_LSW_OFFSET;
        }
    
        /*
         * Get the 32 bit value to be written to the Mask/Data register where
         * the upper 16 bits is the mask and lower 16 bits is the data.
         */
        DataVar &= (u32)0x01;
        Value = ~((u32)1 << (PinNumber + 16U)) & ((DataVar << PinNumber) | 0xFFFF0000U);
    
        printf("write:%lx,%lx,%lx
    ",InstancePtr->GpioConfig.BaseAddr,((u32)(Bank) * XGPIOPS_DATA_MASK_OFFSET) +
                  RegOffset,Value);
    
        XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
                  ((u32)(Bank) * XGPIOPS_DATA_MASK_OFFSET) +
                  RegOffset, Value);
    }
    
    int main()
    {
    
    
    #if 1
        static XGpioPs psGpioInstancePtr;
        XGpioPs_Config* GpioConfigPtr;
    
        int iPinNumber= 54; //想想为什么是54
        u32 uPinDirection = 0x1; //1表示输出,0表示输入
    
        int xStatus;
        //--MIO的初始化
        GpioConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
        if(GpioConfigPtr == NULL)
            return XST_FAILURE;
        printf("baseAddr:0x%lx
    ",GpioConfigPtr->BaseAddr);
        xStatus = XGpioPs_CfgInitialize(&psGpioInstancePtr,GpioConfigPtr, GpioConfigPtr->BaseAddr);
        if(XST_SUCCESS != xStatus)
            print(" PS GPIO INIT FAILED 
    
    ");
    
        //--MIO的输入输出操作
        Ps_SetDirectionPin(&psGpioInstancePtr, iPinNumber,uPinDirection);//配置IO输出方向
        Ps_SetOutputEnablePin(&psGpioInstancePtr, iPinNumber,1);//配置IO的输出
        //while(1)
        //{
            Ps_WritePin(&psGpioInstancePtr, iPinNumber, 1);//输出1
            sleep(2);//延时
            Ps_WritePin(&psGpioInstancePtr, iPinNumber, 0);//输出0
            sleep(2);//延时
        //}
    
    #endif
    
        return 0;
    
    }

    上述代码是利用SDK提供的API接口实现led的控制。

    如果在做驱动开发时,需要知道led对应的(控制寄存器、数据寄存器)物理地址,因此根据上述代码实现了自己的裸机驱动代码

    #include <stdio.h>
    #include "xgpiops.h"
    #include "sleep.h"
    
    
    
    #define MY_GPIO_BASE_ADDR    0xE000A000
    #define XGPIOPS_DATA_MASK_OFFSET 0x00000008U  /* Data/Mask Registers offset */
    #define XGPIOPS_REG_MASK_OFFSET  0x00000040U  /* Registers offset */
    #define XGPIOPS_DIRM_OFFSET         0x00000204U  /* Direction Mode Register, RW */
    #define XGPIOPS_OUTEN_OFFSET     0x00000208U  /* Output Enable Register, RW */
    #define XGPIOPS_DATA_LSW_OFFSET  0x00000000U  /* Mask and Data Register LSW, WO */
    #define XGPIOPS_DATA_MSW_OFFSET  0x00000004U  /* Mask and Data Register MSW, WO */
    
    
    int main()
    {
    
        //引脚EMIO54等价于bank=2,PinNum=0
        //引脚EMIO57等价于bank=2,PinNum=3
        u8 Bank=2;
        u8 PinNumber=0;
    
        /**************对应管脚功能配置**********************/
        u32  Direction=0X01;//设置MIO_54为输出
        u32  OpEnable=0X01;//使能
        u32 DataVar = 0X01;//1亮
    
    
        //方向寄存器地址(由bank决定)
         u32 *Gpio_DIR =( u32 *)(MY_GPIO_BASE_ADDR+
                ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                 XGPIOPS_DIRM_OFFSET);  //方向寄存器,1为输出
         //使能寄存器地址(由bank决定)
         u32 *Gpio_EN =( u32 *)(MY_GPIO_BASE_ADDR+
                    ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                    XGPIOPS_OUTEN_OFFSET);//使能寄存器,1使能
        //数据寄存器地址(由bank和PinNumuber决定)
        u32 RegOffset;    //16位宽,后面要注意
        if (PinNumber > 15U) {
            /* There are only 16 data bits in bit maskable register. */
            PinNumber -= (u8)16;
            RegOffset = XGPIOPS_DATA_MSW_OFFSET;
        } else {
            RegOffset = XGPIOPS_DATA_LSW_OFFSET;
        }
         u32 *Gpio_DATA =( u32 *)(MY_GPIO_BASE_ADDR+
                    ((u32)(Bank) * XGPIOPS_DATA_MASK_OFFSET) +
                    RegOffset);//数据寄存器,1亮
    
        //根据用户方向值,填充方向寄存器值
        u32 DirModeReg=XGpioPs_ReadReg(MY_GPIO_BASE_ADDR,
                   ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                   XGPIOPS_OUTEN_OFFSET);
        if (Direction!=(u32)0) { /*  Output Direction */
            DirModeReg |= ((u32)1 << (u32)PinNumber);
        } else { /* Input Direction */
            DirModeReg &= ~ ((u32)1 << (u32)PinNumber);
        }
        *Gpio_DIR = DirModeReg;
        //根据用户使能值,填充使能寄存器值
        u32 OpEnableReg=XGpioPs_ReadReg(MY_GPIO_BASE_ADDR,
                   ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                   XGPIOPS_OUTEN_OFFSET);
        if (OpEnable != (u32)0) { /*  Enable Output Enable */
                OpEnableReg |= ((u32)1 << (u32)PinNumber);
        } else { /* Disable Output Enable */
                OpEnableReg &= ~ ((u32)1 << (u32)PinNumber);
        }
        *Gpio_EN =OpEnableReg;
    
        //根据用户DATA值,填充数据寄存器值
        /*
         * Get the 32 bit value to be written to the Mask/Data register where
         * the upper 16 bits is the mask and lower 16 bits is the data.
         */
        DataVar &= (u32)0x01;
        u32 Value = ~((u32)1 << (PinNumber + 16U)) & ((DataVar << PinNumber) | 0xFFFF0000U);
        *Gpio_DATA =Value;//1亮 (fffe0001亮,fffe0000灭)
    
        //测试物理地址
        printf("Gpio_DIR:%lx,value:%lx
    ",Gpio_DIR,DirModeReg);
        printf("Gpio_EN:%lx,value:%lx
    ",Gpio_EN,OpEnableReg);
        printf("Gpio_DATA:%lx,value:%lx
    ",Gpio_DATA,Value);
    
    
        return 0;
    
    }

    结合UG585手册能够清晰的确定三个主要寄存器(控制、使能、数据)的基地址,长度(32位),该填充的内容,这里没有自己研究,仅仅将代码测试出来,

    后面二者结合能够更好的明白ZYNQ EMIO对应的寄存器配置。

    该代码仅仅分析了EMIO54-57,分别对应bank2的0-3

    用户仅仅修改,以下区域即可,其他代码均是由这些“用户配置”完成

        //引脚EMIO54等价于bank=2,PinNum=0
        //引脚EMIO57等价于bank=2,PinNum=3
        u8 Bank=2;
        u8 PinNumber=0;
    
        /**************对应管脚功能配置**********************/
        u32  Direction=0X01;//设置MIO_54为输出
        u32  OpEnable=0X01;//使能
        u32 DataVar = 0X01;//1亮
      方向寄存器(地址) 方向寄存器(输出) 使能寄存器(地址) 使能寄存器(使能) s数据寄存器(地址) 数据寄存器(亮) 数据寄存器(灭)
    Y21    e000a284 f e000a288 f e000a010 fffe0001 fffe0000
    G2   e000a284 f e000a288 f e000a010 fffd0002 fffd0000
    W21   e000a284 1f e000a288 1f e000a010 fffb0004 fffb0000
    A17   e000a284 1f e000a288 1f e000a010 fff70008 fff70000

    注意:这里的地址都是绝对地址,也就是最终的物理地址,便于我们做后序驱动开发。

    #include <stdio.h>
    #include "xgpiops.h"
    #include "sleep.h"
    
    
    
    #define MY_GPIO_BASE_ADDR    0xE000A000
    #define XGPIOPS_DATA_MASK_OFFSET 0x00000008U  /* Data/Mask Registers offset */
    #define XGPIOPS_REG_MASK_OFFSET  0x00000040U  /* Registers offset */
    #define XGPIOPS_DIRM_OFFSET         0x00000204U  /* Direction Mode Register, RW */
    #define XGPIOPS_OUTEN_OFFSET     0x00000208U  /* Output Enable Register, RW */
    #define XGPIOPS_DATA_LSW_OFFSET  0x00000000U  /* Mask and Data Register LSW, WO */
    #define XGPIOPS_DATA_MSW_OFFSET  0x00000004U  /* Mask and Data Register MSW, WO */
    
    
    int main()
    {
    
        //引脚EMIO54等价于bank=2,PinNum=0
        //引脚EMIO57等价于bank=2,PinNum=3
        u8 Bank=2;
        u8 PinNumber=0;
    
        /**************对应管脚功能配置**********************/
        u32  Direction=0X01;//设置MIO_54为输出
        u32  OpEnable=0X01;//使能
        u32 DataVar = 0X00;//1亮
    
    
        //方向寄存器地址(由bank决定)
         u32 *Gpio_DIR =( u32 *)(MY_GPIO_BASE_ADDR+
                ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                 XGPIOPS_DIRM_OFFSET);  //方向寄存器,1为输出
         //使能寄存器地址(由bank决定)
         u32 *Gpio_EN =( u32 *)(MY_GPIO_BASE_ADDR+
                    ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                    XGPIOPS_OUTEN_OFFSET);//使能寄存器,1使能
        //数据寄存器地址(由bank和PinNumuber决定)
        u32 RegOffset;    //16位宽,后面要注意
        if (PinNumber > 15U) {
            /* There are only 16 data bits in bit maskable register. */
            PinNumber -= (u8)16;
            RegOffset = XGPIOPS_DATA_MSW_OFFSET;
        } else {
            RegOffset = XGPIOPS_DATA_LSW_OFFSET;
        }
         u32 *Gpio_DATA =( u32 *)(MY_GPIO_BASE_ADDR+
                    ((u32)(Bank) * XGPIOPS_DATA_MASK_OFFSET) +
                    RegOffset);//数据寄存器,1亮
    
        //根据用户方向值,填充方向寄存器值
        u32 DirModeReg=XGpioPs_ReadReg(MY_GPIO_BASE_ADDR,
                   ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                   XGPIOPS_OUTEN_OFFSET);
        if (Direction!=(u32)0) { /*  Output Direction */
            DirModeReg |= ((u32)1 << (u32)PinNumber);
        } else { /* Input Direction */
            DirModeReg &= ~ ((u32)1 << (u32)PinNumber);
        }
        *Gpio_DIR = DirModeReg;
        //根据用户使能值,填充使能寄存器值
        u32 OpEnableReg=XGpioPs_ReadReg(MY_GPIO_BASE_ADDR,
                   ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
                   XGPIOPS_OUTEN_OFFSET);
        if (OpEnable != (u32)0) { /*  Enable Output Enable */
                OpEnableReg |= ((u32)1 << (u32)PinNumber);
        } else { /* Disable Output Enable */
                OpEnableReg &= ~ ((u32)1 << (u32)PinNumber);
        }
        *Gpio_EN =OpEnableReg;
    
        //根据用户DATA值,填充数据寄存器值
        /*
         * Get the 32 bit value to be written to the Mask/Data register where
         * the upper 16 bits is the mask and lower 16 bits is the data.
         */
    
        DataVar &= (u32)0x01;
        u32 Value = ~((u32)1 << (PinNumber + 16U)) & ((DataVar << PinNumber) | 0xFFFF0000U);
        *Gpio_DATA =Value;//1亮 (fffe0001亮,fffe0000灭)
    
        //测试物理地址
        printf("Gpio_DIR:%lx,value:%lx
    ",Gpio_DIR,DirModeReg);
        printf("Gpio_EN:%lx,value:%lx
    ",Gpio_EN,OpEnableReg);
        printf("Gpio_DATA:%lx,value:%lx
    ",Gpio_DATA,Value);
    
    
        return 0;
    
    }
    View Code
  • 相关阅读:
    【LeetCode】面试题59
    【LeetCode】面试题57
    【LeetCode】面试题57
    Chrome查看Markdown并转为PDF
    【LeetCode】232. 用栈实现队列
    【LeetCode】27. 移除元素
    【LeetCode】1323. 6 和 9 组成的最大数字
    【LeetCode】167. 两数之和 II
    第14条:在公有类中使用访问方法而非公有域
    Android Studio项目中三种依赖的添加方式
  • 原文地址:https://www.cnblogs.com/shuqingstudy/p/9159939.html
Copyright © 2020-2023  润新知