自己想要打印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)); /* 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)) { /* Output Direction */
DirModeReg |= ((u32) << (u32)PinNumber);
} else { /* Input Direction */
DirModeReg &= ~ ((u32) << (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)); /* 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)) { /* Enable Output Enable */
OpEnableReg |= ((u32) << (u32)PinNumber);
} else { /* Disable Output Enable */
OpEnableReg &= ~ ((u32) << (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);
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) << (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
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,);//配置IO的输出
//while(1)
//{
Ps_WritePin(&psGpioInstancePtr, iPinNumber, );//输出1
sleep();//延时
Ps_WritePin(&psGpioInstancePtr, iPinNumber, );//输出0
sleep();//延时
//} #endif return ; }

上述代码是利用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=;
u8 PinNumber=; /**************对应管脚功能配置**********************/
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);
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)) { /* Output Direction */
DirModeReg |= ((u32) << (u32)PinNumber);
} else { /* Input Direction */
DirModeReg &= ~ ((u32) << (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)) { /* Enable Output Enable */
OpEnableReg |= ((u32) << (u32)PinNumber);
} else { /* Disable Output Enable */
OpEnableReg &= ~ ((u32) << (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) << (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 ; }

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

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

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

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

    //引脚EMIO54等价于bank=2,PinNum=0
//引脚EMIO57等价于bank=2,PinNum=3
u8 Bank=;
u8 PinNumber=; /**************对应管脚功能配置**********************/
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=;
u8 PinNumber=; /**************对应管脚功能配置**********************/
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);
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)) { /* Output Direction */
DirModeReg |= ((u32) << (u32)PinNumber);
} else { /* Input Direction */
DirModeReg &= ~ ((u32) << (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)) { /* Enable Output Enable */
OpEnableReg |= ((u32) << (u32)PinNumber);
} else { /* Disable Output Enable */
OpEnableReg &= ~ ((u32) << (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) << (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 ; }

驱动学习3.1:获取zynqled的物理地址的更多相关文章

  1. BCM wifi驱动学习

    BCMwifi驱动学习 一.wifi详解1 1.代码路径:Z:\home\stonechen\svn\TD550_X\TD550\3rdparty\wifi\BCM43362\special\bcmd ...

  2. 【Linux驱动学习】SD卡规范学习

    摘要: 学习SD卡的相关规范,包括定义,硬件特性,数据传输,命令系统等.不涉及代码. 文章针对Linux驱动开发而写,以助于理解SD卡驱动,不会涉及过多硬件内容. 纲要: 1. SD卡介绍 2. SD ...

  3. linux驱动之中断方式获取键值

    linux驱动之中断方式获取键值 ----------------------------------------------------------------------------------- ...

  4. linux 驱动学习笔记01--Linux 内核的编译

    由于用的学习材料是<linux设备驱动开发详解(第二版)>,所以linux驱动学习笔记大部分文字描述来自于这本书,学习笔记系列用于自己学习理解的一种查阅和复习方式. #make confi ...

  5. Linux驱动学习步骤(转载)

    1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. 学会写驱动的makefile 4. 写一简单char驱动,makefile编译通过,可以insmod, ls ...

  6. linux驱动学习(二) Makefile高级【转】

    转自:http://blog.csdn.net/ghostyu/article/details/6866863 版权声明:本文为博主原创文章,未经博主允许不得转载. 在我前一篇写的[ linux驱动学 ...

  7. linux驱动学习_1

    目前项目需要,需要做linux驱动了,记录一下 学习驱动,大家一定都会写一个hello world代码,网上也有很多范例,但是记录一下遇到的问题. 1.make之后,使用insmod加载,终端没有打印 ...

  8. Java学习-058-Jsoup爬虫获取中国所有的三级行政区划数据(三),处理二级编码缺失

    通过查看数据可知,直辖市或者某些三级行政区域没有对应的二级区域,为方便后续的地址使用,可自定义缺失的二级地址. 如下示例自定义的二级行政区域的名称为一级区域的名称,对应的源码如下所示: 将此段源码添加 ...

  9. IIC驱动学习笔记,简单的TSC2007的IIC驱动编写,测试

    IIC驱动学习笔记,简单的TSC2007的IIC驱动编写,测试 目的不是为了编写TSC2007驱动,是为了学习IIC驱动的编写,读一下TSC2007的ADC数据进行练习,, Linux主机驱动和外设驱 ...

随机推荐

  1. (转)一篇写的简明易懂的logging模块

    转:http://kenby.iteye.com/blog/1162698 一.从一个使用场景开始 开发一个日志系统, 既要把日志输出到控制台, 还要写入日志文件 import logging # 创 ...

  2. VIM字符编码基础知识

    1 字符编码基础知识 字符编码是计算机技术中最基本和最重要的知识之一.如果缺乏相关知识,请自行恶补之.这里仅做最简要的说明. 1.1 字符编码概述 所谓的字符编码,就是对人类发明的每一个文字进行数字 ...

  3. mysql You can't specify target table 'xxx' for update in FROM clause

    含义:您不能在子句中为更新指定目标表'xxx'. 错误描述:删除语句中直接含select,如下: DELETE FROM meriadianannotation WHERE SeriesID IN ( ...

  4. “我爱淘”第二冲刺阶段Scrum站立会议7

    完成任务: 完成学院分类的点击查看书籍功能,可以点击书的条目查看书的详细信息.将登陆界面以及注册发布界面完善了一下修复一些bug. 计划任务: 将书的详细信息进行完善,并且可以点击收藏以及已预订等功能 ...

  5. 第一次c++团队合作作业期间第一篇随笔

    分析了自己分到的任务,我的理解是这样的:首先要生成程序主框架,在主框架中进行地图的描绘.我应该是先进行地图的拼接,把建筑物和地面都拼接好.然后再在地图上显示出英雄和小兵.同时还要在主框架中分析了自己分 ...

  6. 2016-2017 ACM-ICPC, NEERC, Moscow Subregional Contest Problem L. Lazy Coordinator

    题目来源:http://codeforces.com/group/aUVPeyEnI2/contest/229511 时间限制:1s 空间限制:512MB 题目大意: 给定一个n 随后跟着2n行输入 ...

  7. Alpha - Postmortem

    Alpha - Postmortem NewTeam 2017/11/18 目录 设想和目标 计划 资源 变更管理 设计/实现 测试/发布 团队角色.管理.合作 总结 设想和目标 返回目录 1. 软件 ...

  8. oracle 行转列和列转行

    WITH L AS ( ), m AS ( SELECT A.LV AS LV_A, B.LV AS LV_B, TO_CHAR(B.LV) || 'x' || TO_CHAR(A.LV) || '= ...

  9. 【转】关于cgi、FastCGI、php-fpm、php-cgi

    转自 知乎 的 一个回答 首先,CGI是干嘛的?CGI是为了保证web server传递过来的数据是标准格式的,方便CGI程序的编写者. web server(比如说nginx)只是内容的分发者.比如 ...

  10. php缩略图

    /*引入文件Easyphpthumbnail.class.php 引用地址:http://www.itdaodan.com/article-detail-id-252.html */   class ...