Chinaunix首页 | 论坛 | 博客
  • 博客访问: 108854
  • 博文数量: 24
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 270
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-30 18:17
文章分类

全部博文(24)

文章存档

2010年(21)

2009年(3)

我的朋友

分类: WINDOWS

2010-01-25 13:42:15

一,前言:因为友善尚未公布mini2440开发板上的测试程序,所以我自己就写了一个。还好不是太难。

WINCE6.0+mini2440

二,首先来分析一下LEDDriver

2.1, 入口函数:(Sources文件里指明了DLLENTRY=DllEntry

BOOL WINAPI 

DllEntry(HANDLE  hinstDLL,

                     DWORD dwReason,

                     LPVOID /* lpvReserved */)

{

       switch(dwReason)

       {

       case DLL_PROCESS_ATTACH:

              DEBUGREGISTER((HINSTANCE)hinstDLL);

              return TRUE;

       case DLL_THREAD_ATTACH:

              break;

       case DLL_THREAD_DETACH:

              break;

       case DLL_PROCESS_DETACH:

              break;

#ifdef UNDER_CE

       case DLL_PROCESS_EXITING:

              break;

       case DLL_SYSTEM_STARTED:

              break;

#endif

       }

 

       return TRUE;

}

这里要对dwReason作一些说明,一个程序要调用Dll里的函数,首先要先把DLL文件映射到进程的地址空间。要把一个DLL文件映射到进程的地址空间,有两种方法:静态链接和动态链接的LoadLibrary。当一个DLL文件被映射到进程的地址空间时,传递的dwReason参数为DLL_PROCESS_ATTACH。这种调用只会发生在第一次映射时。如果同一个进程后来为已经映射进来的DLL再次调用LoadLibrary,操作系统只会增加DLL的使用次数,它不会再用DLL_PROCESS_ATTACH调用DLLDllMain函数。但如果是不同进程用LoadLibrary同一个DLL时,则每个进程的第一次映射都会调用DllMain函数,并传递DLL_PROCESS_ATTACH。(驱动一般会在这个case下或XXX_Init()里作些初始化的工作)。

相反地,当进程结束或者使用FreeLibrary解除DLL的映射时,系统再次调用DLLDllMain(),此时传递的dwReason就是DLL_PROCESS_DETACH

当进程创建一个线程时,系统调用DLLDllMain(),此时传递的dwReasonDLL_THREAD_ATTACH

当线程结束时,系统调用DLLDllMain(),此时传递的dwReasonDLL_THREAD_DETACH

2.2:

DWORD LED_Init(DWORD dwContext)

{

      RETAILMSG(1,(TEXT("LED_Init----\r\n")));

      // 1. Virtual Alloc

      Virtual_Alloc();

      LEDGpioInit();

      mInitialized = TRUE;

      return TRUE;

}

先看一看

void Virtual_Alloc()

{

    // GPIO Virtual alloc

      s2440IOP = (volatile IOPreg *) VirtualAlloc(0,sizeof(IOPreg),MEM_RESERVE, PAGE_NOACCESS);

      if(s2440IOP == NULL) {

             RETAILMSG(1,(TEXT("For s2440IOP: VirtualAlloc faiLED!\r\n")));

      }

      else {

            if(!VirtualCopy((PVOID)s2440IOP,(PVOID)(IOP_BASE),sizeof(IOPreg),PAGE_READWRITE | PAGE_NOCACHE )) {

                    RETAILMSG(1,(TEXT("For s2440IOP: VirtualCopy faiLED!\r\n")));

             }

      }

}

先是用VirtualAlloc()来预留一块内存,如果成功则用VirtualCopy()映射IOP_BASE到刚申请的一块内存里。

2.3:

BOOL LEDGpioInit()

{

    RETAILMSG(1,(TEXT("LED_Gpio_Setting----\r\n")));

    s2440IOP->rGPBCON  = (s2440IOP->rGPBCON  &~(3 << 10)) | (1<< 10);       // GPB5 == OUTPUT.

    s2440IOP->rGPBCON  = (s2440IOP->rGPBCON  &~(3 << 12)) | (1<< 12);       // GPB6 == OUTPUT.

    s2440IOP->rGPBCON  = (s2440IOP->rGPBCON  &~(3 << 14)) | (1<< 14);       // GPB7 == OUTPUT.

    s2440IOP->rGPBCON  = (s2440IOP->rGPBCON  &~(3 << 16)) | (1<< 16);       // GPB8 == OUTPUT.

    return TRUE;

}

配置跟LED阴级连接的四个IO管脚为输出方向。这里有意思的是,wince对寄存器的访问方式,s2440IOP是一个指向IOPreg结构体的指针,可以看到该结构体的成员排列顺序和datasheet里的寄存器顺序里一样的,并且IOP_BASE的值是0xB1600000(寄存器rGPACON首地址0x56000000映射到内核中的虚拟地址),所以s2440IOP->rGPBCON就是对应寄存器的值了。这跟linux的(首地址+位移)的访问方式有点不一样。

2.4

BOOL LED_IOControl(DWORD hOpenContext,

                 DWORD dwCode,

                 PBYTE pBufIn,

                 DWORD dwLenIn,

                 PBYTE pBufOut,

                 DWORD dwLenOut,

                 PDWORD pdwActualOut)

{

    LEDGpioInit();

    switch(dwCode)

    {

    case IO_CTL_LED_1_ON:

       s2440IOP->rGPBDAT=s2440IOP->rGPBDAT&~(0x1<<5);

       break;

    case IO_CTL_LED_2_ON:

       s2440IOP->rGPBDAT=s2440IOP->rGPBDAT&~(0x1<<6);

       break;

    case IO_CTL_LED_3_ON:

       s2440IOP->rGPBDAT=s2440IOP->rGPBDAT&~(0x1<<7);

       break;

    case IO_CTL_LED_4_ON:

       s2440IOP->rGPBDAT=s2440IOP->rGPBDAT&~(0x1<<8);

       break;

    case IO_CTL_LED_ALL_ON:

       s2440IOP->rGPBDAT=s2440IOP->rGPBDAT&~(0xF<<5);

       break;

    case IO_CTL_LED_1_OFF:

       s2440IOP->rGPBDAT=s2440IOP->rGPBDAT|(0x1<<5);

       break;

    case IO_CTL_LED_2_OFF:

       s2440IOP->rGPBDAT=s2440IOP->rGPBDAT|(0x1<<6);

       break;

    case IO_CTL_LED_3_OFF:

       s2440IOP->rGPBDAT=s2440IOP->rGPBDAT|(0x1<<7);

       break;

    case IO_CTL_LED_4_OFF:

       s2440IOP->rGPBDAT=s2440IOP->rGPBDAT|(0x1<<8);

       break;

    case IO_CTL_LED_ALL_OFF:

       s2440IOP->rGPBDAT=s2440IOP->rGPBDAT|(0xF<<5);

       break;

    default:

       break;    

    }

   

    RETAILMSG(1,(TEXT("LED:Ioctl code = 0x%x\r\n"), dwCode));

    return TRUE;

}

    这个就是控制LED亮与灭的接口了,其实就是把相应管脚置低或置高。

        三,测试程序分别用了win32 API函数和MFC两种方式来实现。见后面的附件。

Win32 API方式:采用了Boling D.的编程风格,这种方式可以自己掌控窗口的创建,窗口过程,对话框的创建,对话框过程。

MFC:相对来说就简单多了,只要动动鼠标,VS就会帮你生成很多代码。

------------------------------------------
本文乃原创!
转载请注明出处:http://sparklecliz.cublog.cn/
------------------------------------------

 

文件: ledtest.rar
大小: 57KB
下载: 下载
文件: LedControl.rar
大小: 160KB
下载: 下载

 

阅读(3244) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~