转至:http://blog.sina.com.cn/s/blog_455851af0100ctr8.html
最近在业余时间整了个GPIO的驱动程序,并通过应用程序调用,最终实现通过应用程序调用GPIO的驱动,然后实现硬件上LED灯的亮与灭。这里将整个步骤记录在案,供菜鸟学习。
一:编写驱动程序
1.将硬件厂商提供的BSP包拷备到D:\WINCE500\PLATFORM下,如SMDK2440;在D:\WINCE500\PLATFORM\smdk2440\DRIVERS中建一个用于存放驱动程序的文件夹;建立相应文件,这里我命名为FlowLED,对应的文件名分别为:
FlowLED.c
FlowLED.h
FlowLED.def
makefile sources
2.以上文件对应代码如下:
//以下是FlowLED.c的代码:
#include #include
//#include "ceddk.h"
#include "S2440.h"
#define IO_CTL_LED_1_ON 0x01
#define IO_CTL_LED_2_ON 0x02
#define IO_CTL_LED_3_ON 0x03
#define IO_CTL_LED_4_ON 0x04
#define IO_CTL_LED_ALL_ON 0x05
#define IO_CTL_LED_1_OFF 0x06
#define IO_CTL_LED_2_OFF 0x07
#define IO_CTL_LED_3_OFF 0x08
#define IO_CTL_LED_4_OFF 0x09
#define IO_CTL_LED_ALL_OFF 0x0a
BOOL mInitialized;
volatile IOPreg *s2440IOP = (IOPreg *)IOP_BASE;
void Virtual_Alloc()
{
s2440IOP = (volatile IOPreg *) VirtualAlloc(0,sizeof(IOPreg),MEM_RESERVE, PAGE_NOACCESS);
if(s2440IOP == NULL)
{
}
else if(!VirtualCopy((PVOID)s2440IOP,(PVOID)(IOP_BASE),sizeof(IOPreg),PAGE_READWRITE | PAGE_NOCACHE ))
{
}
else
{
}
}
BOOL LEDGpioInit() //为什么没有配置GPFUP?
{
RETAILMSG(1,(TEXT("LED_Gpio_Setting----\r\n")));
s2440IOP->rGPFCON = (s2440IOP->rGPFCON &~(3 << 8) | (1<< 8) ); // GPF4 == OUTPUT.
s2440IOP->rGPFCON = (s2440IOP->rGPFCON &~(3 << 10) | (1<< 10) ); // GPF5 == OUTPUT.
s2440IOP->rGPFCON = (s2440IOP->rGPFCON &~(3 << 12) | (1<< 12) ); // GPF6 == OUTPUT.
s2440IOP->rGPFCON = (s2440IOP->rGPFCON &~(3 << 14) | (1<< 14) ); // GPF7 == OUTPUT.
return TRUE;
}
BOOL WINAPI DllEntry(HANDLE hInstDll, DWORD dwReason, LPVOID lpvReserved)
{
switch ( dwReason )
{ case DLL_PROCESS_ATTACH:
}
return(TRUE);
}
DWORD LED_Init(DWORD dwContext)
{
RETAILMSG(1,(TEXT("LED_Init----\r\n")));
// 1. Virtual Alloc
Virtual_Alloc();
LEDGpioInit();
mInitialized = TRUE; return TRUE;
}
BOOL LED_Deinit(DWORD hDeviceContext)
{
BOOL bRet = TRUE;
RETAILMSG(1,(TEXT("USERLED: LED_Deinit\r\n")));
return TRUE;
}
DWORD LED_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode)
{
RETAILMSG(1,(TEXT("USERLED: LED_Open\r\n")));
return TRUE;
}
BOOL LED_Close(DWORD hOpenContext)
{
s2440IOP->rGPBDAT=s2440IOP->rGPBDAT&(0xF<<5);
RETAILMSG(1,(TEXT("USERLED: LED_Close\r\n")));
return TRUE;
}
BOOL LED_IOControl(DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut)
{
switch(dwCode)
{
case IO_CTL_LED_1_ON: s2440IOP->rGPFDAT=s2440IOP->rGPFDAT&~(0x1<<4);
case IO_CTL_LED_2_ON: s2440IOP->rGPFDAT=s2440IOP->rGPFDAT&~(0x1<<5); break;
case IO_CTL_LED_3_ON: s2440IOP->rGPFDAT=s2440IOP->rGPFDAT&~(0x1<<6); break;
case IO_CTL_LED_4_ON: s2440IOP->rGPFDAT=s2440IOP->rGPFDAT&~(0x1<<7); break;
case IO_CTL_LED_ALL_ON: s2440IOP->rGPFDAT=s2440IOP->rGPFDAT&~(0xF<<4); break;
case IO_CTL_LED_1_OFF: s2440IOP->rGPFDAT=s2440IOP->rGPFDAT|(0x1<<4); break;
case IO_CTL_LED_2_OFF: s2440IOP->rGPFDAT=s2440IOP->rGPFDAT|(0x1<<5); break;
case IO_CTL_LED_3_OFF: s2440IOP->rGPFDAT=s2440IOP->rGPFDAT|(0x1<<6); break;
case IO_CTL_LED_4_OFF: s2440IOP->rGPFDAT=s2440IOP->rGPFDAT|(0x1<<7); break;
case IO_CTL_LED_ALL_OFF: s2440IOP->rGPFDAT=s2440IOP->rGPFDAT|(0xF<<4); break;
default: break;
}
RETAILMSG(1,(TEXT("LED:IOCTL code = 0x%x\r\n"), dwCode));
RETAILMSG(1,(TEXT("GPFDAT = 0x%x\r\n"),s2440IOP->rGPFDAT));
return TRUE;
}
DWORD LED_Read(DWORD hOpenContext, LPVOID pBuffer, DWORD Count)
{
RETAILMSG(1,(TEXT("USERLED: LED_Read\r\n")));
return TRUE;
{
RETAILMSG(1,(TEXT("USERLED: LED_Write\r\n")));
return 0;
}
DWORD LED_Seek(DWORD hOpenContext, long Amount, DWORD Type)
{
RETAILMSG(1,(TEXT("USERLED: LED_Seek\r\n")));
return 0;
}
void LED_PowerUp(DWORD hDeviceContext)
{
RETAILMSG(1,(TEXT("USERLED: LED_PowerUp\r\n")));
}
void LED_PowerDown(DWORD hDeviceContext)
{
RETAILMSG(1,(TEXT("USERLED: LED_PowerDown\r\n")));
}
//以下是FlowLED.def的代码:
LIBRARY FlowLED
EXPORTS
LED_Init
LED_Deinit
LED_Open
LED_Close
LED_Read
LED_Write
LED_Seek
LED_IOControl
LED_PowerDown
LED_PowerUp
//以下是sources的代码:
TARGETNAME=FlowLED
RELEASETYPE=PLATFORM
TARGETTYPE=DYNLINK
TARGETLIBS=$(_COMMONSDKROOT)\lib\$(_CPUINDPATH)\coredll.lib
DEFFILE=$(TARGETNAME).def
DLLENTRY=DllEntry SOURCES=FlowLED.c
makefile的代码直接拷备其他驱动下的即可,不要更改!
二:加载驱动在D:\WINCE500\PLATFORM\smdk2440\DRIVERS中,找到dirs文件,打开添加驱动。添加后的代码如下:
DIRS=
\ FlowLED
\ drvlib
\ serial
\ wavedev
\ wavclick
\ display
\ backlite
\ usb
\ pcmcia
\ keybd
\ touchp
\ nandflsh
\ Camera
\ pwrbtn_pcf
\ cs8900
\ CANBus
\ dm9000
\ atapi
在platform.bib中添加编写的驱动,添加后的部分代码如下:
;fly for IDE Hard disk IF BSP_IDE ;atapi.dll
$(_FLATRELEASEDIR)\atapi.dll NK SH
ENDIF
FLowLED.dll $(_FLATRELEASEDIR)\FlowLED.dll NK SH
; wghdriver.dll $(_FLATRELEASEDIR)\wghdriver.dll NK SH FILES
; Name Path Memory Type
在platform.reg中添加驱动的注册表,需要添加的代码如下:
;FlowLED [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\LED]
"Prefix"="LED" "Dll"="FlowLED.dll"
"FriendlyName"="Flow LED"
"Index"=dword:0
"Order"=dword:0
注意这里的platform.bib和platform.reg通过PB修改后,未必在release中也更新了,一定要将改过的拷备到release中!即从 D:\WINCE500\PLATFORM\smdk2440\FILES 中拷备到 D:\WINCE500\PBWorkspaces\lqm\RelDir\smdk2440_ARMV4I_Release 中!否则就算PB上显示驱动已经加进去了,生成的NK里面也不会有该驱动的程序!
三:编译所要加载的驱动,并生成NK 直接右键点击加载的驱动,点Build current project; 然后在Build OS菜单栏下点Make Run-time image,即生成NK了。
四:将生成的NK下载到开发板上 五:在EVC4.0环境下,编写应用程序。
1.建立GPIO控制的对话框。这里建立了四个按键:
a:打开GPIO驱动
b:关闭GPIO驱动
c:点亮LED灯
d:关闭LED灯
2.对话框实现代码如下:
// GPIOControlDlg.cpp : implementation file
//
#include "stdafx.h"
#include "GPIOControl.h"
#include "GPIOControlDlg.h"
#include "GPIO.h"
HANDLE hFile=INVALID_HANDLE_VALUE;
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
/
// CGPIOControlDlg dialog CGPIOControlDlg::CGPIOControlDlg(CWnd* pParent ) : CDialog(CGPIOControlDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CGPIOControlDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CGPIOControlDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CGPIOControlDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CGPIOControlDlg, CDialog)
//{{AFX_MSG_MAP(CGPIOControlDlg)
ON_BN_CLICKED(IDC_OPEN_GPIO, OnOpenGpio)
ON_BN_CLICKED(IDC_LED_OFF, OnLedOff)
ON_BN_CLICKED(IDC_CLOSE_GPIO, OnCloseGpio)
ON_BN_CLICKED(IDC_LED_ON, OnLedOn)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CGPIOControlDlg message handlers
BOOL CGPIOControlDlg::OnInitDialog()
{ CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
CenterWindow(GetDesktopWindow());
// center to the hpc screen
// TODO: Add extra initialization here
return TRUE;
// return TRUE unless you set the focus to a control }
//打开GPIO驱动,这里LED0表示需要调用的驱动的名字。如果出错则无法打开驱动!
void CGPIOControlDlg::OnOpenGpio()
{
hFile=CreateFile(TEXT("LED0:"),GENERIC_READ | GENERIC_WRITE,0, NULL,OPEN_EXISTING,0,0);
if(hFile==INVALID_HANDLE_VALUE)
{
MessageBox(_T("打开GPIO驱动失败!"));
}
else
{
MessageBox(_T("打开GPIO驱动成功!"));
}
}
//关闭GPIO驱动
void CGPIOControlDlg::OnCloseGpio()
{
if(hFile!=INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
MessageBox(_T("关闭GPIO驱动成功!"));
}
else
{
MessageBox(_T("关闭GPIO驱动失败!"));
}
}
//
void CGPIOControlDlg::OnLedOff()
{
BOOL ret;
ret=::DeviceIoControl(hFile,IO_CTL_LED_ALL_OFF,NULL, 1,NULL,0,NULL,NULL);
if(ret!=TRUE)
{
MessageBox(_T("关闭LED失败!"));
MessageBox(_T("请打开GPIO驱动!"));
}
}
void CGPIOControlDlg::OnLedOn()
{
BOOL ret; ret=::DeviceIoControl(hFile,IO_CTL_LED_ALL_ON,NULL, 1,NULL,0,NULL,NULL);
if(ret!=TRUE)
{ MessageBox(_T("点亮LED失败!"));
MessageBox(_T("请打开GPIO驱动!")); } }
3.这里使用了GPIO.h的头文件,具体内容如下:
#ifndef __GPIO_H__
#define __GPIO_H__
#ifdef __cplusplus extern "C"
{ #endif
//定义四盏灯的工作状态,对应驱动中的LED_IOControl
#define IO_CTL_LED_1_ON 0x01
#define IO_CTL_LED_2_ON 0x02
#define IO_CTL_LED_3_ON 0x03
#define IO_CTL_LED_4_ON 0x04
#define IO_CTL_LED_ALL_ON 0x05
#define IO_CTL_LED_1_OFF 0x06
#define IO_CTL_LED_2_OFF 0x07
#define IO_CTL_LED_3_OFF 0x08
#define IO_CTL_LED_4_OFF 0x09
#define IO_CTL_LED_ALL_OFF 0x0a
#define GPIO_A 0x00 #define GPIO_B 0x01
#define GPIO_C 0x02 #define GPIO_D 0x03
#define GPIO_E 0x04 #define GPIO_F 0x05
#define GPIO_G 0x06 #define GPIO_H 0x07
#define IOCTL_GPIO_FUN_MASK 0x00000F0
#define IOCTL_GPX_MASK 0x000000F
#define IOCTL_GPIO_SET_PIN_OUT 0x0000010
#define IOCTL_GPA_SET_PIN_OUT 0x0000010
#define IOCTL_GPB_SET_PIN_OUT 0x0000011
#define IOCTL_GPC_SET_PIN_OUT 0x0000012
#define IOCTL_GPD_SET_PIN_OUT 0x0000013
#define IOCTL_GPE_SET_PIN_OUT 0x0000014
#define IOCTL_GPF_SET_PIN_OUT 0x0000015
#define IOCTL_GPG_SET_PIN_OUT 0x0000016
#define IOCTL_GPH_SET_PIN_OUT 0x0000017
#define IOCTL_GPIO_SET_MULTI_PIN_OUT 0x0000020
#define IOCTL_GPA_SET_MULTI_PIN_OUT 0x0000020
#define IOCTL_GPB_SET_MULTI_PIN_OUT 0x0000021
#define IOCTL_GPC_SET_MULTI_PIN_OUT 0x0000022
#define IOCTL_GPD_SET_MULTI_PIN_OUT 0x0000023
#define IOCTL_GPE_SET_MULTI_PIN_OUT 0x0000024
#define IOCTL_GPF_SET_MULTI_PIN_OUT 0x0000025
#define IOCTL_GPG_SET_MULTI_PIN_OUT 0x0000026
#define IOCTL_GPH_SET_MULTI_PIN_OUT 0x0000027
#define IOCTL_GPIO_SET_PIN_IN 0x0000030
#define IOCTL_GPA_SET_PIN_IN 0x0000030
#define IOCTL_GPB_SET_PIN_IN 0x0000031
#define IOCTL_GPC_SET_PIN_IN 0x0000032
#define IOCTL_GPD_SET_PIN_IN 0x0000033
#define IOCTL_GPE_SET_PIN_IN 0x0000034
#define IOCTL_GPF_SET_PIN_IN 0x0000035
#define IOCTL_GPG_SET_PIN_IN 0x0000036
#define IOCTL_GPH_SET_PIN_IN 0x0000037
#define IOCTL_GPIO_SET_MULTI_PIN_IN 0x0000040
#define IOCTL_GPA_SET_MULTI_PIN_IN 0x0000040
#define IOCTL_GPB_SET_MULTI_PIN_IN 0x0000041
#define IOCTL_GPC_SET_MULTI_PIN_IN 0x0000042
#define IOCTL_GPD_SET_MULTI_PIN_IN 0x0000043
#define IOCTL_GPE_SET_MULTI_PIN_IN 0x0000044
#define IOCTL_GPF_SET_MULTI_PIN_IN 0x0000045
#define IOCTL_GPG_SET_MULTI_PIN_IN 0x0000046
#define IOCTL_GPH_SET_MULTI_PIN_IN 0x0000047
#define IOCTL_GPIO_SET_PIN 0x0000050
#define IOCTL_GPA_SET_PIN 0x0000050
#define IOCTL_GPB_SET_PIN 0x0000051
#define IOCTL_GPC_SET_PIN 0x0000052
#define IOCTL_GPD_SET_PIN 0x0000053
#define IOCTL_GPE_SET_PIN 0x0000054
#define IOCTL_GPF_SET_PIN 0x0000055
#define IOCTL_GPG_SET_PIN 0x0000056
#define IOCTL_GPH_SET_PIN 0x0000057
#define IOCTL_GPIO_SET_MULTI_PIN 0x0000060
#define IOCTL_GPA_SET_MULTI_PIN 0x0000060
#define IOCTL_GPB_SET_MULTI_PIN 0x0000061
#define IOCTL_GPC_SET_MULTI_PIN 0x0000062
#define IOCTL_GPD_SET_MULTI_PIN 0x0000063
#define IOCTL_GPE_SET_MULTI_PIN 0x0000064
#define IOCTL_GPF_SET_MULTI_PIN 0x0000065
#define IOCTL_GPG_SET_MULTI_PIN 0x0000066
#define IOCTL_GPH_SET_MULTI_PIN 0x0000067
#define IOCTL_GPIO_CLR_PIN 0x0000070
#define IOCTL_GPA_CLR_PIN 0x0000070
#define IOCTL_GPB_CLR_PIN 0x0000071
#define IOCTL_GPC_CLR_PIN 0x0000072
#define IOCTL_GPD_CLR_PIN 0x0000073
#define IOCTL_GPE_CLR_PIN 0x0000074
#define IOCTL_GPF_CLR_PIN 0x0000075
#define IOCTL_GPG_CLR_PIN 0x0000076
#define IOCTL_GPH_CLR_PIN 0x0000077
#define IOCTL_GPIO_CLR_MULTI_PIN 0x0000080
#define IOCTL_GPA_CLR_MULTI_PIN 0x0000080
#define IOCTL_GPB_CLR_MULTI_PIN 0x0000081
#define IOCTL_GPC_CLR_MULTI_PIN 0x0000082
#define IOCTL_GPD_CLR_MULTI_PIN 0x0000083
#define IOCTL_GPE_CLR_MULTI_PIN 0x0000084
#define IOCTL_GPF_CLR_MULTI_PIN 0x0000085
#define IOCTL_GPG_CLR_MULTI_PIN 0x0000086
#define IOCTL_GPH_CLR_MULTI_PIN 0x0000087
#define IOCTL_GPIO_READ_PIN 0x0000090
#define IOCTL_GPA_READ_PIN 0x0000090
#define IOCTL_GPB_READ_PIN 0x0000091
#define IOCTL_GPC_READ_PIN 0x0000092
#define IOCTL_GPD_READ_PIN 0x0000093
#define IOCTL_GPE_READ_PIN 0x0000094
#define IOCTL_GPF_READ_PIN 0x0000095
#define IOCTL_GPG_READ_PIN 0x0000096
#define IOCTL_GPH_READ_PIN 0x0000097
#define IOCTL_GPIO_READ_ALL_PIN 0x00000A0
#define IOCTL_GPA_READ_ALL_PIN 0x00000A0
#define IOCTL_GPB_READ_ALL_PIN 0x00000A1
#define IOCTL_GPC_READ_ALL_PIN 0x00000A2
#define IOCTL_GPD_READ_ALL_PIN 0x00000A3
#define IOCTL_GPE_READ_ALL_PIN 0x00000A4
#define IOCTL_GPF_READ_ALL_PIN 0x00000A5
#define IOCTL_GPG_READ_ALL_PIN 0x00000A6
#define IOCTL_GPH_READ_ALL_PIN 0x00000A7
#define IOCTL_GPIO_EN_PULLUP 0x00000B0
#define IOCTL_GPA_EN_PULLUP 0x00000B0
#define IOCTL_GPB_EN_PULLUP 0x00000B1
#define IOCTL_GPC_EN_PULLUP 0x00000B2
#define IOCTL_GPD_EN_PULLUP 0x00000B3
#define IOCTL_GPE_EN_PULLUP 0x00000B4
#define IOCTL_GPF_EN_PULLUP 0x00000B5
#define IOCTL_GPG_EN_PULLUP 0x00000B6
#define IOCTL_GPH_EN_PULLUP 0x00000B7
#define IOCTL_GPIO_EN_MULTI_PIN_PULLUP 0x00000C0
#define IOCTL_GPA_EN_MULTI_PIN_PULLUP 0x00000C0
#define IOCTL_GPB_EN_MULTI_PIN_PULLUP 0x00000C1
#define IOCTL_GPC_EN_MULTI_PIN_PULLUP 0x00000C2
#define IOCTL_GPE_EN_MULTI_PIN_PULLUP 0x00000C4
#define IOCTL_GPF_EN_MULTI_PIN_PULLUP 0x00000C5
#define IOCTL_GPG_EN_MULTI_PIN_PULLUP 0x00000C6
#define IOCTL_GPH_EN_MULTI_PIN_PULLUP 0x00000C7
#define IOCTL_GPIO_DIS_PULLUP 0x00000D0
#define IOCTL_GPA_DIS_PULLUP 0x00000D0
#define IOCTL_GPB_DIS_PULLUP 0x00000D1
#define IOCTL_GPC_DIS_PULLUP 0x00000D2
#define IOCTL_GPD_DIS_PULLUP 0x00000D3
#define IOCTL_GPE_DIS_PULLUP 0x00000D4
#define IOCTL_GPF_DIS_PULLUP 0x00000D5
#define IOCTL_GPG_DIS_PULLUP 0x00000D6
#define IOCTL_GPH_DIS_PULLUP 0x00000D7
#define IOCTL_GPIO_DIS_MULTI_PIN_PULLUP 0x00000E0
#define IOCTL_GPA_DIS_MULTI_PIN_PULLUP 0x00000E0
#define IOCTL_GPB_DIS_MULTI_PIN_PULLUP 0x00000E1
#define IOCTL_GPC_DIS_MULTI_PIN_PULLUP 0x00000E2
#define IOCTL_GPD_DIS_MULTI_PIN_PULLUP 0x00000E3
#define IOCTL_GPE_DIS_MULTI_PIN_PULLUP 0x00000E4
#define IOCTL_GPF_DIS_MULTI_PIN_PULLUP 0x00000E5
#define IOCTL_GPG_DIS_MULTI_PIN_PULLUP 0x00000E6
#define IOCTL_GPH_DIS_MULTI_PIN_PULLUP 0x00000E7
#define IOCTL_GPIO_READ_PORT 0x00000F0
#define IOCTL_GPA_READ_PORT 0x00000F0
#define IOCTL_GPB_READ_PORT 0x00000F1
#define IOCTL_GPC_READ_PORT 0x00000F2
#define IOCTL_GPD_READ_PORT 0x00000F3
#define IOCTL_GPE_READ_PORT 0x00000F4
#define IOCTL_GPF_READ_PORT 0x00000F5
#define IOCTL_GPG_READ_PORT 0x00000F6
#define IOCTL_GPH_READ_PORT 0x00000F7
#ifdef __cplusplus
}
#endif
#endif
// __GPIO_H__
4.将PC与开发板同步,编译EVC4.0下的代码并下载生成的可执行文件到开发板上,运行生成的可执行文件。可以发现,开发板上的四盏灯已经听你的使唤了!