WINCE下IIC接口FLASH驱动
来源:互联网 发布:淘宝分析数据软件知乎 编辑:程序博客网 时间:2024/04/29 16:05
转自:http://blog.sina.com.cn/s/blog_61ebc5f30100fpdy.html
1.4 AT24LC08读写流驱动开发
AT24LC08是一款I2C接口的EEPROM芯片,容量为8Kbit,内部分4个Page,每个Page有256B。访问AT24LC08上的地址空间需要10位地址线。编写AT24LC08芯片的读写驱动需要了解它的读写方式和I2C总线的访问时序,这里以Micro2440平台为例介绍AT24LC08工作过程。该驱动编写的总体流程与1.3类似。
1.4.1 AT24LC08工作原理
AT24LC08的主要管脚定义如表1所示。其中A2是和硬件上的连接一致的;A1、A0是用于选择Page页;SDA用于双向的串行数据传输;SCL是串行时钟线,时钟上升沿时,数据从总线进入EEPROM,时钟下降沿时,数据从EEPROM传到总线;WP信号接地,即采用普通的读写方式。
表1 AT24LC08主要引脚描述
引脚名称
功能
A0 A1 A2
地址输入
SDA
串行数据
SCL
串行时钟输入
WP
写保护
按芯片的工作流程顺序,分别分析器件寻址、写操作、读操作三个过程。
l 器件寻址
AT24LC08寻址的地址部分包括:8bit的器件地址和8bit的字地址。器件地址的各bit位分布如表2所示。前四位是由芯片厂商确定的,为固定值。A2必须和硬件的输入管脚一致。P1、P0为页选地址。R/W是读写控制位,0表示写操作,1表示读操作。
表2 AT24LC08器件地址
1
0
1
0
A2
P1
P0
R/W
8位字地址用于寻址当前页中的某个地址空间,8位对应256个字节。
在芯片读写操作开始时,首先要依次往总线上发送器件地址和字地址,寻址正确才能进行后续的读写操作。
l 写操作
在Micro2440开发板上,我们定义S3C2440为主设备,AT24LC08芯片为从设备。主设备会发送START信号,STOP信号;从设备会回复ACK信号。
如图3所示,当SCL为高电平时,SDA信号被拉低,即出现START信号;当SCL为高电平时,SDA信号由低变高,即为STOP信号。
图3 启动、停止条件
当主设备发送完一个字节的数据,从设备会在下一个时钟周期回复一个ACK,即一个低电平信号,如图4所示。
图4 输出ACK信号
在AT24LC08的写操作过程中(以页写模式为例),其操作流程如图5所示。首先主设备发出START信号,紧接着发送8位器件地址和8位字地址。器件地址最末位为WRITE(0)。从设备验证完地址并发回ACK信号后,主机就开始发送数据。从设备每收到一个字节的数据就返回一个ACK。发送结束后,主机发出STOP信号,至此,一个完整的写操作结束。
需要注意的是:页写模式最多支持16个字节的写操作。按字地址低四位逐次累加,当累加到1111时,下一个时钟周期地址翻转到0000,新写入的数据将覆盖之前的值。
图5 页写数据顺序
l 读操作
以页读模式为例分析读操作的过程:首先主机发出START信号,依次发送器件地址和字地址,此时的读写控制位为WRITE。从机收到地址返回ACK。然后,主机再发送START信号,再传器件地址,此时的读写控制位为READ。主机等到从机返回的ACK,就开始读数据。读到最后一个字节时,从机返回一个NACK信号,主机发出STOP,标志读过程结束。
同样,页读模式也支持最多16个字节的操作。按字地址的低四位累加,如果溢出就翻转到0000地址开始读。
图6 页读数据顺序
1.4.2 驱动程序架构和访问流程
l 体系结构和访问流程
在流式接口驱动程序中,驱动程序负责把外设抽象成一个文件,而应用程序则使用操作系统提供的文件API对外设进行访问。文件API被操作系统转发到FileSys.exe进程中;然后FileSys.exe发现是对设备的操作,就会把执行交给Device.exe处理;接着Device.exe根据具体的请求,调用流驱动接口函数;最终,驱动程序负责与硬件交互。
图7 流接口驱动体系结构
具体过程分析如下:
(1) 应用程序须使用该设备,首先调用CreateFile(TEXT(“IIC1”)…)打开设备。CreateFile函数是在FileSys.exe中实现的。但是FileSys.exe只作简单判断:如果发现打开的是设备驱动而不是一个文件,那么就重新把主动权交还给设备管理器。
(2) 设备管理器调用驱动程序中的IIC_Open()函数打开设备。在IIC_Open中,驱动程序可以对硬件进行一些额外的初始化工作,使硬件进入工作状态。
(3) IIC_Open()函数把打开设备的结果返回给设备管理器。
(4) 设备管理器把IIC_Open()返回的结果再传给应用程序中的CreateFile()函数调用。
(5) 设备已被成功打开,接下来可对设备进行读写和控制操作。以控制操作为例,CreateFile函数返回的句柄作为DeviceIoControl()的第1个参数,向设备发送控制请求。同样,DeviceIoControl()要FileSys.exe转发给设备管理器。
(6) 设备管理器调用驱动程序中的IIC_IOControl()函数,与硬件完成交互,读写设备的数据信息,然后返回给设备管理器,再返回给应用程序。
(7) 当应用程序不再使用该设备时,它可调用CloseHandle()将设备关闭。此时调用的是驱动程序中的IIC_Close()函数。
l 驱动目录组织
在AT24LC08读写驱动中,根据访问和交互的对象不同,将驱动程序目录组织如下:
Ø IICBus.c 用于和用户态程序的交互,提供流驱动接口函数;
Ø IIC2440.c 和S3C2440的硬件交互,完成寄存器的配置;
Ø 24LC08.c 对AT24LC08芯片操作,按照芯片的读写模式配置。
1.4.3 流驱动接口函数的实现
在本驱动中,定义前缀为“IIC”,IICBus.c文件中的流接口驱动函数都以该前缀命名,本驱动中流接口重点实现以下3个函数:
BOOL IIC_Init(DWORD dwcontext)
BOOL IIC_Deinit(DWORD hDeviceContext)
BOOL IIC_IOControl(DWORD hOpenContext, DWORDdwCode,
EEPROM_INFO *pBufIn, DWORD dwLenIn,
U8 *pBufOut, DWORD dwLenOut, PDWORD pdwActualOut)
IIC_Init()函数
该函数在设备加载时被调用,具体代码实现:
BOOL IIC_Init(DWORD dwcontext)
{
RETAILMSG(DBG_OUT,(TEXT("IIC_Init---/r/n")));
Virtual_Alloc();
Setup_IIC();
return TRUE;
}
Setup_IIC()函数完成一些端口的初始化,以及IIC总线寄存器的初始化配置。
Setup_IIC()
{
RETAILMSG(DBG_OUT,(TEXT("IIC_INTR_Gpio_setting ---/r/n")));
s2440IOP->rGPEUP |= 0xc000; //Pull-up disable
s2440IOP->rGPECON=(s2440IOP->rGPECON&~(3<<30))|(2<< 30); //GPE15=IICSDA.
s2440IOP->rGPECON=(s2440IOP->rGPECON&~(3<< 28))|(2<< 28); //GPE14=IICSCL.
s2440IIC->rIICCON =(1<<7) |(0<<6) |(1<<5) | (0xf); //Tx clock = 0.195MHz
//[Bit7] = Enable ACK, [Bit6] = Prescaler IICCLK=PCLK/16, [Bit5] =Enable interrupt;
//[Bit3:0] = Transmit clock value Tx clock=IICCLK/16
s2440IIC->rIICSTAT =0x10; //IICbus data output enable(Rx/Tx)
s2440IIC->rIICADD = 0x10; //2440slave address = [7:1]
s2440IIC->rIICLC =(1<<2)|(3); //Filter enable, 15 clocks SDA output delay
return TRUE;
}
IIC_Deinit()函数
该函数在设备卸载时被调用,释放加载时申请的虚拟地址空间,具体代码实现:
BOOL IIC_Deinit(DWORD hDeviceContext)
{
RETAILMSG(DBG_OUT, (TEXT("IIC_INTR_Deinit --- /r/n")));
VirtualFree((void*)s2440IOP, sizeof(IOPreg),MEM_RELEASE);
VirtualFree((void*)s2440IIC, sizeof(PWMreg),MEM_RELEASE);
return TRUE;
}
IIC_IOControl()函数
该函数用于处理应用程序发送过来的控制命令,控制指令dwCode有IOCTL_IIC_READ和IOCTL_IIC_WRITE两种。当收到读指令IOCTL_IIC_READ时,保存读操作的起始地址和读取字节数,然后调用E2P_Read()函数读取AT24LC08上的数据,将实际读取的字节数保存到*pdwActualOut。同样,当收到写指令IOCTL_IIC_WRITE时,保存写操作的起始地址和写字节数,然后调用E2P_PageWrite()函数往AT24LC08上写数据,将实际写入的字节数保存到*pdwActualOut。
BOOLIIC_IOControl(DWORD hOpenContext, DWORD dwCode,
EEPROM_INFO *pBufIn, DWORDdwLenIn,
U8 *pBufOut, DWORD dwLenOut,PDWORD pdwActualOut)
{
RETAILMSG(DBG_OUT,(TEXT("IIC: +IIC_IOControl (%d) /r/n"),dwCode));
switch(dwCode){
case IOCTL_IIC_READ:
{
U16 ReadAddress = pBufIn->start_address;
U8 ReadNum = (U8)dwLenOut; //ReadNum为要读取的字节数
*pdwActualOut = E2P_Read(ReadAddress, ReadNum, pBufOut);
return TRUE;
}
case IOCTL_IIC_WRITE:
{
U16 WriteAddress =pBufIn->start_address;
U8 WriteNum = (U8)dwLenIn;
*pdwActualOut = E2P_Write(WriteAddress, WriteNum,pBufIn->dwData);
return TRUE;
}
}
return TRUE;
}
E2P_Read()函数和E2P_Write()函数都是对AT24LC08操作的,在24LC08.c中实现,具体代码如下:
U8 E2P_Read(U16 Address, U8 Num, U8*DataRead)
{
U8 DevAddr_W, DevAddr_R;
U8 PageAddr, WordAddr;
U8 ActualNum;
int i;
if(Address > END_ADDRESS)
{
RETAILMSG(1,(TEXT("IIC: START ADDRESS ERROR!!!")));
return 0;
}
if((Address + Num) > END_ADDRESS) //超出存储器容量
{
ActualNum =(U8)(END_ADDRESS - Address + 1);
}
else
ActualNum = Num;
memset(&E2pInfo, 0, sizeof(IIC_INFO));
WordAddr = (U8)(Address & 0x00ff); //获取字地址
PageAddr = (Address >> 8)& 0x03; //获取A1, A0页地址
DevAddr_W = 0xa0 | (PageAddr <<1); //DevAddr = 0x 1 0 1 0 A2 A1 A0 R/W
E2pInfo.iicMode = SETRDADDR;
E2pInfo.iicPt = 0;
E2pInfo.iicData[0] =WordAddr;
E2pInfo.iicDataCount = 1;
E2pInfo.DeviceAddress = DevAddr_W;
IIC_TX(&E2pInfo);
memset(&E2pInfo, 0, sizeof(IIC_INFO));
DevAddr_R = 0xa1 | (PageAddr <<1);
E2pInfo.iicMode = RDDATA;
E2pInfo.iicPt = 0;
E2pInfo.iicDataCount = ActualNum; //读取的字节数
E2pInfo.DeviceAddress = DevAddr_R;
IIC_RX(&E2pInfo);
for(i = 0; i < ActualNum; i++)
*DataRead++ = *data++;
return ActualNum;
}
E2P_Read()函数功能如下:
(1) 判断读入的地址参数是否有效,若无效,则退出;
(2) 判断所读的数据长度是否会超出存储器的地址空间,截取实际能读取的数据长度保存;
(3) 将输入的16位地址转换成所需的8位器件地址和8位字地址;
(4) 把读写模式指令、器件地址、字地址、可读取的实际字节数保存到结构体E2pInfo中,传递给IIC_TX()函数和IIC_RX()函数实现IIC总线上的数据收发。
(5) 返回读取的实际字节数;
U8 E2P_Write(U16 Address, U8 Num, U8*DataToWrite)
{
U8 *DataTmp, ActualNum;
U16 Address_End;
U8 FirstSector, SectorNum, EndSector;
int i;
if(Address > END_ADDRESS)
{
RETAILMSG(1,(TEXT("IIC: START ADDRESS ERROR!!!")));
return 0;
}
if((Address + Num) > END_ADDRESS) //超出存储器容量
{
ActualNum = (U8)(END_ADDRESS - Address + 1);//获取实际能写入的字符数
}
else
ActualNum = Num;
FirstSector = MAX_BUF - (U8)(Address & 0x000f) ;//计算第一页能存的字节数
if(ActualNum > FirstSector) //判断是否能在第一页存完数据
{
SectorNum = (ActualNum - FirstSector) / MAX_BUF;
DataTmp = DataToWrite + FirstSector;
E2P_PageWrite(Address, FirstSector, DataToWrite); //写第一页数据
for(i = 0; i < SectorNum; i++) //按每页16B 写数据
E2P_PageWrite(Address + FirstSector + i* MAX_BUF,MAX_BUF, DataTmp + i*MAX_BUF);
Address_End = Address + FirstSector + SectorNum*MAX_BUF;//获取末页地址
EndSector = (ActualNum - FirstSector) %MAX_BUF;//获取末页待写字节数
E2P_PageWrite(Address_End, EndSector, DataTmp +SectorNum*MAX_BUF);
}
else
E2P_PageWrite(Address, ActualNum, DataToWrite); //写第一页数据
return ActualNum;
}
E2P_Write()函数功能如下:
(1) 判断写操作起始地址参数是否有效,若无效,则退出;
(2) 判断写数据长度是否会超出存储器的地址空间,截取实际能写的数据长度保存;
(3) 计算起始地址所在页能写的字节数;
(4) 判断实际要写的数据数是否超出第一页,如没有,则直接调用E2P_PageWrite()函数完成页写操作;
(5) 若超出,则判断需分几页写,分别调用E2P_PageWrite()函数按页写数据;
(6) 返回实际写入的数据字节数。
void E2P_PageWrite(U16 Address, U8 Num, U8*SectorData)
{
U8 DevAddr_W;
U8 PageAddr, WordAddr;
int i;
memset(&E2pInfo, 0, sizeof(IIC_INFO));
WordAddr = (U8)(Address & 0x00ff); //获取字地址
PageAddr = (Address >> 8) & 0x03; //获取A1, A0页地址
DevAddr_W = 0xa0 | (PageAddr <<1); //DevAddr = 0x 1 0 1 0 A2 A1 A0 R/W
E2pInfo.iicMode = WRDATA;
E2pInfo.iicPt = 0;
E2pInfo.iicData[0] =WordAddr;
E2pInfo.DeviceAddress = DevAddr_W;
for(i =0; i < Num; i++)
{
E2pInfo.iicData[i+1] =*(SectorData + i);
}
E2pInfo.iicDataCount = 1+Num;
IIC_TX(&E2pInfo);
}
E2P_PageWrite()函数主要完成地址转换和传递结构体E2pInfo的过程,然后调用IIC_TX()函数实现IIC总线上的数据发送。
IIC_TX()函数和IIC_RX()函数在IIC2440.c中实现,代码如下:
void IIC_TX(IIC_INFO *piicinfo)
{
g_iicinfo = piicinfo;
s2440IIC->rIICDS =g_iicinfo->DeviceAddress;
s2440IIC->rIICSTAT = 0xf0; //MasTx,Start
s2440IIC->rIICCON = 0xAf;
//Clearing the pending bit isn't needed because the pending bit hasbeen cleared.
while(g_iicinfo->iicDataCount!=-1)
Run_IICPoll();
return;
}
void IIC_RX(IIC_INFO *piicinfo)
{
g_iicinfo = piicinfo;
s2440IIC->rIICDS =g_iicinfo->DeviceAddress;
s2440IIC->rIICSTAT = 0xb0; //MasRx,Start
s2440IIC->rIICCON = 0xaf; //Resumes IIC operation.
while(g_iicinfo->iicDataCount!=-1)
Run_IICPoll();
data = g_iicinfo->iicData + 1 ;
return;
}
这两个函数都是完成和S3C2440的IIC寄存器相关的操作,按照IIC协议的时序依次往寄存器中器件地址和相关值,然后调用Run_IICPoll()函数逐个字节传递数据。
void Run_IICPoll(void)
{
// When using polling mode
if(s2440IIC->rIICCON &0x10) //Tx/Rx Interrupt Enable
IICPoll();
}
void IICPoll(void)
{
switch(g_iicinfo->iicMode)
{
case RDDATA:
if((g_iicinfo->iicDataCount--)==0)
{
g_iicinfo->iicData[g_iicinfo->iicPt++]= s2440IIC->rIICDS;
s2440IIC->rIICSTAT = 0x90; //Stop MasRx condition
s2440IIC->rIICCON = 0xAf; //Resumes IIC operation.
Delay(10); //Wait until stop condtion is in effect., Too longtime...
//The pending bit will notbe set after issuing stop condition.
break;
}
g_iicinfo->iicData[g_iicinfo->iicPt++]= s2440IIC->rIICDS;
//The last data has to be read with noack.
if((g_iicinfo->iicDataCount)==0)
s2440IIC->rIICCON = 0x2f; //Resumes IIC operation with NOACK
else
s2440IIC->rIICCON = 0xAf; //Resumes IIC operation withACK
break;
case WRDATA:
if((g_iicinfo->iicDataCount--)==0)
{
s2440IIC->rIICSTAT = 0xd0; //stop MasTx condition
s2440IIC->rIICCON = 0xAf; //resumesIIC operation.
Delay(10); // we should adjust this time.
//Thepending bit will not be set after issuing stopcondition.
break;
}
s2440IIC->rIICDS=g_iicinfo->iicData[g_iicinfo->iicPt++];
Delay(1); //forsetup time until rising edge of IICSCL
s2440IIC->rIICCON = 0xAf; //resumes IICoperation.
break;
case SETRDADDR:
if((g_iicinfo->iicDataCount--)==0)
{
break; //IIC operation is stoppedbecause of IICCON[4]
}
s2440IIC->rIICDS =g_iicinfo->iicData[g_iicinfo->iicPt++];
Delay(1); //for setup time until rising edge ofIICSCL
s2440IIC->rIICCON = 0xAf; //resumesIIC operation.
break;
default:
break;
}
}
当S3C2440的rIICCON寄存器中断位使能,Run_IICPoll()函数调用IICPoll()函数。IICPoll()函数实现三种模式的数据传输:
(1)SETRDADDR
当执行读操作时,主机往从机写入第一个地址时使用该模式,只写两个字节数据(器件地址和字地址),然后退出。
(2)RDDATA
当执行读操作,主机发完起始地址后,进入RDDATA模式,地址依次累加读取AT24LC08上的数据,最完最后一个字节时,回复NACK,主机收到后发STOP信号退出。
(2)WRDATA
当执行写操作时进入WRDATA模式,主机往从机发送器件地址和字地址,然后地址依次累加往AT24LC08写入数据,最后主机发STOP信号退出。
1.4.4 添加makefile文件和Source文件
(一)makefile文件
!INCLUDE $(_MAKEENVROOT)/makefile.def
(二)Source文件
RELEASETYPE=PLATFORM
TARGETNAME=IICBus
TARGETTYPE=DYNLINK
DLLENTRY=DllEntry
TARGETLIBS= /
$(_COMMONSDKROOT)/lib/$(_CPUINDPATH)/coredll.lib /
MSC_WARNING_LEVEL=$(MSC_WARNING_LEVEL) /W3/WX
INCLUDES= /
$(_TARGETPLATROOT)/inc; /
$(_COMMONOAKROOT)/inc; /
$(_PUBLICROOT)/common/oak/inc;$(_PUBLICROOT)/common/sdk/inc;$(_PUBLICROOT)/common/ddk/inc;/
../../inc/
SOURCES= /
24LC08.c/
IIC2440.c/
IICBus.c/
FILE_VIEW_INCLUDES_FOLDER= /
IIC.h/
IIC2440.h/
24LC08.h/
1.4.5编写DLL的导出函数定义文件
.DEF文件定义了DLL的导出函数列表。在IIC中添加一个文本文件,命名为IICBus.def,然后在该文件中输入如下内容:
LIBRARY IICBus
EXPORTS
IIC_Init
IIC_Deinit
IIC_Open
IIC_Close
IIC_IOControl
IIC_PowerUp
IIC_PowerDown
IIC_Read
IIC_Write
IIC_Seek
1.4.6配置注册表
在platform.reg中添加如下内容:
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/IICBus]
"Dll" = "IICBus.dll"
"Prefix" = "IIC"
"Index" = dword:1
"Order" = dword:0
另外,还要在platform.bib中添加如下内容:
IICBus.dll $(_FLATRELEASEDIR)/IICBus.dll NK SH
- WINCE下IIC接口FLASH驱动
- wince +6410 IIC 驱动问题
- WinCE下访问Nand Flash接口
- DS1621在Linux下的IIC接口驱动设计
- 调试 S3C6410 IIC 的wince驱动总结
- Wince 流接口驱动
- linux下的IIC驱动
- LINUX下的IIC驱动
- wince下添加自己的流接口驱动
- S3C2440的camera接口特性及WinCE 下的驱动
- S3C2440的camera接口特性及WinCE 下的驱动
- S3C2440的camera接口特性及WinCE 下的驱动
- S3C2440的camera接口特性及WinCE 下的驱动
- S3C2440的camera接口特性及WinCE 下的驱动
- S3C2440的camera接口特性及WinCE 下的驱动
- S3C2440的camera接口特性及WinCE 下的驱动
- WINCE下USB接口摄像头驱动的加载
- Linux-IIC驱动(2)-Linux下IIC子系统的介绍
- word宏
- java代码写excel和文本文档的导入导出
- C++ Lua
- DM642 SDRAM的堆栈分析
- 读《走出软件作坊》第一篇
- WINCE下IIC接口FLASH驱动
- 有一对姐妹,姐姐在12点之前都是讲真话,12点之后都是讲假话,妹妹在12点之前都是讲假话,12点之后都是讲真话,一个人去问:你们谁是姐姐。都回答说:我是。又问现在几点。胖的说:快12点了。瘦的说:12点过了。谁是姐姐,现在几点了:
- LINUX平台部署apache+mod_python+django
- Silverlight游戏设计(Game Design):(十二)帝国时代II(Demo) 之 “战争艺术”①
- ubuntu gtk安装
- 修改 ModPython 下 PYTHON_EGG_CACHE 报错
- 在Qt中保持GUI响应[上]
- Ubuntu下三大CHM阅读软件
- 计算机类图书之旅