Chinaunix首页 | 论坛 | 博客
  • 博客访问: 326242
  • 博文数量: 90
  • 博客积分: 4010
  • 博客等级: 上校
  • 技术积分: 694
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-22 10:51
文章分类

全部博文(90)

文章存档

2011年(3)

2010年(35)

2009年(52)

我的朋友

分类: 嵌入式

2010-07-29 10:52:57

1 I2C 通信协议及S3C2410 芯片介绍
   I2C(Inter Integrated Circuit) 总线是1980 年由Philips 公司推出的。 I2C 总线用两条线(SDA 和SCL )在总线和装置之间传递信息,在微控制器和外部设备之间进行串行通信或在主设备和从设备之间进行双向数据传送。两条通信线通过上拉电阻被拉升至+5 V 。在控制系统中的每个集成电路可以通过一个CMOS 缓冲器来读每一条线路,也可以通过一个栅极开路的FET 管将每一条线的电平下拉。因此,对每个芯片来 说,每条线既是输入线,又是输出线。
  I2C 总线遵从同步串行传输协议,即各位串行(一位接一位)发送,由时钟(clock )线指示读数据(data )线的时刻。每个数据包前有一个地址,以指示由哪个器件来接收该数据。
   S3C2410 是一款基于ARM920T 的16/32 位RISC 微处理器,主要用于手持设备,拥有高性价比,低功耗等特点,也是目前市面上出现较多的嵌入式开发板的处理器之一。芯片拥有16 KB 的指令和数据缓存器,有存储管理单元(MMU )、LCD 控制器、3 个串口、4 路DMA 、4 个时钟定时器、8 路10 位的A/D 转换;支持I2C 、 I2S 、SPI 、主从USB 等接口以及SD/MMC 卡。
  S3C2410 微处理器的I2C 总线可以处于下面4 种模式下:主接收模式、主发送模式、从接收模式和从发送模式。处理器对I2C 进行的操作,主要是对下面的几个寄存器进行读/ 写:
  ◇ IIC 控制寄存器,IICCON (物理地址0X54000000 ,内存映射后的虚拟地址);
   ◇ IIC 控制/ 状态寄存器,IICSTAT (物理地址0X54000004 );
   ◇ IIC 数据寄存器,IICDS (物理地址0X54000008 );
   ◇ IIC 地址寄存器,IICADD (物理地址0X5400000C )。
   本设计主要是CPU 工作在主模式下与下面的I2C 接口设备进行通信。
2 Windows CE 系统驱动特点
   Windows CE.net 驱动有两种模型:本机设备驱动程序和流接口驱动程序。本机设备驱动适于集成到基于Windows CE.net 平台的设备。这些设备驱动程序是一些硬件所必需的,是由原始设备制造商创建的,用以驱动如键盘、触摸屏、音频设备等,往往在设备售出后就不会再更换,如通用LED 驱动、电源驱动、键盘驱动和显示驱动等都是本机设备驱动。对于本机设备驱动程序,Platform Builder 提供了一些驱动程序样本,目的是为了方便开发人员快速开发出自己的驱动程序。当Win CE 系统启动时, 本地设备驱动程序将被加载到系统的内存中。本地驱动程序的开发分为分层驱动和单片驱动程序。分层驱动要利用微软提供的与应用程序通信的上层,称为模块驱动程序层MDD (Model Device Driver )。MDD 层通过设备驱动程序接口DDI (Device Driver Interface )与应用程序通信,开发驱动程序通常不修改MDD 层,主要关心与具体硬件相关的下层,依赖平台的设备驱动程序层 PDD (Platform Dependent Driver ), PDD 层通过设备驱动服务接口(Device Driver Service Provider Interface )直接管理硬件。流接口设备驱动程序(指可安装的启动程序)可以由第三方生产商提供,以支持添加到系统中的设备。Windows CE 下的设备驱动程序在与应用程序相同的保护级上工作。当系统启动时,大多数驱动程序是由设备管理进程(DEVICE.EXE )加载的,所有这些驱动程序 将共享同一个进程地址空间。
