Windows CE下操作 GPIO的方法 (以S3C2440为例)
s3c2440共有130个GPIO端口,分为9组,GPA ~ GPJ,通过寄存器控制。
控制s3c2440的GPIO端口的寄存器有3类,分别是GPxCON、GPxDAT、GPxUP (x=A ~ J):
GPxCON:GPIO控制寄存器,可以设置选定GPIO口的输入输出方式和功能。GPA组的23个端口比较特殊,只能是输出方式。GPACON的每一位对应一个引脚,当某位为0时,对应引脚为输出端口,否则为复用功能。
GPB ~ GPJ端口的GPxCON寄存器使用方法一致,每两位控制一个引脚,00时为输入I/O口,01时为输出I/O口,10时为复用功能,11保留。
GPxDAT:此引脚用于读写引脚的状态,即端口数据。当引脚配置为输出时,给该寄存器某位写1,则对应引脚输出高电平,写0输出低电平。当引脚配置为输出时,读该寄存器可以得到端口电平状态。
GPxUP:该寄存器可以设置引脚是否使用上拉电阻,某位为0时对应引脚使用上拉电阻,某位为1时不使用上拉电阻。注意:GPA组没有GPxUP寄存器,即没有上拉电阻。
GPIO 是ARM芯片最基本的输入输出通道,在ADS下操作就是一个单片机工作,直接读写其寄存器。在ARM9平台上,Windows CE系统将GPIO的实地址(例如2410的GPIO的基地址为0x56000000)映射到虚拟地址空间(GPIO对应为0xB1600000),这样,通过对这段虚拟地址空间的操作,就能够完成对GPIO或者其他片内资源的控制、输入输出工作。
要操作一个平台的GPIO,在其对应BSP中按照基地址,找到虚拟地址,并且找到方便操作这个地址的数据结构就可以了,关键函数就是VirtualAlloc和VirtualCopy。并且CE的方便之处就是用户态的应用程序仍然可以使用这两个函数来访问所有这些虚拟空间,对于不太复杂的程序,甚至可以省略写驱动直接在应用程序中操作,其实在CE6之前,这些驱动也是工作在用户态的。
下面以操作S3C2440的GPIO为例
#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 ;;; SHL
unsigned int rGSTATUS3; // B8
unsigned int rGSTATUS4; // BC
unsigned int rFLTOUT; // C0
unsigned int rDSC0;
unsigned int rDSC1;
unsigned int rMSLCON;
unsigned int rGPJCON; // D0
unsigned int rGPJDAT;
unsigned int rGPJUP;
unsigned int rPAD9;
}IOPreg;
#ifdef __cplusplus
extern "C"
{
#endif
BOOL VirtualCopy( PVOID, PVOID, DWORD, DWORD );
#ifdef __cplusplus
}
#endif
void GPIO() //通过GPIO控制蜂鸣器
{
volatile IOPreg *v_pIORegs = NULL;
v_pIORegs = (volatile IOPreg *)VirtualAlloc(0, sizeof(IOPreg), MEM_RESERVE, PAGE_NOACCESS);
if(v_pIORegs)
{
if(VirtualCopy((PVOID)v_pIORegs, (PVOID)IOP_BASE, sizeof(IOPreg), PAGE_READWRITE | PAGE_NOCACHE))
{
v_pIORegs->rGPBCON = 1; //将GPB0设置为OUTPUT
unsigned long dwTT = v_pIORegs->rGPBDAT;
v_pIORegs->rGPBDAT = 0x3ff; //设置为高电平,蜂鸣器发声
Sleep(3000);
v_pIORegs->rGPBDAT = dwTT; //恢复为低电平,蜂鸣器停止发声
}
VirtualFree((LPVOID)v_pIORegs, 0, MEM_RELEASE);
v_pIORegs = NULL;
}
}