zq2002
论坛版主
论坛版主
  • 注册日期2003-12-30
  • 最后登录2018-09-26
  • 粉丝0
  • 关注0
  • 积分45分
  • 威望185点
  • 贡献值0点
  • 好评度23点
  • 原创分0分
  • 专家分0分
阅读:1787回复:7

求助!关于在wince下访问硬件寄存器的问题

楼主#
更多 发布于:2004-10-20 17:31
我想在wince的应用程序中控制gpio口,下面是部分相关程序
PHYSICAL_ADDRESS IoAddress;
IoAddress.LowPart = 0x56000050;\\这是arm9 GPFCON控制寄存器的硬件地址
IoAddress.HighPart = 0;
ULONG  * gpioPtr;
gpioPtr = ( ULONG *)MmMapIoSpace( IoAddress,40,FALSE );
WRITE_REGISTER_ULONG(gpioPtr,numDatWrite);\\写0x56000050寄存器
WRITE_REGISTER_ULONG((gpioPtr+4),numDatWrite);\\写0x56000054寄存器

然后我debug这个应用程序,发现虚拟地址映射是成功的,写0x56000050寄存器也是成功的,但是写0x56000054寄存器时,evc出错,跟硬件短开了
以下是错误代码
C Run-Time Error R6025pure virtual function call
No object has been instantiated to handle the pure virtual function call.

This error is caused by calling a virtual function in an abstract base class through a pointer which is created by a cast to the type of the derived class, but is actually a pointer to the base class. This can occur when casting from a void* to a pointer to a class when the void* was created during the construction of the base class.


但是我假如我修改上面的代码,不写0x56000050这个寄存器,而是直接写0x56000054时,不会报错,但是数值写不到寄存其中去,真是奇哉怪也啊
哪位能指点下迷津呢?

最新喜欢:

jedijiejediji...
wxl_50685330
论坛版主
论坛版主
  • 注册日期2002-11-19
  • 最后登录2018-09-25
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望521点
  • 贡献值0点
  • 好评度419点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2004-10-21 13:32
我虽然没有试过mmmapiospace能不能工作,但是我认为即使可以工作也最好不要使用这个函数,我觉得这个函数是用在那些memroy空间和io空间独立编址的处理器中的,这个函数应该用于映射io空间到进程虚拟地址空间。


arm是memroy和io统一编址的,所有外围设备的访问都是对memory空间进行,所以应该使用virtualalloc在进程虚拟地址空间中分配一段,然后把你的gpio寄存器的地址空间用virtualcopy映射到这段空间,用下面这个试试吧:
参数给出你要映射的物理地址空间的首地址和长度
返回可用的虚拟地址
PVOID MyVirtualMap(PVOID PhyMem, UINT32 size)
{
PVOID pVirtualAddr;
pVirtualAddr = VirtualAlloc( 0, size, MEM_RESERVE, PAGE_NOACCESS );

if(pVirtualAddr == NULL)
{
RETAILMSG(1,(TEXT("MyVirtualMap : pVirtualAddr is not allocated!\n\r")));
RETAILMSG(1,(TEXT("MyVirtualMap : Error code = 0x%x\n\r"),GetLastError()));
return NULL;
}

if( !VirtualCopy(pVirtualAddr, PhyMem, size, PAGE_READWRITE | PAGE_NOCACHE ) )
{
     RETAILMSG(1, (TEXT("MyVirtualMap : pVirtualAddr is not mapped!\n\r")));
RETAILMSG(1,(TEXT("MyVirtualMap : Error code = 0x%x\n\r"),GetLastError()));
     VirtualFree((PVOID)pVirtualAddr, 0, MEM_RELEASE);
     return NULL;
}

return pVirtualAddr;
}

使用的是有注意事项有:
1.参数中所谓的物理地址,其实也是一个变幻过的地址,其实是wince内核虚拟地址,
2.物理地址必须4k对齐,这个msdn的帮助没有说,我试出来的

