最近在调试一块S3C6410的核心板。为了验证核心板扩展槽上的所有接口,LD特地设计了一个扩展底板,上面遍布红红绿绿的LED。软件上用总线读写和GPIO来控制这些灯。观察LED的亮灭,该亮的亮,该灭的灭,说明接口没有问题,否则就需要拿给硬件检查了。
考虑到既有总线读写,又有大量的GPIO控制,写驱动程序会相当麻烦,所以使用了《WinCE6.0中应用程序如何直接访问物理空间》中介绍的方法,直接在测试程序中实现总线访问和GPIO控制。测试程序写的还算顺利,一会儿就搞定了。不过,有些IO的控制有点奇怪,总是莫名其妙的被修改。《ARM-WinCE5.0-寄存器读写工具》中曾提到过GPIO被修改的原因和解决办法。不过,在这里似乎都解释不通。因为现在只有测试应用程序能够修改GPIO,不存在被别的程序修改的可能。难道是代码写的有问题?代码已经简单到不能再简单了,如下。
#include
"
stdafx.h
"
#include <windows.h>
#include " s3c6410.h "
typedef struct {
LPVOID pvDestMem;
DWORD dwPhysAddr;
DWORD dwSize;
} VIRTUAL_COPY_EX_DATA,*PVIRTUAL_COPY_EX_DATA;
#define IOCTL_VIRTUAL_COPY_EX CTL_CODE (FILE_DEVICE_UNKNOWN,3333,METHOD_BUFFERED,FILE_ANY_ACCESS)
LPVOID GetVirtual(DWORD dwPhyBaseAddress, DWORD dwSize)
{
LPVOID pVirtual;
VIRTUAL_COPY_EX_DATA vced;
if(dwPhyBaseAddress & 0xFFF)
{
return NULL;
}
vced.dwPhysAddr = dwPhyBaseAddress>> 8;
pVirtual = VirtualAlloc( 0, dwSize, MEM_RESERVE, PAGE_NOACCESS);
vced.pvDestMem = pVirtual;
vced.dwSize = dwSize;
KernelIoControl(IOCTL_VIRTUAL_COPY_EX, &vced, sizeof(vced), NULL, NULL, NULL);
return pVirtual;
}
int _tmain( int argc, _TCHAR* argv[])
{
volatile PS3C6410_GPIO_REG pGPIO1;
pGPIO1 = (PS3C6410_GPIO_REG)GetVirtual(S3C6410_BASE_REG_PA_GPIO, sizeof(S3C6410_GPIO_REG));
pGPIO1->GPBCON = 0x22222222;
printf( " \r\npGPIO1->GPBCON(%08x) ", pGPIO1->GPBCON);
pGPIO1->GPBCON &= (~( 0xFFFF << 16));
printf( " -->(%08x) ", pGPIO1->GPBCON);
return 0;
}
#include <windows.h>
#include " s3c6410.h "
typedef struct {
LPVOID pvDestMem;
DWORD dwPhysAddr;
DWORD dwSize;
} VIRTUAL_COPY_EX_DATA,*PVIRTUAL_COPY_EX_DATA;
#define IOCTL_VIRTUAL_COPY_EX CTL_CODE (FILE_DEVICE_UNKNOWN,3333,METHOD_BUFFERED,FILE_ANY_ACCESS)
LPVOID GetVirtual(DWORD dwPhyBaseAddress, DWORD dwSize)
{
LPVOID pVirtual;
VIRTUAL_COPY_EX_DATA vced;
if(dwPhyBaseAddress & 0xFFF)
{
return NULL;
}
vced.dwPhysAddr = dwPhyBaseAddress>> 8;
pVirtual = VirtualAlloc( 0, dwSize, MEM_RESERVE, PAGE_NOACCESS);
vced.pvDestMem = pVirtual;
vced.dwSize = dwSize;
KernelIoControl(IOCTL_VIRTUAL_COPY_EX, &vced, sizeof(vced), NULL, NULL, NULL);
return pVirtual;
}
int _tmain( int argc, _TCHAR* argv[])
{
volatile PS3C6410_GPIO_REG pGPIO1;
pGPIO1 = (PS3C6410_GPIO_REG)GetVirtual(S3C6410_BASE_REG_PA_GPIO, sizeof(S3C6410_GPIO_REG));
pGPIO1->GPBCON = 0x22222222;
printf( " \r\npGPIO1->GPBCON(%08x) ", pGPIO1->GPBCON);
pGPIO1->GPBCON &= (~( 0xFFFF << 16));
printf( " -->(%08x) ", pGPIO1->GPBCON);
return 0;
}
预想的执行结果应该是pGPIO1->GPBCON(02222222)-->(00002222)而实际结果却是pGPIO1->GPBCON(02222222)-->(00000000),不仅仅是高16位被清零了,所有位都被清零!
跟LD一起调试时,愣是没找到原因。回来的路上,忽然想到可能是编译器优化的问题。不过,马上又把它给否了——已经加了volatile啊。难道volatile不起效?不太可能吧?
到家以后,用IDA工具看了下测试程序的汇编代码,果不其然,跟预想的不一样,代码如下。
.
text:
00011000 wmain
;
CODE XREF: mainCRTStartupHelper+8C