GPIO是ARM芯片的通用IO口,在不存在操作系统的情况下,可以通过C语言程序,直接读写其寄存器进行控制,这就是以前的单片机编程。在基于ARM9的Windows CE系统平台下,将GPIO的实地址(例如2410的GPIO的基地址为0x56000000)映射到虚拟地址空间(GPIO对应为0xB1600000),这样,通过对这段虚拟地址空间的操作,就能够完成对GPIO或者其他片内资源的控制、输入输出工作。
要操作一个平台的GPIO,在其对应的BSP中按照基地址,找到虚拟地址,并且找到方便操作这个地址的数据结构就可以了,关键函数就是VirtualAlloc和VirtualCopy。并且CE的方便之处就是用户态的应用程序仍然可以使用这两个函数来访问所有这些虚拟空间,对于不太复杂的程序,甚至可以省略写驱动直接在应用程序中操作,其实在CE6之 前,这些驱动也是工作在用户态的。
下面是S3C2410的GPIO操作步骤:
1> 首先在BSP包中找到s2410.h文件,找到虚拟地址映射以及操作GPIO的寄存器结构体(这个在自己制作一些特殊设备的BSP时,会依据需要而发生更改)。
——————————————————————————————————
#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;
——————————————————————————————————
2> 建立一个VC的应用程序,由于VirtualCopy函数没有在头文件中定义,但是在coredll.lib里面提供了符号连接,所以我们需要在头文件里添加一个函数定义。
——————————————————————————————————
#ifdef __cplusplus
extern "C"
{
#endif
BOOL VirtualCopy( LPVOID, LPVOID, DWORD, DWORD );
#ifdef __cplusplus
}
#endif
——————————————————————————————————
同时将第1步中的结构体定义也复制到这里。
3> 定义一个寄存器结构体变量。
volatile IOPreg *v_pIOPRegs;
4> 使用的时候,给这个变量分配空间并且映射到寄存器的地址上,使用完毕后相应的也要取消映射。我们这里是操作一个蜂鸣器,点击button,蜂鸣器蜂鸣一声。也就是将GPB0置高,延时,然后再将GPB0置低。
——————————————————————————————————
v_pIOPRegs = (volatile IOPreg*)VirtualAlloc(0, sizeof(IOPreg), MEM_RESERVE, PAGE_NOACCESS);
if (v_pIOPRegs == NULL)
{
DEBUGMSG (1,(TEXT("v_pIOPRegs is not allocated/n/r")));
MessageBox(_T("关联失败"),NULL);
return;
}
if (!VirtualCopy((PVOID)v_pIOPRegs, (PVOID)IOP_BASE, sizeof(IOPreg), PAGE_READWRITE|PAGE_NOCACHE)) {
DEBUGMSG (1,(TEXT("v_pIOPRegs is not mapped/n/r")));
MessageBox(_T("映射失败"),NULL);
return;
}
v_pIOPRegs->rGPBCON &=~(0x03);
v_pIOPRegs->rGPBCON |=0x01;
Sleep(500);
v_pIOPRegs->rGPBDAT |=0x01;
Sleep(500);
//v_pIOPRegs->rGPBDAT &= 0x3fe;
v_pIOPRegs->rGPBDAT &=~ 0x01;
if(v_pIOPRegs){
VirtualFree((PVOID)v_pIOPRegs,0,MEM_RELEASE);
}
v_pIOPRegs=NULL;
——————————————————————————————————