根据地的兄弟们,团结就是力量
zq2002
论坛版主
论坛版主
  • 注册日期2003-12-30
  • 最后登录2018-09-26
  • 粉丝0
  • 关注0
  • 积分45分
  • 威望185点
  • 贡献值0点
  • 好评度23点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2004-10-21 14:42
哎呀,又是你啊,真是个热心人,我现在就回去试试! :D
wxl_50685330
论坛版主
论坛版主
  • 注册日期2002-11-19
  • 最后登录2018-09-25
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望521点
  • 贡献值0点
  • 好评度419点
  • 原创分0分
  • 专家分0分
地板#
发布于:2004-10-21 14:59
要得!最近在弄wince,所以经常和兄弟们探讨一下:)
根据地的兄弟们,团结就是力量
zq2002
论坛版主
论坛版主
  • 注册日期2003-12-30
  • 最后登录2018-09-26
  • 粉丝0
  • 关注0
  • 积分45分
  • 威望185点
  • 贡献值0点
  • 好评度23点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2004-10-22 08:55
哎,今天用你的方法试了一下,还是在写寄存器的时候出错被强行断开,我好迷惘啊。。。。
下面这个是我的部分代码,为了方便,把好多输出调试信息的语句都去掉了

DWORD  size=128;


PVOID pVirtualAddr;
BOOL x;
pVirtualAddr = VirtualAlloc( 0, size, MEM_RESERVE, PAGE_NOACCESS );
x=VirtualCopy(pVirtualAddr, (void *)(0xb1600000/256), size, PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL) ;
WRITE_REGISTER_ULONG((ULONG*)pVirtualAddr,0x00000000);
joyfly
驱动小牛
驱动小牛
  • 注册日期2002-07-02
  • 最后登录2009-09-17
  • 粉丝0
  • 关注0
  • 积分319分
  • 威望32点
  • 贡献值0点
  • 好评度31点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2004-10-22 10:37
参考XSCALE BSP里关于VirtualAllocCopy的实现吧.注意物理地址4K对齐.
还有你的硬件地址到系统的物理地址的影射关系是什么样的?
0x56000050 -- > 0xb1600000 ?好象不太对哦.
所以你要处理好自己的对齐关系,然后加OFFSET去找到要设置的寄存器.

另外,关于VirtualCopy的用法, 如果你的参数里带了 PAGE_PHYSICAL, 那你传入的lpvSrc参数应该是硬件地址/256 , 如果不带PAGE_PHYSICAL, 那么应该传入系统的物理地址.

#define PAGE_SIZE 0x1000
#define ALIGNMENT_MASK (PAGE_SIZE-1)

PVOID VirtualAllocCopy(unsigned size,char *str,PVOID pVirtualAddress)
{
PVOID ptr;
    unsigned offset;

offset = (unsigned)pVirtualAddress & ALIGNMENT_MASK;

size +=offset ? PAGE_SIZE : 0;
ptr = VirtualAlloc(0,size,MEM_RESERVE,PAGE_NOACCESS);
if (ptr == NULL) {
ERRORMSG(1,(TEXT("VirtualAlloc failed! %s : size=0x%x, (0x%x)\r\n"),str,size,GetLastError()));
return(0);
}

if (!VirtualCopy((PVOID)ptr,(PVOID)((unsigned)pVirtualAddress - offset),size,PAGE_READWRITE|PAGE_NOCACHE)) {
ERRORMSG(1,(TEXT("VirtualCopy failed! %s : addr=0x%x, offset=0x%x(0x%x)\r\n"),str,(unsigned)pVirtualAddress,offset,GetLastError()));
return(0);
}  
return((PVOID)((PBYTE)ptr+offset));
}
www.cnemb.com
zq2002
论坛版主
论坛版主
  • 注册日期2003-12-30
  • 最后登录2018-09-26
  • 粉丝0
  • 关注0
  • 积分45分
  • 威望185点
  • 贡献值0点
  • 好评度23点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2004-10-22 12:13
刚才终于成功了!
下面是代码,给大家参考下
相关参数的定义在2410.h中,如下
// Registers : I/O port
//

