自己想要打印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\n",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\n",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\n",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\n",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\n",GpioConfigPtr->BaseAddr); xStatus = XGpioPs_CfgInitialize(&psGpioInstancePtr,GpioConfigPtr, GpioConfigPtr->BaseAddr); if(XST_SUCCESS != xStatus) print(" PS GPIO INIT FAILED \n\r"); //--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\n",Gpio_DIR,DirModeReg); printf("Gpio_EN:%lx,value:%lx\n",Gpio_EN,OpEnableReg); printf("Gpio_DATA:%lx,value:%lx\n",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 |
注意:这里的地址都是绝对地址,也就是最终的物理地址,便于我们做后序驱动开发。