·ChinaUnix首页 ·论坛 ·博客 
Linux首页 | Linux新闻 | Linux论坛 | Linux文档 | Linux下载 | Linux博客 | Linux搜索 | 开源项目孵化平台 | 《开源时代》
新手入门 | 安装启动 | 管理员指南 | 开发手册 | 桌面应用 | 程序开发 | 数据库 | 网络技术| CentOS | Fedora | MySQL | Apache | Ubuntu | Gentoo| OSCON08
  Linux时代 >> 技术文档 >> 网络技术
 
ARM的CF卡驱动分析
来源: ChinaUnix博客  日期: 2009.06.12 10:08 (共有条评论) 我要评论
 

ARM的CF卡驱动分析

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
工作模式

软复位信号

中断模式选择






Memory Mapped模式





1
I/O Mapped对应于16位系统






I/O Mapped
对应于1F0h-1F7h 3F6h-3F7h






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        //地址信号,决定了内部寄存器的偏移
#define        IDE_A1            (1        //
#define        IDE_A2            (1        //
#define        IDE_CS0           ( 0x28000000 ) //片选信号,决定了CF卡的寻址范围
#define        IDE_CS1           ( 0x28800000 )

我们可以根据他们如何接入MCU从而确定CF寄存器的地址。

有了寄存器地址,我们就可以读写他们了,以下为两个关键的宏outportw和inportw,实现方法与解释:
MACRO
     MOV_PC_LR
     [ THUMBCODE
       bx lr
     |
       mov pc,lr
     ]
   MEND

EXPORT outportw
     outportw strh r0, [r1]
     MOV_PC_LR

EXPORT inportw
     inportw ldrh r0, [r0]
     MOV_PC_LR

   首先看c与汇编的接口方式。根据nios的二进制接口规则,当编译器把c函数编译到汇编代码时,如果参数不多于4个,那么就由r0 r1 r2 r3来传递参数,函数的返回值将被放到r0中。比如c中调用这样一个函数outportw(dat,addr),那么当编译器将这个函数编译为汇编时,dat的值被赋给r0,addr的值被赋给r1。在于这个c文件在同一个文件夹下的s文件,如果其中有这么一段:
   export outportw
   outportw str r0,[r1]
   MOV_PC_LR
   那么调用在c函数中调用outportw()这个函数的实际作用就是将dat的值发送到addr的地址上去。这样就实现了对底层硬件资源的直接访问。
   如果c中有这样一个函数rt = inportw(addr)并且在与这个c文件同一个文件夹下的s文件中有这样一段代码的话:
   export inportw
   inportw ldr r0,[r0]
   MOV_PC_LR
   那么这个函数的实际作用就是将addr地址上的值读出并作为函数返回值返回。
   上面两段汇编代码中遇到的MOV_PC_LR就是一个MACRO。
   MACRO
   MOV_PC_LR
    [THUMBCODE
       bx lr
    |
        mov pc,lr
    ]
    MEND
   其实这种方式实现c与汇编的接口并不是很方便。这样做需要有比较好的汇编基础。其实可以通过相对简单的c宏定义来实现同样的功能。我之前经常使用这样的宏定义来访问固定的地址。#define rDATA (*((volatile unsigned int *)0x********)),这样data = rDATA; rDATA = data;就可以实现对固定内存地址的读写了。其实刚才的汇编代码也是对具体的内存地址进行读写,只是这个地址是作为参数传递的。只要将c函数中的宏定义改成这个样子就可以实现同样的功能。
#define outportw(dat,addr) (*(volatile U16*)(addr) = (dat))
#define inportw(addr) (*(volatile U16 *)(addr))


下面是CF卡驱动的步骤:
1.       CF卡的初始化,完成了IO的配置,与硬件连接直接相关
void CF_Init(void)
{
       rGPGCON = rGPGCON & (~(0x0f                                 
        //GPG7,GPG8 is input
rGPBCON = rGPBCON & (~(0x03                             
//GPB9 input
       rGPBCON      = rGPBCON &      (~(0x03            
      //GPB10 output
}

2.       探测CF卡是否加载上电
#define     CFCard_Dected ( rGPGDAT&(1
//这一位,结CF卡的CF_CD1,判断是否上电

void CF_Probe(void)
{
      
       rGPBDAT = ( rGPBDAT&(~(1
       if(CFCard_Dected)                      //Probe CF CARD
              CFCard_Flag=FALSE;
       else
              CFCard_Flag=TRUE;
       if(CFCard_Flag)
       {
              rGPBDAT = ( rGPBDAT&(~(1
              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个字(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个字(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;                                            /*返回*/
}


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/49742/showart_1962489.html
  发表评论 查看评论(共有条评论) 我要提问
 
 


最新资讯更多>> 
· 谷歌劝说诺基亚采用Android操作..
· Apache 基金会确认退出 JCP 执..
· Chrome 10 新功能探秘:新增GP..
· 金山宣布开源其安全软件
· 女黑客在开源会议上抱受骚扰
· 21款值得关注的Linux游戏
· 马化腾:腾讯半年后彻底转型,..
· [多图] Chrome OS 预发布版本多..
· Lubuntu 11.04 默认应用抢先一览
· Red Hat宣布收购云计算软件提供..
论坛热点更多>> 
· do_execve时候用户栈中参数的..
· swapinfo -atm 问题
· Linux 的优点简述
· VM虚拟机上得Red Hat Linux上..
· 我看成了上海男人喜欢女人毛..
· 校车展览,看了你就知道
· 在遇到他之前,唯一需要做的..
· GRUB的疑问
· 从来没有人真正付足书价——..
· 云存储 vs 网盘
文档更新更多>> 
· orcale queue
· 谁可以推荐几本经典的操作系统的..
· 【北京】某物联网公司招云计算应..
· 【北京】某物联网公司招云计算应..
· 谁能推荐几本关于操作系统的书
· 如何添加网络接口eth1
· 葡萄牙语入门教材的选取与经验分享
· 葡萄牙语就业前景分析
· 葡萄牙语学习经验交流
· Щ
 
关于我们 | 联系方式 | 广告合作 | 诚聘英才 | 网站地图 | 友情链接 | 免费注册

Copyright © 2001-2009 ChinaUnix.net All Rights Reserved

感谢所有关心和支持过ChinaUnix的朋友们

京ICP证:060528号