#define IOP_BASE      0xB1600000 // 0x56000000
typedef struct  {
    unsigned int  rGPACON; // 00
    unsigned int  rGPADAT;
    unsigned int  rPAD1[2];
    
    unsigned int  rGPBCON; // 10
    unsigned int  rGPBDAT;
    unsigned int  rGPBUP;
    unsigned int  rPAD2;
    
    unsigned int  rGPCCON; // 20
    unsigned int  rGPCDAT;
    unsigned int  rGPCUP;
    unsigned int  rPAD3;
    
    unsigned int  rGPDCON; // 30
    unsigned int  rGPDDAT;
    unsigned int  rGPDUP;
    unsigned int  rPAD4;
    
    unsigned int  rGPECON; // 40
    unsigned int  rGPEDAT;
    unsigned int  rGPEUP;
    unsigned int  rPAD5;
    
    unsigned int  rGPFCON; // 50
    unsigned int  rGPFDAT;
    unsigned int  rGPFUP;
    unsigned int  rPAD6;
    
    unsigned int  rGPGCON; // 60
    unsigned int  rGPGDAT;
    unsigned int  rGPGUP;
    unsigned int  rPAD7;
    
    unsigned int  rGPHCON; // 70
    unsigned int  rGPHDAT;
    unsigned int  rGPHUP;
    unsigned int  rPAD8;
    
    unsigned int  rMISCCR; // 80
    unsigned int  rDCKCON;
    unsigned int  rEXTINT0;
    unsigned int  rEXTINT1;
    unsigned int  rEXTINT2; // 90
unsigned int  rEINTFLT0;
unsigned int  rEINTFLT1;
unsigned int  rEINTFLT2;
unsigned int  rEINTFLT3; // A0
unsigned int  rEINTMASK;
unsigned int  rEINTPEND;
unsigned int  rGSTATUS0; // AC
unsigned int  rGSTATUS1; // B0
unsigned int  rGSTATUS2; // B4
unsigned int  rGSTATUS3; // B8
unsigned int  rGSTATUS4; // BC

}IOPreg;  
其实我要做的就是让把GPF0和GPF2设置成IO输出工作方式,让他们输出一个高低电平不断变换的波形
下面是部分代码
BOOL x;
int n,m;
v_pIOPRegs = (volatile IOPreg *)VirtualAlloc(0, sizeof(IOPreg), MEM_RESERVE, PAGE_NOACCESS);
x=VirtualCopy((PVOID)v_pIOPRegs, (PVOID)IOP_BASE, sizeof(IOPreg), PAGE_READWRITE|PAGE_NOCACHE);
v_pIOPRegs->rGPFCON = (v_pIOPRegs->rGPFCON & 0x00000000) | (0x11);//将GPFn配置成数据输出方式
while(1)
{



for(n=0;n<100;n++)//延时
{
m=n;
}
v_pIOPRegs->rGPFUP=(v_pIOPRegs->rGPFUP&0x0);
v_pIOPRegs->rGPFDAT=(v_pIOPRegs->rGPFDAT|0xf);\\输出高
for(n=0;n<100;n++)\\延时
{
m=n;
}
v_pIOPRegs->rGPFUP=(v_pIOPRegs->rGPFUP|0xf);
v_pIOPRegs->rGPFDAT=(v_pIOPRegs->rGPFDAT&0x0);\\输出低

}
这样,我用示波器就可以从GPF0 和GPF2上面检测到一个方波的波形了,我估计原来一直出错的原因可能是因为使用WRITE_REGISTER_ULONG这个函数造成的


[编辑 -  10/22/04 by  zq2002]
wxl_50685330
论坛版主
论坛版主
  • 注册日期2002-11-19
  • 最后登录2018-09-25
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望521点
  • 贡献值0点
  • 好评度419点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2004-10-22 13:36
那个东西的定义:
#define WRITE_REGISTER_ULONG(reg, val) \
    (*(volatile unsigned long * const)(reg)) = (val)

不应该是这个的问题,不过这样用:

WRITE_REGISTER_ULONG(&(v_pIOPRegs->rGPFCON), val)
根据地的兄弟们,团结就是力量
游客

返回顶部