3 I2C 总线底层驱动设计
  I2C 总线驱动是放在Windows CE 操作系统的内核下层,位于OEM Adaptation Layer (OAL )层的一个真正的驱动。
3.1 初始化I2C 中断和编写ISR 例程
  I2C 的通信是通过操作I2C 的寄存器进行的。在I2C 通信中主要对上面介绍的4 个寄存器进行读写。通过读写这些寄存器中的命令状态字可以检测和控制I2C 总线的行为。在Windows CE.net 下,首先要在文件oalintr.h 添加I2C 的中断号的宏定义:
  #defineSYSINTR_I2C(SYSINTR_FIRMWARE+19)
然后在文件cfw.c 的文件中添加I2C 中断的初始化,禁止和复位。具体代码如下:
在OEMInterruptEnable 函数中加入
   case SYSINTR_IIC:
     s2410INT->rSRCPND=BIT_IIC;
     if (s2410INT->rINTPND & BIT_IIC) s2410INT->rINTPND = BIT_IIC;
     s2410INT->rINTMSK&= ~BIT_IIC;
     break;
   在OEMInterruptDisable 函数中加入
   case SYSINTR_IIC:
     s2410INT->rINTMSK|= BIT_IIC;
       break;
 
在OEMInterruptDone 函数中加入
   case SYSINTR_IIC:
     s2410INT->rSRCPND=BIT_IIC;
     if (s2410INT->rINTPND & BIT_IIC) s2410INT->rINTPND = BIT_IIC;
     s2410INT->rINTMSK&= ~BIT_IIC;
     break;
在armint.c 文件中添加ISR 程序,处理中断发生后返回定义的中断号。具体代码如下:
   在OEMInterruptHandler 函数中添加
   else if (IntPendVal == INTSRC_IIC) {
     s2410INT->rSRCPND= BIT_IIC; /* 清除中断 */
     if (s2410INT->rINTPND & BIT_IIC) s2410INT->rINTPND= BIT_IIC;
     s2410INT->rINTMSK|= BIT_IIC; /* I2C 中断禁止 */
     return (SYSINTR_RTC_ALARM);
   }
3.2 编写流驱动程序
   I2C 总线驱动程序采用的是Win CE 流驱动的标准形式。在IIC_Init 的函数中,首先通过函数VirtualAlloc ()和VirtualCopy (),把芯片中针对I2C 的物理 地址和操作系统的虚存空间联系起来,对虚拟地址空间的操作就相当于对芯片的物理地址进行操作。地址映射的代码如下:
  reg = (PVOID)VirtualAlloc(0, sz, MEM_RESERVE, PAGE_NOACCESS);
     if (reg) {
       if (!VirtualCopy(reg, addr, sz, PAGE_READWRITE | PAGE_NOCACHE )) {
         RETAILMSG( DEBUGMODE,( TEXT( "Initializing interrupt " ) ) );
         VirtualFree(reg, sz, MEM_RELEASE);
         reg = NULL;
       }
     }
  其中sz 是申请的长度,addr 是申请虚拟地址空间的实际物理地址在Win CE 中的映射地址。
   然后对申请到的虚拟地址进行操作,安装Windows 中的流驱动的模型进行驱动的编写,主要包括下面函数的编写。
  IIC_Init ()
   在函数中,主要是对I2C 的初始化,主要语句如下:
   v_pIICregs = ( volatile IICreg *)IIC_RegAlloc((PVOID)IIC_BASE, sizeof(IICreg));
   v_pIOPregs = ( volatile IOPreg *)IOP_RegAlloc((PVOID)IOP_BASE, sizeof(IOPreg));
   v_pIOPregs->rGPEUP|= 0xc000;
   v_pIOPregs->rGPECON |= 0xa00000;
   v_pIICregs->rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);
   v_pIICregs->rIICADD= 0x10;
   v_pIICregs->rIICSTAT = 0x10;
   VirtualFree( ( PVOID )v_pIOPregs,sizeof( IOPreg ),MEM_RELEASE );
   v_pIOPregs = NULL;
   if ( !StartDispatchThread( pIIcHead) )
   { IIC_Deinit( pIIcHead );return ( NULL );} 在StartDispatchThread() 函数中, 主要是创建线程、关联事件和中断, 主要语句如下:
   InterruptInitialize( 36,pIicHead->hIicEvent,NULL,0 );// 关联时间和中断
   CreateThread( NULL,0,IicDispatchThread,pIicHead,0,NULL );// 创建线程等待时间
   在IicDispatchThread() 函数中, 主要是等待中断的产生, 然后去执行:WaitReturn =        WaitForSingleObject( pIicHead->hIicEvent,INFINITE );
   IicEventHandler( pIicHead );// 事件处理函数
   InterruptDone( 36 );
   最后,在函数IIC_Open 、IIC_Read 、IIC_Write 中,对各个寄存器进行操作,进行数据的赋值, 得到I2C 读取的数据和发送数据。
