控制单个GPIO端口的驱动
// GpioDriver.cpp : Defines the entry point for the DLL application.
//
#include <ceddk.h>
#include "GpioDriver.h"
#include "stdafx.h"
typedef struct _GPIO{
volatile unsigned int PORTCFG0; // 0x000 R/W Port Configuration Register 0
volatile unsigned int PORTCFG1; // 0x004 R/W Port Configuration Register 1
volatile unsigned int PORTCFG2; // 0x008 R/W Port Configuration Register 2
volatile unsigned int PORTCFG3; // 0x00C R/W Port Configuration Register 3
volatile unsigned int PORTCFG4; // 0x010 R/W Port Configuration Register 4
volatile unsigned int PORTCFG5; // 0x014 R/W Port Configuration Register 5
volatile unsigned int PORTCFG6; // 0x018 R/W Port Configuration Register 6
volatile unsigned int PORTCFG7; // 0x01C R/W Port Configuration Register 7
volatile unsigned int PORTCFG8; // 0x020 R/W Port Configuration Register 8
volatile unsigned int PORTCFG9; // 0x024 R/W Port Configuration Register 9
volatile unsigned int PORTCFG10; // 0x028 R/W Port Configuration Register 10
volatile unsigned int PORTCFG11; // 0x02C R/W Port Configuration Register 11
volatile unsigned int PORTCFG12; // 0x030 R/W Port Configuration Register 12
volatile unsigned int PORTCFG13; // 0x034 R/W Port Configuration Register 13
volatile unsigned int NOTDEFINE0; // 0x038 -
volatile unsigned int NOTDEFINE1; // 0x03C -
volatile unsigned int GPADAT; // 0x040 R/W 0x00000000 GPA Data Register
volatile unsigned int GPAEN; // 0x044 R/W 0x00000000 GPA Output Enable Register
volatile unsigned int GPASET; // 0x048 W - OR function on GPA Output Data
volatile unsigned int GPACLR; // 0x04C W - BIC function on GPA Output Data
volatile unsigned int GPAXOR; // 0x050 W - XOR function on GPA Output Data
volatile unsigned int NOTDEFINE2; // 0x054
volatile unsigned int NOTDEFINE3; // 0x058
volatile unsigned int NOTDEFINE4; // 0x05C
volatile unsigned int GPBDAT; // 0x060 R/W 0x00000000 GPB Data Register
volatile unsigned int GPBEN; // 0x064 R/W 0x00000000 GPB Output Enable Register
volatile unsigned int GPBSET; // 0x068 W - OR function on GPB Output Data
volatile unsigned int GPBCLR; // 0x06C W - BIC function on GPB Output Data
volatile unsigned int GPBXOR; // 0x070 W - XOR function on GPB Output Data
volatile unsigned int NOTDEFINE5; // 0x074
volatile unsigned int NOTDEFINE6; // 0x078
volatile unsigned int NOTDEFINE7; // 0x07C
volatile unsigned int GPCDAT; // 0x080 R/W 0x00000000 GPC Data Register
volatile unsigned int GPCEN; // 0x084 R/W 0x00000000 GPC Output Enable Register
volatile unsigned int GPCSET; // 0x088 W - OR function on GPC Output Data
volatile unsigned int GPCCLR; // 0x08C W - BIC function on GPC Output Data
volatile unsigned int GPCXOR; // 0x090 W - XOR function on GPC Output Data
volatile unsigned int NOTDEFINE8; // 0x094
volatile unsigned int NOTDEFINE9; // 0x098
volatile unsigned int NOTDEFINE10; // 0x09C
volatile unsigned int GPDDAT; // 0x0A0 R/W 0x00000000 GPD Data Register
volatile unsigned int GPDEN; // 0x0A4 R/W 0x00000000 GPD Output Enable Register
volatile unsigned int GPDSET; // 0x0A8 W - OR function on GPD Output Data
volatile unsigned int GPDCLR; // 0x0AC W - BIC function on GPD Output Data
volatile unsigned int GPDXOR; // 0x0B0 W - XOR function on GPD Output Data
volatile unsigned int NOTDEFINE11; // 0x0B4
volatile unsigned int NOTDEFINE12; // 0x0B8
volatile unsigned int NOTDEFINE13; // 0x0BC
volatile unsigned int GPEDAT; // 0x0C0 R/W 0x00000000 GPE Data Register
volatile unsigned int GPEEN; // 0x0C4 R/W 0x00000000 GPE Output Enable Register
volatile unsigned int GPESET; // 0x0C8 W - OR function on GPE Output Data
volatile unsigned int GPECLR; // 0x0CC W - BIC function on GPE Output Data
volatile unsigned int GPEXOR; // 0x0D0 W - XOR function on GPE Output Data
volatile unsigned int NOTDEFINE14[3]; // 0x0D4,0x0D8,0x0DC
volatile unsigned int GPFDAT; // 0x0E0 R/W 0x00000000 GPF Data Register
volatile unsigned int GPFEN; //0x0E4 R/W 0x00000000 GPF Output Enable Register
volatile unsigned int GPFSET; //0x0E8 W - OR function on GPF Output Data
volatile unsigned int GPFCLR; //0x0EC W - BIC function on GPF Output Data
volatile unsigned int GPFXOR; //0x0F0 W - XOR function on GPF Output Data
volatile unsigned int NOTDEFINE15[3]; //RESERVED 0x0F4 0x0F8 0x0FC
volatile unsigned int CPUD0 ; //0x100 R/W Pull-Up/Down Control Register 0
volatile unsigned int CPUD1; // 0x104 R/W Pull-Up/Down Control Register 1
volatile unsigned int CPUD2 ; //0x108 R/W Pull-Up/Down Control Register 2
volatile unsigned int CPUD3 ; //0x10C R/W Pull-Up/Down Control Register 3
volatile unsigned int CPUD4; // 0x110 R/W Pull-Up/Down Control Register 4
volatile unsigned int CPUD5; // 0x114 R/W Pull-Up/Down Control Register 5
volatile unsigned int CPUD6; // 0x118 R/W Pull-Up/Down Control Register 6
volatile unsigned int CPUD7; // 0x11C R/W Pull-Up/Down Control Register 7
volatile unsigned int CPUD8; // 0x120 R/W Pull-Up/Down Control Register 8
volatile unsigned int CPUD9 ; //0x124 R/W Pull-Up/Down Control Register 9
volatile unsigned int CPDRV0; // 0x128 R/W Driver strength Control Register 0
volatile unsigned int CPDRV1; // 0x12C R/W
volatile unsigned int AINCFG; // 0x130 R/W 0x00000000 Analog Input Pad Control Register
volatile unsigned int EINTSEL0; // 0x134 R/W 0x00000000 External Interrupt Select Register 0
volatile unsigned int EINTSEL1; // 0x138 R/W 0x00000000 External Interrupt Select Register 1
volatile unsigned int IRQSEL; // 0x13C R/W 0x00000000 Interrupt Select Register
}GPIO, *PGPIO;
#define IOCTL_GPIO_SET_PIN 0x0000050
#define IOCTL_GPIO_CLR_PIN 0x0000070
#define IOCTL_GPIO_DIS_PIN 0x0000090
//寄存器对应的结构体
static volatile GPIO * v_pIOPregs;
static int g_OpenCount = 0; // 驱动打开计数器
#define BASE_ADDRESS 0xF005A000
#define ADDRESS_INTERVAL_GPIO 0x04
#define GPx_GPA 0
/*******************************************************************************************
函数名称: PIO_InitializeAddresses
描 述: 取得相关寄存器的虚拟地址
输入参数: 无
输出参数: 无
返 回: > 0 分配到的虚拟地址; FALSE: 失败
*******************************************************************************************/
static BOOL MyGPIO_InitAddresses(void)
{
BOOL RetValue = TRUE;
// IO Register Allocation
v_pIOPregs = (volatile GPIO *)VirtualAlloc(0, sizeof(GPIO), MEM_RESERVE, PAGE_NOACCESS);
if (v_pIOPregs == NULL)
{
RETAILMSG(1,(TEXT("For IOPregs : VirtualAlloc failed!/r/n")));
RetValue = FALSE;
}
else
{
if (!VirtualCopy((PVOID)v_pIOPregs, (PVOID)(BASE_ADDRESS >> 8), sizeof(GPIO), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE))
{
RETAILMSG(1,(TEXT("For IOPregs: VirtualCopy failed!/r/n")));
RetValue = FALSE;
}
}
if (!RetValue)
{
RETAILMSG (1, (TEXT("::: PIO_InitializeAddresses - Fail!!/r/n") ));
if (v_pIOPregs)
{
VirtualFree((PVOID) v_pIOPregs, 0, MEM_RELEASE);
}
v_pIOPregs = NULL;
RetValue = FALSE;
return RetValue;
}
RETAILMSG(1,(TEXT("For IOPregs : VirtualAlloc SUCCESS!/r/n")));
//配置寄存器选中GPIOE8
// v_pIOPregs->PORTCFG10 &= ~(0x0f << 12);
// v_pIOPregs->PORTCFG10 |= (0x01 << 12);
//配置寄存器为输出模式
// v_pIOPregs->GPEEN |= (0x01 << 8);
return(RetValue);
}
/*******************************************************************************************
函数名称: PIO_Init
描 述: 驱动程序初始化函数
输入参数: DWORD dwContext: 设备管理器传递给本驱动的参数, 通常为流接口驱动在注册表内的位置
输出参数: 无
返 回: 驱动程序句柄
*******************************************************************************************/
DWORD PIO_Init(DWORD dwContext)
{
MyGPIO_InitAddresses();
g_OpenCount = 0;
RETAILMSG(1, (TEXT("PIO_Init!/r/n")));
return (DWORD)1;
}
/*******************************************************************************************
函数名称: DllEntry
描 述: 驱动程序动态库入口
输入参数:
输出参数:
返 回:
*******************************************************************************************/
BOOL DllEntry(HINSTANCE hinst_dll, DWORD reason, LPVOID reserved)
{
switch (reason) {
case DLL_PROCESS_ATTACH:
RETAILMSG(1, (TEXT("[GPIO] Process Attach/r/n")));
break;
case DLL_PROCESS_DETACH:
RETAILMSG(1, (TEXT("[GPIO] Process Detach/r/n")));
break;
}
return TRUE;
}
/*******************************************************************************************
函数名称: PIO_Close
描 述: 驱动程序关闭函数
输入参数: DWORD Handle:驱动程序引用事例句柄
输出参数: 无
返 回: FALSE: 失败 TRUE: 成功
*******************************************************************************************/
BOOL PIO_Close(DWORD Handle)
{
g_OpenCount = 0;
return TRUE;
}
/*******************************************************************************************
函数名称: PIO_Deinit
描 述: 驱动程序卸载函数
输入参数: DWORD dwContext: 驱动程序句柄
输出参数: 无
返 回: FALSE: 失败 TRUE: 成功
*******************************************************************************************/
BOOL PIO_Deinit(DWORD dwContext)
{
g_OpenCount = 0;
if (v_pIOPregs)
VirtualFree((PVOID) v_pIOPregs, 0, MEM_RELEASE); /* 释放申请的虚拟空间 */
return TRUE;
}
/*******************************************************************************************
函数名称: PIO_Open
描 述: 打开驱动程序
输入参数: DWORD dwData : 设备驱动程序句柄
DWORD dwAccess : 访问请求代码,是读和写的组合
DWORD dwShareMode: 共享模式
输出参数:
返 回: 驱动程序引用事例句柄
*******************************************************************************************/
DWORD PIO_Open(DWORD dwData, DWORD dwAccess, DWORD dwShareMode)
{
if (g_OpenCount > 0)
return 0;
g_OpenCount++;
return g_OpenCount; /* 返回一个不为零的数 */
}
/*******************************************************************************************
函数名称: GPIO_SetPin
描 述: 设置某个引脚输出高电平
输入参数: DWORD dwIoControlCode : I/O control code, 指出操作的GPIO组, 如GPA, GPB
BYTE PinNum : 引脚编号, 如 GPB1, 则值为 1
输出参数:
返 回: TRUE: 操作成功 FALSE: 操作失败
*******************************************************************************************/
BOOL GPIO_SetPin(DWORD dwIoControlCode, BYTE PinNum)
{
//配置寄存器选中GPIOE8
v_pIOPregs->PORTCFG10 &= ~(0x0f << 12);
v_pIOPregs->PORTCFG10 |= (0x01 << 12);
//配置寄存器为输出模式
v_pIOPregs->GPEEN |= (0x01 << 8);
//设置数据寄存器为1
v_pIOPregs->GPESET |= (0x01 << 8);
//使能上拉
// v_pIOPregs->CPUD7 &= ~(0x03 << 30);
// v_pIOPregs->CPUD7 |= (0x01 << 30);
return TRUE;
}
/*******************************************************************************************
函数名称: GPIO_ClrPin
描 述: 设置某个引脚输出低电平
输入参数: DWORD dwIoControlCode : I/O control code, 指出操作的GPIO组, 如GPA, GPB
BYTE PinNum : 引脚编号, 如 GPB1, 则值为 1
输出参数:
返 回: TRUE: 操作成功 FALSE: 操作失败
*******************************************************************************************/
BOOL GPIO_ClrPin(DWORD dwIoControlCode, BYTE PinNum)
{
//配置寄存器选中GPIOE8
v_pIOPregs->PORTCFG10 &= ~(0x0f << 12);
v_pIOPregs->PORTCFG10 |= (0x01 << 12);
//配置寄存器为输出模式
v_pIOPregs->GPEEN |= (0x01 << 8);
//设置数据寄存器为0
v_pIOPregs->GPECLR |= (0x01 << 8);
//禁止上拉
// v_pIOPregs->CPUD7 &= ~(0x03 << 30);
// v_pIOPregs->CPUD7 |= (0x02 << 30);
return TRUE;
}
/*******************************************************************************************
函数名称: GPIO_Display
描 述: 设置某个引脚输出低电平
输入参数: DWORD dwIoControlCode : I/O control code, 指出操作的GPIO组, 如GPA, GPB
BYTE PinNum : 引脚编号, 如 GPB1, 则值为 1
输出参数:
返 回: TRUE: 操作成功 FALSE: 操作失败
*******************************************************************************************/
BOOL GPIO_Display(DWORD dwIoControlCode, BYTE PinNum)
{
RETAILMSG(1,(TEXT("GPIO_Display/r/n")));
// Sleep 函数 睡眠 让出权限其他驱动有可能改变寄存器的值
for (int i = 0; i < 100; i++)
{
GPIO_ClrPin(dwIoControlCode, NULL);
Sleep(1000);
GPIO_SetPin(dwIoControlCode, NULL);
Sleep(1000);
}
return TRUE;
}
/*******************************************************************************************
函数名称: PIO_IOControl
描 述: 驱动程序 I/O 请求
输入参数: DWORD dwIoControlCode: 见本文件的头文件
输出参数:
返 回: TRUE: 操作成功 FALSE: 操作失败
*******************************************************************************************/
BOOL
PIO_IOControl(
DWORD Handle,
DWORD dwIoControlCode,
PBYTE pInBuf,
DWORD nInBufSize,
PBYTE pOutBuf,
DWORD nOutBufSize,
PDWORD pBytesReturned
)
{
BOOL bErr = FALSE;
switch(dwIoControlCode)
{
case IOCTL_GPIO_SET_PIN:
GPIO_SetPin(dwIoControlCode, *pInBuf);
RETAILMSG(1,(TEXT("PORTCFG10:,0x%x/r/n"), v_pIOPregs->PORTCFG10));
RETAILMSG(1,(TEXT("CPUD7:,0x%x/r/n"), v_pIOPregs->CPUD7));
RETAILMSG(1,(TEXT("GPEEN:,0x%x/r/n"), v_pIOPregs->GPEEN));
RETAILMSG(1,(TEXT("IOCTL_GPIO_SET_PIN,0x%x/r/n"),v_pIOPregs->GPEDAT));
break;
case IOCTL_GPIO_CLR_PIN:
GPIO_ClrPin(dwIoControlCode, *pInBuf);
RETAILMSG(1,(TEXT("PORTCFG10:,0x%x/r/n"), v_pIOPregs->PORTCFG10));
RETAILMSG(1,(TEXT("CPUD7:,0x%x/r/n"), v_pIOPregs->CPUD7));
RETAILMSG(1,(TEXT("GPEEN:,0x%x/r/n"), v_pIOPregs->GPEEN));
RETAILMSG(1,(TEXT("IOCTL_GPIO_CLR_PIN,0x%x/r/n"), v_pIOPregs->GPEDAT));
break;
case IOCTL_GPIO_DIS_PIN:
RETAILMSG(1,(TEXT("GPIO_Display/r/n")));
GPIO_Display(0, NULL);
break;
}
return true;
}
这次写这个驱动遇到的问题:
1.初始化端口放在了PIO_INIT函数里面,在驱动加载过程中就初始化了端口!这样有可能其他驱动访问相同的端口,导致在PIO_SETPIN 和 PIO_CLRPIN函数中,PORTCFG和GPEEN寄存器的值已经被改回(今天查找一天的Bug就是这个原因)。这样得不到正确的输出波形。
2.GPIO端口默认的是输入模式,是内部拉高的!只有在输出模式下才能改变GPEDAT寄存器的值(我操作的是GPIOE8端口)。