AU1200 GPIO的使用
//========================================================================
//TITLE:
// AU1200 GPIO的使用
//AUTHOR:
// norains
//DATE:
// Saturday 10-May-2008
//Environment:
// VS2005 + MIPS-SDK + DBAU1200 BOARD
//========================================================================
如果说一款CPU的精髓在于GPIO PIN,其实一点也不为过。一个工程师能否熟练操控CPU的GPIO,几乎决定了一个产品的成败。有太多的芯片,和CPU打交道的唯一方式就是GPIO。
所幸的是,DBAU1200的SDK中包含了完整的GPIO驱动。相对于其它半吊子的驱动来说,不能不让我们略感欣慰。
如果安装了DBAU1200 SDK Packet,那么GPIO驱动将位于:$WINCEROOT$/PLATFORM/Db1200/Drivers/Gpio。
AU1200的GPIO分为两块,分别是Primary GENERAL PURPOSE I/O和Secondary GENERAL PURPOSE I/O。
Secondary GENERAL PURPOSE I/O(以下简称GPIO2)的使用比较简单,无非就是设置PIN的方向(Input/Output),读取PIN的数值(1/0),用来控制那些外围芯片的EN PIN是个非常合适的选择;而Primary GENERAL PURPOSE I/O(以下简称GPIO1)就比较复杂,它是一个多功能复用PIN,具体的功能需要设置相关的寄存器。
首先我们先看看最简单的GPIO2。
GPIO2的具体介绍可以参考RMI的AU1200文档Secondary GENERAL PURPOSE I/O一节,在这里只是挑一些重点来说明。
GPIO2一共有16个PIN,它的Physical Base Address为0x0 1170 0000,KSEG1 Base Address为0xB170 0000。
与GPIO2的Control Register有六个,除了一个是保留的以外,真正有作用的是五个。
Offset (Note1) Register Name Description
0x0000 gpio2_dir Direction Register
0x0004 — Reserved
0x0008 gpio2_output Data Output Register
0x000C gpio2_pinstate Pin State Register
0x0010 gpio2_inten Interrupt Enable Register
0x0014 gpio2_enable Enable Register
因为涉及到寄存器的设置,所以在使用中比较简单。假如我们需要将GPIO2_0的方向设置为ouput,则代码可以如此:
#define KSEG1_GPIO_BASE 0xB1700000
#define GPIO_OFFSET 0x0000
*((volatile unsigned long *)(KSEG1_GPIO_BASE + GPIO_OFFSET)) = 0x0001
相对GPIO2来说,因为GPIO1是复用多功能pin,在使用中会比GPIO2要略显麻烦。
GPIO1有27个PIN,每个PIN基本上都具有两个功能,而这些功能的选择是通过写入sys_pinfunc寄存器来实现的。sys_pinfunc的地址是相对于sys_base偏移0x002C,而sys_base的Physical Base Address为0x0 1190 0000,KSEG1 Base Address为0xB190 0000。
因为篇幅关系,在这里就不将每个PIN的复用功能列出来,有兴趣的朋友可以参考RMI关于AU1200文档的Primary General Purpose I/O and Pin Functionality一节。
GPIO的Control Register有七个,分别罗列如下:
Offset Register Name Register Description
0x0100 sys_trioutrd Displays the tristate/output state of GPIO[n].
0x0100 sys_trioutclr Set sys_trioutclr[n] to clear and tristate the corre-
sponding bit. All input pins must be tristated.
0x0108 sys_outputrd Displays the output state of GPIO[n].
0x0108 sys_outputset Set sys_outputset[n] to enable a high level output.
0x010C sys_outputclr Set sys_outputclr[n] to enable a low level output.
Setting an output pin brings the pin out of tristate
mode and enables the output.
0x0110 sys_pinstaterd Displays the state of the pins.
0x0110 sys_pininputen Writing to this register allows the system to use
GPIO[7:0] as external inputs to wake the processor
from Sleep. This register must be written before any
GPIO[7:0] signal can be used as a Sleep wakeup
input source.
对该Register的读写,可以参照GPIO2寄存器的读写方法。
如果在应用程序中操作GPIO,则可以很简单地通过GPIO驱动来实现。
调用GPIO驱动方法大体上有两种,现在分别以这两种方法关闭SD CARD PIN功能。因为SD CARD PIN主要存在于GPIO1,所以下面的代码都是对GPIO1进行的。
方法一:流驱动方式
因为GPIO是流驱动,所以我们可以用通用的方法来进行读写。
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
//该类型数值的定义可以在GPIO.C文件中找到。
enum {
IOCTL_GPIO_READSTATE = 0x80001000, // some arbirary base
IOCTL_GPIO_OUTPUTSTATESET, // 1
IOCTL_GPIO_OUTPUTSTATECLEAR, // 2
IOCTL_GPIO_SETASOUTPUT, // 3
IOCTL_GPIO_SETASINPUT, // 4
IOCTL_GPIO_READTRISTATE, // 5
IOCTL_GPIO_SETPINFUNC, // 6
IOCTL_GPIO_CLEARPINFUNC, // 7
IOCTL_GPIO_GETPINFUNC, // 8
IOCTL_GPIO_SETFREQCONTROL0, // 9
IOCTL_GPIO_SETFREQCONTROL1, // a
IOCTL_GPIO_SETCLOCKSOURCE, // b
IOCTL_GPIO2_SETDIRECTION,
IOCTL_GPIO2_GETDIRECTION,
IOCTL_GPIO2_GETDATAOUTPUT,
IOCTL_GPIO2_SETDATAOUTPUT,
IOCTL_GPIO2_GETPINSTATE
};
//打开设备驱动。GPIO的设备驱动为PIO,在DBAU1200 Boar中的序号为1.该设置可参考Gpio.reg文件
HANDLE hd = CreateFile(TEXT("PIO1:"),GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,0);
if(hd == INVALID_HANDLE_VALUE )
{
return 0x01;
}
ULONG ulTmp;
ULONG ulCmd;
//设置GPIO1的PIN功能。
ulCmd = SYS_PINFUNC_S0C;
DeviceIoControl(
hd,
IOCTL_GPIO_SETPINFUNC,
&ulCmd,
sizeof(ulCmd),
NULL,
0,
&ulTmp,
NULL);
//清除GPIO1的PIN功能
ulCmd = SYS_PINFUNC_S0A|SYS_PINFUNC_S0B;
DeviceIoControl(
hd,
IOCTL_GPIO_CLEARPINFUNC,
&ulCmd,
sizeof(ulCmd),
NULL,
0,
&ulTmp,
NULL);
//关闭设备。
CloseHandle(hd);
return 0;
}
采用该方法,对设备进行读写的唯一通道就是DeviceIoControl函数,通过设置参数2,可以实现不同的功能。
方法二:直接调用gpio.dll
这种方法比较暴力,也比较直接,但所起到的作用和方法一是一致的。
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
//Initialize the function
typedef HANDLE (WINAPI *GPIO_INIT)(void);
GPIO_INIT GPIO_Init;
typedef void (WINAPI *GPIO_ClOSE)(HANDLE);
GPIO_ClOSE GPIO_Close;
typedef BOOL (WINAPI *GPIO_SETPINFUNCTION)(HANDLE,ULONG);
GPIO_SETPINFUNCTION GPIO_SetPinFunction;
typedef BOOL (WINAPI *GPIO_CLEARPINFUNCTION)(HANDLE,ULONG);
GPIO_CLEARPINFUNCTION GPIO_ClearPinFunction;
HINSTANCE hInstDll = LoadLibrary(TEXT("GPIO.dll"));
if(hInstDll != NULL)
{
GPIO_Init = (GPIO_INIT) GetProcAddress(hInstDll,TEXT("GPIO_Init"));
GPIO_Close = (GPIO_ClOSE) GetProcAddress(hInstDll,TEXT("GPIO_Close"));
GPIO_SetPinFunction = (GPIO_SETPINFUNCTION) GetProcAddress(hInstDll,TEXT("GPIO_SetPinFunction"));
GPIO_ClearPinFunction = (GPIO_CLEARPINFUNCTION) GetProcAddress(hInstDll,TEXT("GPIO_ClearPinFunction"));
if(!GPIO_Init || !GPIO_Close || !GPIO_SetPinFunction || !GPIO_ClearPinFunction)
{
MessageBox(NULL,TEXT("The function is NULL!"),TEXT(""),MB_OK);
}
}
else
{
MessageBox(NULL,TEXT("The instance of the Dll is NULL!"),TEXT(""),MB_OK);
return 0x03;
}
HANDLE hGPIO = GPIO_Init();
if(!hGPIO)
{
MessageBox(NULL,TEXT("Failed in GPIO init!"),TEXT(""),MB_OK);
return 0x04;
}
GPIO_SetPinFunction(hGPIO,SYS_PINFUNC_S0C);
GPIO_ClearPinFunction(hGPIO,SYS_PINFUNC_S0A|SYS_PINFUNC_S0B);
GPIO_Close(hGPIO);
//释放资源
FreeLibrary(hInstDll);
MessageBox(NULL,TEXT("Succeed !"),TEXT(""),MB_OK);
return 0;
}
采用方法二有如下函数可以使用:
PIO_Init
PIO_Deinit
PIO_Open
PIO_Close
PIO_Read
PIO_Write
PIO_Seek
PIO_IOControl
PIO_PowerDown
PIO_PowerUp
GPIO_SetPinOutputState
GPIO_ClearPinOutputState
GPIO_GetState
GPIO_SetAsOutput
GPIO_SetAsInput
GPIO_GetTristate
GPIO_ClearPinFunction
GPIO_SetPinFunction
GPIO_GetPinFunction
GPIO_SetClockSourceControl
GPIO_SetFrequencyControl0
GPIO_SetFrequencyControl1
GPIO_Init
GPIO2_SetDirection
GPIO2_GetDirection
GPIO2_SetDataOutput
GPIO2_GetDatatOutput
GPIO2_GetPinState
GPIO_Close
因为GPIO1的每个PIN的功能都不相同,设置sys_pinfunc寄存器其实已经包含设置相对应PIN的意味。在au1x00.h文件中已经将这些功能用宏定义给出:
#define SYS_PINFUNC_DMA (1<<31)
#define SYS_PINFUNC_S0A (1<<30)
#define SYS_PINFUNC_S1A (1<<29)
#define SYS_PINFUNC_LP0 (1<<28)
#define SYS_PINFUNC_LP1 (1<<27)
#define SYS_PINFUNC_LD16 (1<<26)
#define SYS_PINFUNC_LD8 (1<<25)
#define SYS_PINFUNC_LD1 (1<<24)
#define SYS_PINFUNC_LD0 (1<<23)
#define SYS_PINFUNC_P1A (3<<21)
#define SYS_PINFUNC_P1B (1<<20)
#define SYS_PINFUNC_FS3 (1<<19)
#define SYS_PINFUNC_P0A (3<<17)
#define SYS_PINFUNC_CS (1<<16)
#define SYS_PINFUNC_CIM (1<<15)
#define SYS_PINFUNC_P1C (1<<14)
#define SYS_PINFUNC_U1T (1<<12)
#define SYS_PINFUNC_U1R (1<<11)
#define SYS_PINFUNC_EX1 (1<<10)
#define SYS_PINFUNC_EX0 (1<<9)
#define SYS_PINFUNC_U0R (1<<8)
#define SYS_PINFUNC_MC (1<<7)
#define SYS_PINFUNC_S0B (1<<6)
#define SYS_PINFUNC_S0C (1<<5)
#define SYS_PINFUNC_P0B (1<<4)
#define SYS_PINFUNC_U0T (1<<3)
#define SYS_PINFUNC_S1B (1<<2)
和GPIO1不同,每个GPIO2的功能都是相同或类似的,因此如果具体到设置每个PIN,则需要明确指出该PIN的序号:
GPIO2_SetDataOutput(hd,0x0001); //设置GPIO2_0输出为1
之前的代码都是在应用程序中调用,如果需要在驱动中使用则更方便,只需要在驱动中包含gpio.h文件即可。在该文件中,声明了如下函数原型:
extern HANDLE
GPIO_Init(
VOID);
extern VOID
GPIO_Close(
HANDLE);
extern BOOL
GPIO_GetPinFunction(
HANDLE Handle,
PULONG PinFunc);
extern BOOL
GPIO_ClearPinFunction(
HANDLE Handle,
ULONG PinStates);
extern BOOL
GPIO_SetPinFunction(
HANDLE Handle,
ULONG PinFunc);
extern BOOL
GPIO_GetTristate(
HANDLE Handle,
PULONG PinTristates);
extern BOOL
GPIO_SetAsOutput(
HANDLE Handle,
ULONG PinsToSet);
extern BOOL
GPIO_SetAsInput(
HANDLE Handle,
ULONG PinsToSet);
extern BOOL
GPIO_ClearPinOutputState(
HANDLE Handle,
ULONG PinsToClear);
extern BOOL
GPIO_SetPinOutputState(
HANDLE Handle,
ULONG PinsToSet);
extern BOOL
GPIO_GetState(
HANDLE Handle,
PULONG PinStates);
extern BOOL
GPIO_SetClockSourceControl(
HANDLE Handle,
ULONG AndMask,
ULONG OrMask);
extern BOOL
GPIO_SetFrequencyControl1(
HANDLE Handle,
ULONG AndMask,
ULONG OrMask);
extern BOOL
GPIO_SetFrequencyControl0(
HANDLE Handle,
ULONG AndMask,
ULONG OrMask);
extern BOOL
GPIO2_GetPinState(
HANDLE Handle,
PULONG PinState
);
extern BOOL
GPIO2_GetDirection(
HANDLE Handle,
PULONG Direction
);
extern BOOL
GPIO2_SetDirection(
HANDLE Handle,
ULONG AndMask,
ULONG OrMask
);
extern BOOL
GPIO2_GetDatatOutput(
HANDLE Handle,
PULONG DataOutput
);
extern BOOL
GPIO2_SetDataOutput(
HANDLE Handle,
ULONG State
);