4 I2C 驱动的封装和添加到Windows CE 中
  通过上面的工作,能编译一个DLL 函数,但这还不能叫流接口驱动程序。因为它的接口函数还没有导出,还需要告诉链接程序需要输出什么样的函数,为此要建立一个自己的def 文件,可以用记事本建一个,取名mydrive.Def :
  LIBRARY MyDriver
   EXPORTS
   IIC_Close
   IIC_Deinit
   IIC_Init
   IIC_IOControl
   IIC_Open
   IIC_PowerDown
   IIC_PowerUp
   IIC_Read
   IIC_Seek
   IIC_Write
  然后同样用记事本编写一个注册表文件,取名为mydrive.reg:
  [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\STRINGS]
   "Index"=dword:1
   "Prefix"="IIC"
   "Dll"="MyDriver.dll"
   "Order"=dword:0
   最后编写自己的CEC 文件。主要是添加一个Build Method ,任务是复制注册表到Win CE 的系统目录下面。加一个Bib File ,其主要功能是把编译的mydrive.dll 文件添加到系统内核中去。保存写好的CEC 文件。打开Platform Builder ,打开“File” 菜单,添加刚刚编写的CEC 特征到系统选项中去。生成系统的时候,添加自己的CEC 特性,就可以包含刚刚编写的I2C 驱 动了。
