"); //-->
CF卡是一种包含了控制和大容量flash存储器的标准器件,具有容量大、体积小、高性能、较高的抗震性和较好的兼容性等特点。
CF卡内集成了控制器、Flash Memory阵列和读写缓冲区,其设计符合PCMCIA(Personal Computer Memory Card International Association)和ATA(Advanced Technology Attachment)接口规范。CF卡支持3种接口访问模式,分别为符合PCMCIA规范的Memory Mapped模式、I/O Mapped模式和符合ATA规范的True IDE模式。上电时,OE(9脚)为低电平,CF卡进入True IDE;上电时,OE(9脚)为高电平,CF卡进入Memory Mapped模式或I/O Mapped模式;此时通过修改CF卡的配置选项寄存器进入相应的模式。配置选项寄存器格式如表1所示:
SRESET |
LevelREQ |
conf5 |
conf4 |
conf3 |
conf2 |
conf1 |
conf0 |
工作模式 |
软复位信号 |
中断模式选择 |
0 |
0 |
0 |
0 |
0 |
0 |
Memory Mapped模式 |
0 |
0 |
0 |
0 |
0 |
1 |
I/O Mapped对应于16位系统 |
||
0 |
0 |
0 |
0 |
1 |
0 |
I/O Mapped 对应于1F0h-1F7h 3F6h-3F7h |
||
0 |
0 |
0 |
0 |
1 |
1 |
I/O Mapped 对应于170h-177h 370h-377h |
表1 CF卡工作模式选择
TRUEIDE模式接口电路:
下面以内存工作模式为例子介绍cf卡的驱动(最简单):
首先我们知道当把地址线与数据线挂载到MCU后,我们就可以以内存的方式读写CF卡的内部寄存器了,CF卡内部寄存器有:
#define CF_REG_DATA IDE_CS0 /*数据寄存器*/
#define CF_REG_ERR (IDE_CS0 + IDE_A0) /*读错误寄存器*/
#define CF_REG_FEATURE (IDE_CS0 + IDE_A0) /*写功能寄存器*/
#define CF_REG_SECCNT (IDE_CS0 + IDE_A1) /*扇区计数器*/
#define CF_REG_SECTOR (IDE_CS0 + IDE_A1 + IDE_A0)
/*扇区号*/
#define CF_REG_CYLINDER_LOW (IDE_CS0 + IDE_A2) /*柱面低8位*/
#define CF_REG_CYLINDER_HIGH (IDE_CS0 + IDE_A2 + IDE_A0) /*柱面高8位*/
#define CF_REG_DEVICE_HEAD (IDE_CS0 + IDE_A2 + IDE_A1) /*选择主从,模式,磁头*/
#define CF_REG_COMMAND (IDE_CS0 + IDE_A2 + IDE_A1 + IDE_A0)
/*写命令寄存器*/
#define CF_REG_STATUS (IDE_CS0 + IDE_A2 + IDE_A1 + IDE_A0)
/*读状态寄存器*/
#define CF_REG_CONTROL (IDE_CS1 + IDE_A2 + IDE_A1) /*写控制寄存器*/
#define CF_REG_ASTATUS (IDE_CS1 + IDE_A2 + IDE_A1)
/*读辅助状态寄存器*/
显然他们与硬件电路连接的A0,A1,A2,CS0,CS1有关
#define IDE_A0 (1<<1) //地址信号,决定了内部寄存器的偏移
#define IDE_A1 (1<<2) //
#define IDE_A2 (1<<3) //
#define IDE_CS0 ( 0x28000000 ) //片选信号,决定了CF卡的寻址范围
#define IDE_CS1 ( 0x28800000 )
我们可以根据他们如何接入MCU从而确定CF寄存器的地址。
有了寄存器地址,我们就可以读写他们了,以下为两个关键的宏:
#define outportw(data,port) *(volatile U16 *)(port) = (data) //写16位的寄存器
#define inportw(port) *(volatile U16 *)(port) //读16位的寄存器
下面是CF卡驱动的步骤:
1. CF卡的初始化,完成了IO的配置,与硬件连接直接相关
void CF_Init(void)
{
rGPGCON = rGPGCON & (~(0x0f<<14)) ; //GPG7,GPG8 is input
rGPBCON = rGPBCON & (~(0x03<<18)); //GPB9 input
rGPBCON = rGPBCON & (~(0x03<<20)) | (1<<20); //GPB10 output
}
2. 探测CF卡是否加载上电
#define CFCard_Dected ( rGPGDAT&(1<<7) ) //这一位,结CF卡的CF_CD1,
//判断是否上电
void CF_Probe(void)
{
rGPBDAT = ( rGPBDAT&(~(1<<10)) ) | ((0&1)<<10);
if(CFCard_Dected) //Probe CF CARD
CFCard_Flag=FALSE;
else
CFCard_Flag=TRUE;
if(CFCard_Flag)
{
rGPBDAT = ( rGPBDAT&(~(1<<10)) ) | ((1&1)<<10);
Uart_Printf("CF Card Detect OK\n"); //上电了,ok
}
else
Uart_Printf( "CF Card is NOT Pluged!!!\n" ) ;
}
3. 设置CF卡的寻址方式,以及主从
void CF_SetDevice(void)
{
CF_Dev_Config = CF_DevReg_DEV1 + /*选择设备1*/
CF_DevReg_b5 +
CF_DevReg_LBA+ /*工作在LAB模式*/
CF_DevReg_b7;
outportw(CF_Dev_Config,CF_REG_DEVICE_HEAD);
}
4. 然后就可以完成CF卡的读写了
1) 写
int CF_Write_Sector(U16 * Buffer, U32 Sector ,U8 count) //写一个簇
{
U8 Status=FALSE;
U16 i;
if(!CFCard_Flag) /*CF卡不可用,立即返回*/
return FALSE;
CF_WriteSetting( Sector, count); /*写扇区设置*/
do
{ count--;
if(CF_IsBusy()) /*等待设备请求数据传输*/
{
for(i = 0; i < 256; i ++)
/*连续写256个字(512字节)数据,即写入一个扇区*/
{
outportw(*(Buffer++),CF_REG_DATA);
/*向数据寄存器写一个字数据*/
}
Buffer +=256; /*调要写入数据缓冲区的指针*/
}
else
break; /*出错退出*/
}while(count>0);
if(CF_IsBusy()) /*等待设备就绪,读取状态寄存器同时检测设备是否出错*/
Status = TRUE; /*操作正确*/
return Status; /*返回*/
}
其中:调用了read初始化配置函数和总线检测函数如下
void CF_WriteSetting(U32 Sectors , U8 Count) //写CF卡的寄存器设置
{
//outportw函数为写字数据到据存起
outportw(0,CF_REG_FEATURE);
/*写特征寄存器,与驱动接口*/
outportw(Count,CF_REG_SECCNT);
/*写扇区计数寄存器,与驱动接口*/
outportw(Sectors,CF_REG_SECTOR);
/*写扇区寄存器,与驱动接口*/
outportw(Sectors/0x100,CF_REG_CYLINDER_LOW);
/*写柱面低8位寄存器,与驱动接口*/
outportw(Sectors/0x10000,CF_REG_DEVICE_HEAD);
/*写设备磁头寄存器,与驱动接口*/
outportw(((Sectors/0x1000000)&0x0f)|CF_Dev_Config,CF_REG_DEVICE_HEAD); /*写设备磁头寄存器,与驱动接口*/
outportw(0x30,CF_REG_COMMAND);
/*写命令寄存器,与驱动接口,0x30 写扇区命令*/
}
U8 CF_IsBusy(void) //测试总线是不是忙
{
int time="0xffff"; //没有精确的值
U8 status="FALSE";
while(time--)
{
inportw(CF_REG_ASTATUS);
if(!(inportw(CF_REG_STATUS)&0x80)) //判断CF卡是否忙
status=TRUE;
else
status=FALSE;
}
return status;
}
2) 读
void CF_ReadSetting(U32 Sectors , U8 Count) //读的配置
{
outportw(0,CF_REG_FEATURE);
/*写特征寄存器,与驱动接口*/
outportw(Count,CF_REG_SECCNT);
/*写扇区计数寄存器,与驱动接口*/
outportw(Sectors,CF_REG_SECTOR);
/*写扇区寄存器,与驱动接口*/
outportw(Sectors/0x100,CF_REG_CYLINDER_LOW);
/*写柱面低8位寄存器,与驱动接口*/
outportw(Sectors/0x10000,CF_REG_DEVICE_HEAD);
/*写设备磁头寄存器,与驱动接口*/
outportw(((Sectors/0x1000000)&0x0f)|CF_Dev_Config,CF_REG_DEVICE_HEAD); /*写设备磁头寄存器,与驱动接口*/
outportw(0x20,CF_REG_COMMAND);
/*写命令寄存器,与驱动接口,0x20 读扇区命令*/
}
int CF_Read_Sector(U16 * Buffer, U32 Sector ,U8 count) //读一个簇
{
U8 Status=FALSE;
U16 i;
U16 j;
if(!(CFCard_Flag)) /*CF卡不可用,立即返回*/
return FALSE; /*设备无效直接返回*/
CF_ReadSetting( Sector, count); /*读扇区设置*/
do
{
count--; /*扇区数减1*/
if(CF_IsBusy()) /* 等待设备请求数据传输*/
{
for(i = 0; i < 256; i ++)
/*连续读256个字(512字节)数据,及一个扇区大小*/
{
//*Buffer=inportw(CF_REG_DATA);
//Buffer++;
j=inportw(CF_REG_DATA);
*(Buffer++)=j;
//*(Buffer++)=inportw(CF_REG_DATA);
/*从数据寄存器读一个字数据*/
}
Buffer +=256; /*调整数据格式*/
}
else break;
//else return 0; /*出错,退出d0...while*/
}while(count>0); /*所有扇区数据传输完成*/
if(CF_IsBusy())
/*等待设备就绪,读取状态寄存器同时检测设备是否出错*/
Status = TRUE; /*操作正确*/
return Status; /*返回*/
}
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。