GPIO 是ARM芯片最基本的输入输出通道,在ADS下操作就是一个单片机工作,直接读写其寄存器。在ARM9平台上,Windows CE系统将GPIO的实地址(例如2410的GPIO的基地址为0x56000000)映射到虚拟地址空间(GPIO对应为0xB1600000),这 样,通过对这段虚拟地址空间的操作,就能够完成对GPIO或者其他片内资源的控制、输入输出工作。
要操作一个平台的GPIO,在其对应BSP中按照基地址,找到虚拟地址,并且找到方便操作这个地址的数据结构就可以了,关键函数就是 VirtualAlloc和VirtualCopy。并且CE的方便之处就是用户态的应用程序仍然可以使用这两个函数来访问所有这些虚拟空间,对于不太复 杂的程序,甚至可以省略写驱动直接在应用程序中操作,其实在CE6之前,这些驱动也是工作在用户态的。
下面以操作Samsung S3C2410的GPIO为例,讲述这个步骤:
1.首先在BSP中的s2410.h文件,找到虚拟地址映射以及操作GPIO的寄存器结构体(这个在自己制作一些特殊设备的BSP时,会依据需要而发生更改)
//
// Registers : I/O port
//#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.在EVC中建立一个应用程序工程,由于VirtualCopy函数没有在头文件中定义,但是在coredll.lib里面提供了符号连接,所以我们这里直接添加一个函数定义就OK了。
#ifdef __cplusplus
extern "C"
{
#endif
BOOL VirtualCopy( LPVOID, LPVOID, DWORD, DWORD );
#ifdef __cplusplus
}
#endif
同时将步骤1里面的定义复制到这里。
3.按照驱动程序里面操作的方法在应用程序中写GPIO操作函数
(1)定义一个寄存器结构体变量
volatile IOPreg *v_pIOPRegs;
(2)给这个变量分配空间并且映射到寄存器的空间上
v_pIOPRegs = (volatile IOPreg*)VirtualAlloc(0, sizeof(IOPreg), MEM_RESERVE, PAGE_NOACCESS);
if (v_pIOPRegs == NULL)
{
DEBUGMSG (1,(TEXT("v_pIOPRegs is not allocated ")));
return TRUE;
}
if (!VirtualCopy((PVOID)v_pIOPRegs, (PVOID)IOP_BASE, sizeof(IOPreg), PAGE_READWRITE|PAGE_NOCACHE)) {
DEBUGMSG (1,(TEXT("v_pIOPRegs is not mapped ")));
return TRUE;
}
DEBUGMSG (1,(TEXT("v_pIOPRegs is mapped to %x "), v_pIOPRegs));
这3个步骤之后,对v_pIOPRegs的操作将直接和GPIO的寄存器关联
例如:设置GPB的控制寄存器为全部Output
v_pIOPRegs->rGPBCON=0x155555;
设置GPB的数据寄存器输出高电平
v_pIOPRegs->rGPBDAT=0x3FF;
更多的操作,需要查阅ARM的datasheet以及WINCE的BSP源码完成。
对于非ARM的平台,在CE下操作,也可以参考这个思路。
////////////////////////////////////////////////////////////////////////////////////////////////////////
Telechip 参考:http://blog.csdn.net/norains/archive/2010/11/09/5997230.aspx
操作LCD Register 代码:
#ifndef _VIRTUAL_H_
#define _VIRTUAL_H_
#include <windows.h>
#ifdef __TCC89XX_WINCE__
#define __HDMI_INCLUDE__
//#define __ROTATE_INCLUDE__
//#define __2DACCELATE_CHECK__ // After BSP v2664
//#define __SCALER1_INCLUDE__ // this define used at TCMovieManager CM2MScaler Class
//#define __WITH_PHOTOPLAY__
#ifdef __HDMI_INCLUDE__
#define __HDMI_SUBTITLE__
#endif
#ifdef __HDMI_INCLUDE__
#define SCALER_YSIZE 0x00200000
#else
#define SCALER_YSIZE 0x00100000
#endif
#define UV_FACTOR 1 // M2M Scaler Output UV data Size factor. YUV422->1, YUV420 -> 2
// YUV422[2]->(Y[1]+U[1/2]+V[1/2]) -> Y[1] + UV[1]
// YUV420[1+1/2]->(Y[1]+U[1/4]+V[1/4] -> Y[1] + UV[1/2]
#define SCALER_UVSIZE SCALER_YSIZE/UV_FACTOR
#define SCALER_BUFF_SIZE (SCALER_YSIZE + SCALER_UVSIZE)
#ifdef __ROTATE_INCLUDE__
#define ROTATE_BUFF_SIZE SCALER_BUFF_SIZE
#else
#define ROTATE_BUFF_SIZE 0
#endif
#ifdef __HDMI_SUBTITLE__
#define HDMI_SUBTITLE_BUFF_SIZE 0x00100000
#else
#define HDMI_SUBTITLE_BUFF_SIZE 0
#endif
#ifdef __SCALER1_INCLUDE__
#define SCALER1_BUFF_SIZE SCALER_BUFF_SIZE
#define JPEG_ENC_BUFF_SIZE 0x00080000
#else
#define SCALER1_BUFF_SIZE 0
#define JPEG_ENC_BUFF_SIZE 0
#endif
#ifdef __WITH_PHOTOPLAY__
#define PHOTODEC_BUFF_SIZE 0x01A00000
#else
#define PHOTODEC_BUFF_SIZE 0
#endif
// Current Offset = Previous Offset + Previous Region Size(Not Current Region Size)
///////////////////////////////////////////////////////////////////////////
#define SCALER0_MEM0_OFFSET PHOTODEC_BUFF_SIZE //0
#define SCALER0_MEM1_OFFSET SCALER0_MEM0_OFFSET + SCALER_BUFF_SIZE
#define SCALER1_MEM0_OFFSET SCALER0_MEM1_OFFSET + SCALER_BUFF_SIZE
#define ROTATE1_MEM_OFFSET SCALER1_MEM0_OFFSET + SCALER1_BUFF_SIZE // *2
#define ROTATE2_MEM_OFFSET ROTATE1_MEM_OFFSET + ROTATE_BUFF_SIZE
#define JPEG_ENC_MEM_OFFSET (ROTATE2_MEM_OFFSET+ROTATE_BUFF_SIZE)
#define HDMI_SUBTITLE_MEM_OFFSET JPEG_ENC_MEM_OFFSET+JPEG_ENC_BUFF_SIZE
#define VIDEO_DEC_MEM_OFFSET (HDMI_SUBTITLE_MEM_OFFSET + HDMI_SUBTITLE_BUFF_SIZE)
#define CAMERA_MEM_OFFSET VIDEO_DEC_MEM_OFFSET
#define CAMERA_MEM_SIZE 0x900000 // preview 3 frame(max 1280x729 YUV422) + capture 1 frame(max 1600x1200)
#define VIDEO_ENC_MEM_OFFSET CAMERA_MEM_OFFSET + CAMERA_MEM_SIZE
typedef struct _UID_MEM {
DWORD dwHwBaseAddress;
DWORD dwAllocBaseAddress;
DWORD dwSize;
}UID_MEM;
extern volatile LPVOID SetVirtual(unsigned int HwBaseAddress, unsigned int nSize);
extern void FreeVirtual(LPVOID pVirtualAddress, unsigned int nSize);
#else
#include "Pkfuncs.h"
#define SHARED_MEM_PHYSADDR 0xA0000000
//#define RAM128
#ifdef RAM128
#define HW_MEM_BASE 0x27C00000
#else
#define HW_MEM_BASE 0x23C00000
#endif
#define HW_MEM_LIMIT 0x00400000
#define OUTBUFFER_BASE HW_MEM_BASE
#define OUTBUFFER_LIMIT 0x00300000
#define INBUFFER_BASE (HW_MEM_BASE + OUTBUFFER_LIMIT)
#define INBUFFER_LIMIT 0x00040000
#define DATABUFFER_BASE (HW_MEM_BASE + OUTBUFFER_LIMIT + INBUFFER_LIMIT)
#define DATABUFFER_LIMIT 0x00040000
#define SCALER_OUT1 (HW_MEM_BASE + OUTBUFFER_LIMIT + INBUFFER_LIMIT + DATABUFFER_LIMIT)
#define SCALER_OUT2 (HW_MEM_BASE + OUTBUFFER_LIMIT + INBUFFER_LIMIT + DATABUFFER_LIMIT + SCALER_LIMIT)
#define SCALER_LIMIT 0x00040000
#define HW_MEM_BASE_TCC79X 0x20100000 // for TCC79x (defaul value)
#define SCALER_TCC79X_OUT1 0x20480000 // for TCC79x (default value)
#define SCALER_TCC79X_OUT2 0x204C0000 // for TCC79x (default value)
#define DFLT_BASE_WMV9_ROBASE 0x10004000
#define DFLT_BASE_MPEG2_ROBASE 0x10008000
#define DFLT_BASE_MPEG2_HTBASE 0x10016000
#define DFLT_BASE_MPEG4SP_ROBASE 0x10004000
#define DFLT_BASE_MPEG4SP_HTBASE 0x10016000
#define MBMEM0BASE 0x10010000
#define MBMEM0BASE_SIZE 6144
#define DFLT_BASE_JPEGDEC_ROBASE 0x10008000
#define DFLT_BASE_JPEGDEC_ROBASE_LIBV033 0x10004000
#define DFLT_BASE_JPEGENC_ROBASE 0x10008000
#define PHY_ADDR_R_PINGPONG_1 0x10014000
#define PHY_ADDR_R_PINGPONG_2 0x10016000
extern volatile LPVOID SetVirtual(unsigned int physical_addr, unsigned int mem_size);
extern volatile LPVOID SetVirtualCache(unsigned int physical_addr, unsigned int mem_size);
extern void FreeVirtual(LPVOID virtual_ptr, unsigned int mem_size);
#endif // __TCC89XX_WINCE__
#endif // _VIRTUAL_H_
#include "StdAfx.h"
#include "Virtual.h"
#ifndef __TCC89XX_WINCE__
#include <ceddk.h>
volatile LPVOID SetVirtual(unsigned int physical_addr, unsigned int mem_size)
{
LPVOID pVirtual;
PHYSICAL_ADDRESS PA;
PA.LowPart = (DWORD)(physical_addr);
pVirtual = (DWORD*)MmMapIoSpace(PA,mem_size, FALSE);
if(!pVirtual){
printf("MmMapIoSpace GetLastError() : %d\n",GetLastError());
return NULL;
}
return pVirtual;
}
volatile LPVOID SetVirtualCache(unsigned int physical_addr, unsigned int mem_size)
{
LPVOID pVirtual;
PHYSICAL_ADDRESS PA;
PA.LowPart = (DWORD)(physical_addr);
pVirtual = (DWORD*)MmMapIoSpace(PA,mem_size, TRUE);
if(!pVirtual){
printf("MmMapIoSpace GetLastError() : %d\n",GetLastError());
return NULL;
}
return pVirtual;
}
void FreeVirtual(LPVOID virtual_ptr, unsigned int mem_size)
{
MmUnmapIoSpace(virtual_ptr, mem_size);
}
#else
#include "ioctl_code.h"
#include "Pkfuncs.h"
volatile LPVOID SetVirtual(unsigned int HwBaseAddress, unsigned int nSize)
{
volatile LPVOID pVirtual;
UID_MEM uid_mem;
if(HwBaseAddress&0xFFF)
{
RETAILMSG(1,(TEXT("Need to Align Baseaddress.. (%x) \n"),HwBaseAddress&0xFFF));
return NULL;
}
//need align 8bit
uid_mem.dwHwBaseAddress = (DWORD)(HwBaseAddress>>8);
//alloc virtual space
pVirtual = VirtualAlloc(0,
nSize,
MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
uid_mem.dwAllocBaseAddress =(DWORD)pVirtual;
//define alloc size
uid_mem.dwSize = nSize;
DWORD nhRet =KernelIoControl(IOCTL_HAL_VIRTUALCOPY,&uid_mem, sizeof(UID_MEM), NULL, NULL, NULL);
return pVirtual;
}
void FreeVirtual(LPVOID pVirtualAddress, unsigned int nSize)
{
if(VirtualFree(pVirtualAddress, 0, MEM_RELEASE) == 0)
{
RETAILMSG(1,(TEXT("(VirtualFree Fail.. (%d) \n"),GetLastError()));
}
}
#endif