以上介绍了Win CE 的驱动结构,并给出了基于Win CE 的 I2C 驱动程序部分源代码。实验证明该设计是可行的。
   
 
1.1         初始化IIC 中断和编写ISR 例程
IIC 的通信是通过操作IIC 的寄存器进行的。在IIC 通信中主要对上面介绍的4 个寄存器进行读写。通过读写这些寄存器中的命令状态字可以检测和控制IIC 总线的行为。在Windows CE.NET 下,我们首先要在文件oalintr.h 添加IIC 的中断号的宏定义:
#define   SYSINTR_IIC        (SYSINTR_FIRMWARE+19)
然后在文件cfw.c 的文件中添加IIC 中断的初始化,禁止和复位。
在OEMInterruptEnable 函数中,通过向中断寄存器rSRCPND 的第27 位写入1 表示IIC 中断源有中断请求产生。向中断中断寄存器rINTMSK 的第27 位写入0 则将IIC 中断标记为可处理状态。这样就实现了IIC 中断的初始化。在OEMInterruptDisable 函数中,通过向中断寄存器rINTMSK 的第27 位写入1 实现了IIC 中断的禁止。
IIC 驱动程序需要建立一个事件,可以使用CreateEvent 函数实现,然后调InterruptInitialize 将该事件与IIC 中断号绑定,则使能该中断,OAL 中的OEMInerrupteEnable 就会被调用,如果该函数不返回true 的话,InterruptInitialize 就会失败。然后驱动程序中的IST 就可以使用WaitForSingleObject 函数来等待中断的发生。
当一个IIC 中断发生之后,操作系统陷入异常,中断向量指示进入CE 的异常处理程序,该异常处理程序然后调用OAL 的OEMInterruptHandler 函数,该函数检测硬件之后,将硬件中断转换为软件的中断号,返回给系统。该中断号就是上面的InterruptInitialize 中使用的那个中断号。系统得到该中断号之后,就会找到该中断号对应的事件,并唤醒等待相应事件的线程(IST) ,然后IST 就可以在用户态进行中断处理。处理完成之后,IST 需要调用InterruptDone 来告诉操作系统中断处理结束,操作系统再次调用OAL 中的OEMInterruptDone 函数,最后完成中断的处理。
1.2            编写流驱动程序
本IIC 驱动程序采用的是Windows CE 流驱动的标准形式编写,在IIC_Init 的函数中,通过函数VirtualAlloc ()和VirtualCopy (),把芯片中针对IIC 的物理地址和操作系统的虚存地址空间联系起来,对虚拟地址空间的操作就相当于对芯片的物理地址进行操作。
然后对申请到的虚拟地址进行操作,安装Windows 中的流驱动的模型进行驱动的编写,主要包括下面的个几个函数的编写:
1 . IIC_Init( ) :对IIC 进行初始化,在设备管理器加载IIC 驱动后首先调用,用于初始化所需的变量,硬件设备等资源。该过程分配代表设备硬件实例的数据结构,并通过硬件抽象接口HWInit 初始化硬件。同时该函数会调用InterruptInitialize 为接收内核中的逻辑中断创建相应事件并初始化临界区。2 .StartDispatchThread( ) :主要是创建线程, 关联事件和中断, 主要语句如下:
InterruptInitialize( 36,pIicHead->hIicEvent,NULL,0 );// 关联事件和中断
CreateThread( NULL,0,IicDispatchThread,pIicHead,0,NULL );// 创建线程等待时间。
如果StartDispatchThread() 执行后返回false, 则执行 IIC_Deinit() 卸载IIC 驱动。
3 . IicDispatchThread( ) :主要是等待中断的产生, 然后去执行
WaitReturn = WaitForSingleObject( pIicHead->hIicEvent,INFINITE );
IicEventHandler( pIicHead );     // 事件处理函数
InterruptDone( 36 );
最后,在函数IIC_Open ,IIC_Read ,IIC_Write 中,对各个寄存器进行操作,进行数据的赋值。得到IIC 读取的数据和发送速据。
2            IIC 驱动的封装和添加到Windows CE 中
通过上面的工作,我们能编译一个DLL 函数,但是这个还不能叫流接口驱动程序,因为它的接口函数还没有导出,我们还需要告诉链接程序需要输出什么样的函数,为此要建立一个自己的def 文件,可以用记事本程序编辑一个文件名为“mydrive.Def” 的文件。该文件做的工作就是在EXPORTS 段后面列出要从DLL 中输出的函数的名称。在LIBRARY 后面必须加上要编译文件的实际名,然后将这个文件添加到流接口驱动程序的工程里面。
然后同样用记事本编写一个注册表文件,取名为“mydrive.reg” ,并保存到流接口驱动程序的目录里,下面是这个注册表文件的内容。
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\STRINGS]
"Index"=dword:1
"Prefix"="IIC"
"Dll"="MyDriver.dll"
"Order"=dword:0
最后编写自己的CEC 文件。主要任务是添加一个Build Method ,任务是copy 注册表到Window CE 的系统目录下面。接着添加一个Bib File ,其主要功能是把编译的mydrive.dll 文件添加到系统内核中去。然后保存写好的CEC 文件。打开Platform Build ,打开“File” 菜单,添加刚刚编写的CEC 特征到系统选项中去。最后生成系统的时候,添加自己的CEC 特性,就可以包含刚刚编写的IIC 驱动了
 
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cfanlwn/archive/2009/12/04/4939786.aspx
阅读(787) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~