ARM的CF卡驱动分析

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情

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<<1)        //地址信号,决定了内部寄存器的偏移


#define        IDE_A1            (1<<2)        //


#define        IDE_A2            (1<<3)        //


#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<<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;                                            /*返回*/


}

Cutter图形化逆向分析:从反汇编到漏洞挖掘的实战指南 逆向工程是分析软件内部工作原理、进行安全审计和漏洞挖掘的核心技术。其基本原理是通过反汇编将机器码转换为可读的汇编指令,进而理解程序逻辑与控制流。这项技术的价值在于能够深入分析闭源软件、恶意代码或进行软件安全评估。在应用场景上,它广泛用于软件调试、漏洞研究、恶意软件分析和协议逆向等领域。Cutter作为基于radare2的图形化逆向分析工具,通过可视化控制流图和智能导航功能,极大地提升了分析效率。它集成了强大的反汇编引擎,支持对二进制文件进行深度静态分析,并能通过图形视图直观展示函数结构,帮助分析师快速定位关 阅读详情

相关推荐

老旧设备安装Windows 11与安卓子系统的实战指南

虚拟化技术通过创建隔离的软件环境,使老旧硬件也能运行现代操作系统。其核心原理是利用CPU的VT-x/AMD-V指令集,在物理硬件上构建虚拟层。这项技术显著提升了设备兼容性,特别适用于企业IT资产利旧和开发者测试环境。在Windows生态中,微软推出的安卓子系统(WSA)基于Hyper-V虚拟化架构,实现了原生级安卓应用兼容。通过修改注册表、定制安装镜像等技术手段,可以绕过TPM 2.0等硬件限制,在2015年前后的设备上流畅运行Windows 11。重点需要关注内存管理(建议8GB以上)和存储优化(推荐SS

weixin_34075268的博客 344

i.MX处理器连接ATA硬盘:硬件设计、时序分析驱动调试实战

在嵌入式系统开发中,外部存储扩展是核心需求之一,ATA硬盘及其衍生技术因其高容量和成熟性,曾是嵌入式设计的常见选择。其工作原理基于并行接口协议,通过PIO和DMA两种主要模式进行数据传输,技术价值在于为系统提供了可靠的大容量存储解决方案,广泛应用于工业控制、数据采集和多媒体终端等场景。本文将深入探讨如何将ATA硬盘连接到i.MX系列应用处理器,涵盖硬件接口匹配、时序约束分析以及驱动软件适配等关键环节,并重点解析PIO模式与Multiword DMA模式的实现差异与硬件要求,为工程师在类似项目中提供从方案选型

weixin_30580341的博客 322

深入解析s3c6410 CF与SD存储接口源代码

本文还有配套的精品资源,点击获取 简介:s3c6410微处理器是基于ARM11内核,广泛用于嵌入式系统。文章深入分析了s3c6410 CF与SD存储接口的源代码实现,包括初始化过程、命令交互、数据传输、中断处理和错误处理。通过理解这些源代码和协议,开发者可以优化存储性能、调试故障,并定制化开发嵌入式系统。本文同时提供了在Android平台上,s3c6410 CF与SD卡驱动...

weixin_30765637的博客 1134

ARM-驱动/总结一

内核模块 / 字符设备驱动

weixin_57039874的博客 1459

S3C6410 IDE硬盘接口性能测试

因项目需要,要验证在S3C6410系统下面挂硬盘存储大量数据的方案,目前市场上的6410开发板由于成本和定位的原因,99.99%都没把6410的ATA接口留出。放狗搜了半天,找来找去也就只有立宇泰一家的6410支持ATA接口,打开一看,只有wince下面的测试报告,PIO模式,支持单硬盘,但读写速度只有区区的2.88MB/S,连个NAND Flash的速度都比不上,更不用说SD的速度了,好好的一

sdecat的专栏 1542

CF的基础知识

CF的基础知识   CF的物理和硬件接口特性 CF可以工作在PCATA I/O模式、PCATA存储模式和实IDE模式三种模式下,实IDE模式与IDE接口完全歉。CF遵从ATA协议,属于块存储设备,存储单元是通过磁头(head)、柱面(cylinder,也称磁道)和扇区(sector)组织起来的;在物理寻址(CHS)方式下,每一组H/C/S参数唯一确定存储中的一个扇区,通常一个扇

liushi558 5490

2.10 Linux 串口、CF、MTD、I2C驱动分析

本文以风河linux代码为例,解析Linux 串口、CF、flash MTD、I2C驱动的具体实现。1、串口驱动1.1、原理简介Mspb单板的xlr732cpu提供了两个串口,我们使用了其中一个串口作为控制台。串口虽然简单,但是作用是非常重要的。在内核调试的初期一切都未正常,只能向串口直接输出调试信息来调试;在系统的启动阶段也只能向串口打印启动信息。在Linux系统中,串口驱动的架构如下: 1.2

pwl999的博客 1923

ARM7系统中实现CF存储的文件系统设计

关键词:嵌入式文件系统 CF ARM7随着微控制器性能的不断提高,嵌入式应用越来越广泛。但是目前市场上的大型商用嵌入式实时系统,价格昂贵,而且都针对特定的硬件平台。对于中小型系统开发,购买商用实时系统并不划算。目前我们正着手将嵌入式系统软件应用于汽车卫星导航仪系统的一步开发。传统的嵌入式应用并不包括文件系统,而我们要实现的文件系统需要在车辆导航系统中实现地图数据文件的读写。因此它既要支持

千金甜果的专栏 1817

linux cf 驱动下载,嵌入式Linux系统中CF卡驱动程序的设计

摘要:随着各种新技术的出现,人们对计算机的认识越来越深刻.计算正逐步走进设备里面,计算机系统也从各种有形的外观变为无形.大到航天航空领域,小到手中的PDA,都移植入了计算机系统,人们把这样的一个系统叫做嵌入式系统.嵌入式Linux系统不仅继承了传统Linux的许多优点,如易于开发,高效,功能强大,稳定,易于扩充,免版费,开放源码等,而且对原有系统做了大量的嵌入化改造,使其能够更好的适应嵌入式应用的...

weixin_39552286的博客 251

5个步骤快速部署Windows安卓子系统:WSABuilds完整实战指南

WSABuilds是一个开源的Windows安卓子系统自动化构建项目,为Windows 10和Windows 11用户提供了一站式的Android环境部署解决方案。这个项目通过预构建的二进制文件,集成了Google Play商店服务和多种Root解决方案,让用户能够在Windows系统上轻松运行Android应用程序。无论你是开发者需要测试应用兼容性,还是普通用户想在PC上体验Android生态,

gitblog_00981的博客 296

WSABuilds完整指南:在Windows 10/11上运行Android应用的终极解决方案

WSABuilds项目为Windows用户提供了一个强大的解决方案,让你能够在Windows 10和Windows 11系统上完美运行Android应用程序。这个开源项目集成了Google Play商店、Magisk和KernelSU等关键组件,为Windows上的Android体验带来了革命性的改进。无论你是开发者需要测试Android应用,还是普通用户想在PC上享受移动应用,WSABuilds

gitblog_00853的博客 1008

从零到精通:Windows安卓子系统WSABuilds完整实战指南

想在Windows上无缝运行Android应用却苦于复杂配置?WSABuilds项目为你提供了一站式解决方案,通过预编译的二进制文件集成了Google Play商店、Magisk和KernelSU等核心组件,让Windows安卓子系统安装变得前所未有的简单。这个开源项目专为Windows 10和Windows 11用户设计,无需繁琐的手动配置即可享受完整的Android生态体验。 ## 为什么W

gitblog_00007的博客 1101

高效实现Windows与Android无缝集成:全新跨系统应用运行指南

在数字化办公与娱乐需求日益融合的今天,Windows Android集成已成为提升多设备协作效率的关键。本文将系统讲解如何通过WSABuilds方案实现跨系统应用运行,让你的Windows设备兼具桌面系统的强大与移动应用的灵活。 ## 需求分析:你是否需要Windows Android集成? 现代用户在设备使用中常面临"应用割裂"困境:专业软件依赖Windows环境,而移动应用生态又难以替代。

gitblog_00386的博客 425

WSA-Script完整指南:在Windows 11上打造终极Android开发环境

WSA-Script是一个强大的开源工具集,专门用于在Windows 11上构建功能完整的Android子系统环境。通过集成Magisk root权限和Google Play服务,它解决了官方WSA(Windows Subsystem for Android)的诸多限制,为开发者、测试人员和普通用户提供了原生的Android体验。本文将详细介绍如何从零开始配置这个强大的工具,并探索其核心功能和技术

gitblog_00895的博客 208

Windows Mobile下SQLite的Native C++轻量封装实践

SQLite是一种嵌入式关系型数据库引擎,其核心设计强调零配置、自包含与事务可靠性;在资源受限的嵌入式系统中,需绕过高级抽象、禁用异常与RTTI,并基于原生C API构建确定性访问层。Native C++封装能规避托管运行时开销,满足硬实时、低内存占用及跨语言调用需求,广泛应用于工业PDA、医疗终端、电力巡检等离线场景。本文聚焦Windows Mobile 6.5(ARMV4I/CE 5.2)平台,详解如何通过纯C导出接口、手动临界区同步、WAL日志适配与路径归一化等关键技术,实现稳定、可预测、可部署的SQ

diaoqi6581的博客 566

小米平板刷Windows系统全攻略:从原理到实践

x86与ARM架构差异是移动设备刷入Windows系统的技术分水岭。通过EFI引导和驱动注入,可实现Android设备运行Windows系统,这对预算有限但需要Windows生产力的用户极具价值。本文以小米平板为例,详解硬件适配原理、分区方案设计及驱动兼容性处理,特别针对Intel芯片版本提供完整刷机方案。涉及UEFI引导、注册表优化等核心技术,并给出触控失灵、WiFi连接等典型问题的工程解决方案,最后通过实测数据验证轻办公场景下的可用性。

weixin_34221276的博客 447

Windows安卓子系统完整安装指南:WSABuilds让你的Windows运行Android应用

**WSABuilds**是一个开源项目,它让你能在Windows 10和Windows 11电脑上轻松运行Android应用。这个项目通过预构建的二进制文件,集成了Google Play商店、Magisk和KernelSU等核心组件,为Windows用户提供了最完整的安卓子系统解决方案。 ## 🎯 为什么选择WSABuilds? 传统的Windows安卓子系统安装过程复杂且需要大量手动配置

gitblog_00865的博客 502

WSABuilds 终极解决方案:5大核心问题诊断与修复完整指南

### 1.1 WSABuilds 系统架构概览 WSABuilds 项目通过创新的技术方案,在 Windows 系统上构建完整的 Android 子系统环境。整个架构包含三个核心层次: **应用层**:通过 WSA 运行 Android 应用程序,支持 Google Play 商店、Magisk 或 KernelSU 等模块集成。 **适配层**:包含 libhoudini ARM 转译引

gitblog_00113的博客 1051
上一篇: ata驱动框架
下一篇: 在ubuntu下安装xinetd模式的tftpd服务
evenness
博客等级 码龄15年 98粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值