admin管理员组

文章数量:1531695

2024年1月6日发(作者:)

SD卡工作原理介绍和工作原理图

大容量SD卡在海洋数据存储中的应用

本设计使用8 GB的SDHC(High Capacity SD Memory Card,大容量SD存储卡),为了方便卡上数据在操作系统上的读取,以及数据的进一步分析和处理,在SDHC卡上建立了FAT32文件系统。 海洋要素测量系统要求数据存储量大、安全性高,采用可插拔式存储卡是一种不错的选择。目前,可插拔式存储卡有CF卡、U盘及SD卡。CF卡不能与计算机直接通信;U盘需要外扩接口芯片才能与单片机通信,增加了外形尺寸及功耗;而SD卡具有耐用、可靠、安全、容量大、体积小、便于携带和兼容性好等优点,非常适合于测量系统长期的数据存储。 1 SD卡接口的硬件设计

STM32F103xx增强型系列是意法半导体公司生产的基于Cortex-M3的高性能的32位RISC内核,工作频率为72 MHz,

O端口和连接到2条APB总线的外设。内置高速存储器(128 KB的闪存和20 KB的SRAM),以及丰富的增强I,

STM32F103xx系列工作于-40,+105?的温度范围,供电电压为2.0,3.6 V,与SD卡工作电压兼容,一系列的省电模式可满足低功耗应用的要求。

SD卡支持SD模式和SPI模式两种通信方式。采用SPI模式时,占用较少的I,O资源。STM32F103VB包含串行外设SPI接口,可方便地与SD卡进行连接。通过4条信号线即可完成数据的传输,分别是时钟SCLK、主机输入从机输出MISO、主机输出从机输入MOSI和片选CS。STM32F103VB与SD卡卡座的接口电路如图1所示。

SD卡的最高数据读写速度为10 MB,s,接口电压为2.7,3.6 V,具有9个引脚。SD卡使用卡座代替传输电缆,减少了环境干扰,降低了出错率,而且1对1传输没有共享信道的问题。SD卡在SPI模式下各引脚的定义如表1所列。 2 SD卡接口的软件设计

本设计采用STM32F103VB自带的串行外设SPI接口与SD卡进行通信,这里只介绍SPI模式的通信方式。 2.1SD卡的读写

先对STM32F103VB的SPI_CRl(SPI控制寄存器)以及SPI_SR(SPI状态寄存器)进行初始化设置,使能SPI并使用主机模式;同时设置好时钟,在时钟上升沿锁存数据。SPI通道传输的基本单位是字节,由STM32F103VB控制其和SD卡之间的所有通信。

要读写SD卡,首先要对其进行初始化。初始化成功后,即可通过发送相应的读写命令对SD卡进行读写。SD卡的读写流程如图2所示。

2.2 SD1.x与SD2.0标准的识别

由于大容量SDHC的出现,SD1.x满足不了SDHC的容量要求,标准已经升级为SD2.0。但也因此出现了许多电子设备无法驱动大容量SD卡的情况,如何识别SD1.x与SD2.0就显得尤为重要。SD2.0的SPI模式初始化流程如图3所示。 判断是否为SD2.0卡,CMD8(SD2.0新增的命令)是关键。若卡是SD2.0,则发送CMD8将会返回有效响应;若是SD1.x,则返回非法响应,这样就可以识别SD卡的类型。

SD1.x与SD2.0的最大不同在于命令地址的表示。SD1.x的地址单位是字节,而SD2.0的地址单位是扇区,地址仍然采用32位4个字节来表示。因此在读写操作时应该根据不同的卡对地址进行相应的处理,若是SD1.x则写入字节地址,若为SD2.0则写入扇区地址。

3 FAT32文件系统 目前有3种FAT文件系统:FAT12、FAT16和FAT32。它们的区别在于文件分配表(File Allocation Table,FAT)中每一表项的大小(也就是所占的位数):FAT12为12位,FATl6为16位,FAT32为32位。本设

1

计选择FAT32文件系统。由于文件存储在硬盘上占用的存储器空间以簇为最小单位,FAT32文件系统不适合管理容量低于512 MB的存储器。簇如果太大,存储小文件会浪费大量的存储空间;如果太小,FAT表会变大,不方便管理。综合考虑,FAT32每簇大小为4 KB。

3.1 FAT32文件系统结构

FAT32文件系统可以分为以下几部分;保留区(reserved

region),存放FAT文件系统的重要参数和引导程序;FAT区

(FAT region),记录簇(cluster)的使用情况;根目录区(root

directory region),记录根目录信息,FAT32文件系统舍弃了这

个区,根目录区可以指定为任意一个簇;文件目录数据区(file

and directory data region),是各种文件数据实际存放的区域。

保留区中的BPB表从扇区0偏移11个字节开始,共占25字

节。表2是格式化为FAT32文件系统的8 GBSD卡首扇区中

读出的BPB参数内容。

逻辑加密存储卡芯片AT88SC1604卡的应用

摘 要:本文介绍了目前应用较为广泛的AT88SC1604逻辑加密卡的特点和工作原理,同时给出了通过单片机控制操作IC卡的的应用实例及程序。

前言

IC卡按结构划分,可分为存储器卡和微处理器卡(CPU card)两大类。逻辑加密卡与普通存储卡相比,内部结构较复杂,其存储区可以分成卡片设置区和应用区。卡片设置区内存放与卡片厂商及发卡者相关代码和卡片密码;应用区又可以根据需要分为不同的分区。逻辑加密卡的安全性相对较高,体现在:卡片设立主密码、每个应用分区具有各自独立的操作密码。逻辑加密卡主要控制作用是:对数据存储区开放/关闭的控制;对数据存储区读/写的控制;对数据存储区擦除操作的控制以及对密码校验和错误次数计数及锁闭功能控制。

AT88SC1604卡的工作原理

AT88SC1604是由美国ATMEL公司设计的逻辑加密存储卡芯片。它具有15704位的存储容量,是目前逻辑加密存储卡中容量较大的一种产品芯片。

芯片特点

(1) AT88SC1604芯片属于单存储器多逻辑分区结构。主存储器除划分了特定的标志数据区和控制数据区之外,还将应用数据区分成四个完全隔离的子区,并在每个子区中配备了各自的读、写控制标志和写入/擦除密码以及密码输入错误计数器等逻辑控制。

(2) 芯片为串行传输方式,并满足ISO7816-3同步传输协议。

(3)芯片采用低功耗的CMOS工艺制造,每字位的读取时间为 s,写周期为5ms。

(4) 芯片内部的存储单元具有至少10000次的擦除/改写循环次数。数据保存期为10年。

2

芯片存储分区结构及定义

AT88SC1604芯片分为制造商代码区、发行商代码区、用户安全密码区、用户密码比较计数区、个人代码区以及四个应用区。每个应用区都由密码区,密码比较计数区,擦除密码区和擦除密码比较计数区、应用数据区和存储器测试区组成。

(1) 制造商代码区(FZ)

该区里记录的卡芯片生产商的特定信息(例如:生产批号、日期、以及特别制定的特征代码),由制造商在芯片出厂前写入。在控制本区的熔丝(FUSHl)没有熔断时,该区的存储单元可以象普通的EEPROM存储单元一样进行擦除和改写。一旦熔丝熔断,所写入的"制造商代码"就不可再更改。

(2) 发行商代码区(IZ)

:发行批号、日期、地区范围编号以及特定用户编号等特征代码)。当控 该区用于记录卡片发行商的特定信息(例如

制本区的熔丝没有熔断时,该区的存储单元内容可以自由的擦除或改写。在个人化处理过程完成之后,控制该区的熔丝(FUSH2)熔断,即可将注入的“发行商代码”完全固化。这一代码也是识别卡片的真伪,区分卡片应用类别的重要标识。

(3) 个人代码区(CPZ)

该区用于存放个人身份标识数据。该区使用上受芯片的“用户密码”的保护。当“用户密码”比较成功,该区可读可写可擦除。“用户密码”比较不成功,该区只能读而不能写入和擦除。

(4) 用户密码区(SC)

这个密码区是整个存储器的“总控制开关”。使用前,由授权持卡人预先输入的一个安全代码作为“参照字”储存在这个存储区里。使用时,必须输入一个“校验密码”。芯片将输入的“校验密码”与内部存储器的“参照字”一一比较。如果比较结果一致,IC卡将开放整个芯片储存器(包括各分区的控制密码和各应用数据区)。各区的“安全密码”区SCn(n=l,2,3,4)与SC的作用是完全类似的。

1,2,3,4)来说,其比较操作要受到对应“应用区密码”比较计数器(SnAC)的计数 对于各分区的密码区SCn (n,

控制。当连续8次输入密码错误,SCn将被锁死。

(5) 密码比较计数区(SCAC)

该区对连续输入的错误密码的次数进行累计。当连续8次不正确的比较操作之后,芯片将被锁死。芯片被锁死之后,将拒绝任何的擦除、写入和比较的操作命令。

该区是8位长,按位写入方式操作。在芯片初始化时是全“1”状态,即读出值为“FFH”。在每次比较输入的密码时,先按从高位到低位的顺序找第一个为“1”的位,将此位写“0”,然后将新输入的“校验密码”与原存储在SC区的“参照字”进行比较。比较操作本身由芯片内部自行完成,而比较结果则通过置

SV标志来判别,即比较成功时SV被置“1”。比较不成功,SV保持原来的“0”状态。在连续8次比较错误过程中每次比较操作之后计数器的计数值分别为“7FH”、“3FH”、“1FH”、“0FH”、“07H”、“03H”、“01H”、“00H”。当计数器为“00H”后,后续的比较操作命令由于无法在“SCAC”区中找到一个为“1”的位,因而芯片拒绝继续执行比较操作。

SnAC(n,1,2,3,4)的作用与SCAC是类似的。操作控制也完全一样。只是SCAC是限制对SC区的比较操作。而SnAC则限制对SCn区的比较操作。SCAC的控制级别最高。当SCAC为“00H”后,芯片内部封锁了对SC区的比较操作,从而使对SCn的比较也被禁止。如果SCAC为非“00H”值,在对SC区的比较密码操作成功之后,SCn能否进行比较操作就由SnAC区的状态值来决定。SnAC区在连续8次比较输入过程中,每次比较操作之后计数器的计数值与SCAC的8个值一样。(即分别为“7FH”、“3FH”、“1FH”、“0FH”、“07H”、“03H”、“OlH”、“00H”)当SnAC为“00H”时,则“应用n区”将被锁死。

(6)擦除密码区(EZn ,n,l.2,3,4)

该区用于存储擦除应用区操作的控制密码。这些密码一般由发行商使用。在个人化处理时输入的最后一组“擦除密码”,在芯片熔丝FUSE2熔断之后将使“擦除密码”保存在该区内。该区不再能读出、写入和擦除,只能进行比较操作。在使用过程中如需对应用区进行擦除操作,都必须首先对相应的EZ区输送一个“擦除密码”与之比较,在“擦除密码比较计数器”不为“00H”的情况下,如果相比较的两代码完全一致,则相应的应用区的单元允许擦除,否则将禁止执行擦除操作。

(7) 擦除密码比较计数区(EnAC ,n=l,2,3,4)

擦除密码比较计数区的作用与SCAC的作用相类似。它对各应用区擦除密码连续输入错误的次数进行累计。最多连续8次不正确的密码比较之后,该区所控制的

应用区的擦除操作即被锁死,从而导致该应用区有可能成为只读和允许单次写入的状态。

3

(8) 应用数据区(AZn ,n,1,2,3,4)

该区主要给用户使用。用于存储系统的相关数据记录和卡片标识等信息。应用数据区的写入与读出分别由该区的前两位Pn和Rn以及SV标志的状态控制,擦除操作则由该区的擦除密码控制。AT88SC1604设计了四个完全隔离的分区,其中1至3分区的单元容量分别是4K位、第4分区的单元容量为3.6K位。

(9) 存储区测试区(MTZ)

该区主要用于芯片生产后对EEPROM单元阵列进行各项性能测试该区不受任何控制区状态和标志状态的保护,允许对这个区进行读出、写人和擦除操作,但不能进行比较操作。

应用实例

基于上述1604芯片的特点,在石化系统的加油电路设计中,我们利用单片机芯片89C2051与IC卡电路组成一个独立系统,控制IC卡芯片的各项操作,该系统通过标准RS232通讯接口,与主控制板实现数据交换,这种电路设计在硬件方面兼容性较好,只要通过协调双方的IC卡通讯协议,可与任何带有RS232接口的控制板或微机相连接。

单片机芯片89C2051的6个端口通过IOC卡座与IC卡相连接,P1.2口控制IC卡5V电源的通断,上电时单片机芯片处于复位状态, 6个端口均输出“1”,IC卡电源处于断开状态,ICSW为IC卡的检测端,当IC卡插入后,该端口与地相接,P1.3口检测到IC 卡已插入卡座,即接通IC卡电源,IC卡操作完毕后,切断IC卡电源,并提示用户可以拔卡。单片机芯片其他4个端口在接通IC卡电源后,根据对卡操作的需要,对IC卡进行复位,读卡,校对密码,擦卡,写卡等操作。

硬件电路

芯片的操作模式时序及设计程序

AT88SCl604芯片的操作模式有五种。它们是通过配PGM、RST、CLK等引脚信号及内部地址计数器(IAC)的状态组合来实现。

芯片复位操作: AT88SCl604有两种复位方式:上电复位和控制复位。

上电复位: 上电复位是当芯片加电时的最初状态。上电复位属于芯片

内部复位。它将使芯片内部所有的隐含标志复位到"0"状态。并使地址计数器复位到0位。

控制复位: 当CLK为低时,在RST脚上的一个下降沿将便芯片产生复位操作。控制复位是将地址计数器复位到0位,而不影响任何内部标志的状态。

注:1)RST为高时禁止计数

2)在CLK端降低之后,延迟一个"复位维持时间"Trh(min 0.1 s)RST端复位(下降沿),同时地址计数器清零。地址计数器清零后延迟一个“数据复位有效时间”Tdvr(max 2 s)第0位单元的数据被送上I/O线。 FWZCX: CLR ICPGM ;复位子程序 CLR ICCLK ;时钟端清0

NOP NOP

SETB ICREST CLR ICREST ;复位端清0

NOP NOP

SETB ICSDA RET

NOP

(2)读出操作: 在进行读出操作时,必须保证使RST脚和PGM脚同时保持为低。如果对芯片各密码控制区进行读出操作,只能是在FUSE2未熔断且SV标志“1”时才能进行。

如果对芯片各标识数据区进行读出操作,除FZ和IZ区外,需要使SV标志置“1”后才能执行。

如果对芯片各应用数据区进行读出操作,需要在SV,1且Rn,1(n,1,2,3,4)状态下才能执行。

注:在CLK的下降沿时,地址计数器加1,地址计数器当前所指的地址单元的数据被输出到I/O线上。因此,在整个时钟周期Tdk期间,包含了地址加1(INC)和读出(REA)两项操作。

读IC数据子程序(R2:需读IC卡字节数,R0:数据区存放低位首地址)

RICDAZ: MOV A,#KXXDZ ;卡信息地址送A MOV C,ICSDA ;位读到A

RLC A LCALL SADR ;寻卡地址

RICDA: MOV R3,#08 SETB ICCLK

RICDA1: SETB ICSDA NOP

NOP CLR ICCLK

4

NOP SADR1: SETB ICREST ;复位端置1 DJNZ R3,RICDA1 SETB ICSDA

CLR ICPGM MOV @R0,A ;8位数据送数据区

DEC R0 CLR ICCLK DJNZ R2,RICDA CLR ICREST RET SADR2: SETB ICCLK

SETB ICCLK ; 寻IC卡位地址子程序(调用前16进制地址送ACC)

SADR: LCALL FWZCX CLR ICCLK MOV B,#08 CLR ICCLK

DJNZ R4,SADR2 MUL AB ;计算位地址: 16进制地址*8

MOV A,R5 MOV R4,A ;低位位地址送R4

JZ SADR3 MOV R5,B ;高位位地址送R5

DEC R5 JNZ SADR1 ;低位地址不为0转

MOV A,R5 SJMP SADR2 JZ SADR3 SADR3: RET DEC R5 ;

(3)比较操作:在进行比较操作时,必须保证使RST脚和PGM脚同时保持为低。比较操作只能对芯片密码控制区

执行,且由芯片内部来判断。在FUSE2未熔断时,只能在SV=0时,对SC区进行比较操作,对其它区的比较操作均为

无效操作。SV=1时,芯片不做任何比较操作。在FUSE2熔断后,只能在SV=0时,对SC区进行比较操作,对其它区的

比较操作均为无效操作。

注:上述芯片密码比较时序图中是假设密码计数器中前两位为0,第三位寻到1的处理时序。

有关芯片SC的时序关系如图2~5图所示:

从操作(B)到(F),地址计数器不变,密码比较的过程是:

(A)比较安全密码/擦除密码序列

(B)在密码输入比较计数器中找出一位为“1”的位

(C)在这个为“1”的单元写“0”

(D)芯片输出“0”

(E)如果比较成功,在PGM的上升沿安全密码/擦除密码的相应标志

(SV,Sn或En)被置“1”,同时安全密码/擦除密码输入比较计数器

(SCAC,SnAC或EnAC)被擦除。

(F)如果擦除成功,相应安全密码/擦除密码标志被置“1”,芯片将输出“1”,否则芯片输出“0”。 (G)在CLK的下降沿,地址计数器加1,并输出下一位的状态。

MOV R3,#08 比较用户密码子程序(地址0AH,0BH)

CPSC: MOV R0,#CMM+2 BJMM2: RLC A MOV R1,#06 MOV ICSDA,C MOV R2,#02

NOP

LCALL MVITI SETB ICCLK MOV A,#0AH NOP

CLR ICCLK LCALL SADR ;寻址

MOV R0,#06 NOP

LCALL BJMMRET DJNZ R3,BJMM2

INC R0 ; 比较密码程序

BJMM: CLR ICREST DJNZ R2,BJMM1 CLR ICPGM MOV R2,#08;查8位 MOV

R2,#02 BJMM4: SETB ICSDA BJMM1: MOV A,@R0 NOP

5

MOV C,ICSDA BJMM6: SETB ICPGM

NOP JC BJMM5 ;是1转

SETB ICCLK ;指向下一位 SETB ICSDA ;写1(擦除) NOP NOP

CLR ICCLK SETB ICCLK NOP NOP

DJNZ R2,BJMM4 CLR ICPGM

NOP LJMP BJMM8 ;计数器为00,卡锁死转

BJMM5: SETB ICPGM LCALL DELY5 NOP CLR ICCLK

NOP CLR ICSDA ;写0

NOP SETB ICSDA SETB ICCLK NOP

NOP MOV C,ICSDA CLR ICPGM NOP

NOP SETB ICCLK LCALL DELY5 JNC BJMM7 ;擦除不成功(密码错)转 CLR ICCLK

SETB FGICG1 ;置已校对密码标志 NOP RET

SETB ICSDA BJMM7: CLR FGICG1 ;建密码错标记 NOP RET

MOV C,ICSDA BJMM8: SETB FGICG2 ;置卡锁死标志 JNC BJMM6 RET

LJMP BJMM7 ;未写入0,转出错

(4)写入操作:写入操作实际包含着两种:当写入的数据为“0”时,本次操作称为“写入操作”。当写入的数据为“1”时,本次操作称为“擦除操作”。“写入操作”可以按位进行。但“擦除操作”只能按字节进行。即使操作时只对单独一位进行擦除,但执行的结果将使这一位所在的字节的所有8位全部置成“1”。

对芯片的任何一个允许写入或擦除的区域,其执行写入和擦除的必要条件是芯片的SV标志为“1”状态。

注:在CLK为低的状态下,PGM端从“0”到“1”,并延时一段“编程建立时间”(Tspr)之后,CLK端从“0”到“1”(这时是写入/擦除操作的开始),在此刻之前的Tds(数据建立时间)由外部向I/O线给出写入数据。CLK端在“1”状态应至少保持5ms(Tchp)之后,CLK端从“1”到“0”(这时是写入/擦除操作的结束)。应特别注意结束写入操作的CLK端的下降沿并不会使地址计数器加1,而只是将刚写入的“数据”读出, 以便外部验证刚才的“写入操作”。

WICDAB: RLC A WICD: MOV A,#KDWDZ ;送擦除卡低位首地址

LCALL SADR ;寻位地址 JC WICDAC ;该位为1,转 MOV R2,#30 ;擦除30字节

SETB ICPGM ;打开编程位

SETB ICPGM LCALL CPESC3 ;擦除

MOV ICSDA,C MOV R0,#RAMDZ ;CPU的RAM中待写

MOV ICSDA,C 入数据地址

SETB ICCLK MOV R2,#30 ;写入30字节

WICDA: MOV A,@R0 SETB ICCLK LCALL WICDAA CLR ICPGM ;关闭编程位 INC

R0 CLR ICPGM ;关闭编程位 DJNZ R2,WICDA LCALL DELY5 ;延时5MS RET CLR

ICCLK

CLR ICCLK ; 向IC卡写入子程序

WICDAA: MOV R3,#08 WICDAC: SETB ICCLK

6

SETB ICCLK CPESC4: SETB ICCLK CLR ICCLK SETB ICCLK DJNZ R3,WICDAB

CLR ICCLK RET CLR ICCLK

DJNZ R3,CPESC4 ; 擦除应用区1

DJNZ R2,CPESC3 CPESC3: SETB ICPGM ;打开编程位,擦除灰名

RET 单入口

SETB ICPGM ; 延时(R7)

SETB ICSDA DELY5: MOV R7,#0AH ;5毫秒延时 SETB ICSDA DELY: PUSH 07

SETB ICCLK DLY1: PUSH 07 SETB ICCLK DLY2: PUSH 07

DLY3: DJNZ R7,DLY3 CLR ICPGM ;关闭编程位

POP 07 LCALL DELY5 ;延时5MS

CLR ICCLK DJNZ R7,DLY2 CLR ICCLK POP 07

SETB ICCLK DJNZ R7,DLY1 SETB ICCLK POP 07

CLR ICCLK DJNZ R7,DELY MOV R3,#07 RET 结束

总希望随着MP3手机的兴起,用户不仅对手机音乐的音量、音质要求越来越高,而且对手机的存储容量的要求也越来越大,能多存些歌,可以省去频繁换歌的烦恼。但目前一般手机自带的内存远远不能满足这些要求,而且很多手机平台也无法支持外接存储卡,为了解决这一问题,就需要有配套的存储管理芯片。

方泰电子的ft1780可以帮手机设计工程师很好的解决这个难题。它不仅可以提供专业的MP3音乐,而且集成了SD/MMC存储卡接口,由于内置文件管理系统,可以方便地升级原有的手机产品,使之具有可更换外接SD/MMC存储卡的功能。本文介绍了ft1780音频处理芯片的功能特点,并详细叙述了其在手机上的应用实例。

ft1780芯片内部结构和特点

图1是ft1780芯片的内部框图,从中可以看出,ft1780主要由7部分组成。

图1:ft1780芯片内部框图。

1. 主机接口:与Baseband相连,Baseband通过它向ft1780发命令和读取状态;

2. 音频/系统引擎:芯片的核心部分,完成64和弦MIDI合成,MP3解码,七段数字均衡器,文件系统管理,系统控制等功能;

3. SD/MMC卡控制器:完成SD/MMC卡接口功能;

24. 输入/输出控制器:完成IS接口,四路LED控制,马达和背光控制等功能;

5. 电源管理系统:可以关掉不用的功能模块,节省系统功耗;

6. 立体声耳机功放:可以直接驱动16ohm的耳机,输出功率可达到20mW以上;

7

7. 喇叭功放:可以直接驱动8ohm喇叭,输出功率可达到500mW以上;

ft1780芯片采用6mmx7mm 48Pin的BGA封装,与其它普通MP3解码芯片相比,它有以下几个主要特色: 1. 工作电流小,具有高效的省电设计电路,芯片内各模块可以单独控制开和关,可满足手机上不同的工作模式要求; 2. 支持全系列采样率和编码率的MP3数据,包括MPEG Version1 Layer3,MPEG Version2 Layer3和MPEG

Version2.5 Layer3

标准,采样率范围是8~48kHz,编码率是8~320kbps,解码品质高,声音音质好;

3. 支持64和弦的铃声,支持自有的人声音效格式(FTF格式),同时支持自然音和背景音的播放; 4. 内置SD/MMC卡的文件管理系统程序,不需要手机的基带来解析SD/MMC卡上的文件系统,基带只要发简单的命令就可以控制ft1780的播放功

能,SD/MMC卡的数据可以不经过基带,由ft1780芯片自己读取和播放,这样可以大大减轻基带的负担,也因此拓宽了ft1780的应用面。

5. 内置高品质立体声耳机功率放大电路,输出功率大,并具有无耦合电容设计的耳机输出电路。普通的耳机输出需要两个较大的隔直电容,若电容容量太小,会使低频响应变差,声音低频失真。而无耦合电容设计可以节省成本,节省手机电路板宝贵的空间,增加耳机输出的保真度。

6. 内置喇叭功率放大电路,在8ohm喇叭上可以输出500mW以上的功率。

图2:典型应用示意图。

ft1780芯片的曲型应用

ft1780的应用电路比较简单,所需的外围器件很少,只需要十几个电阻和电容,典型应用线路如2所示。通过调整R1和R3的比值可以调节ft1780内部输出到喇叭的增益,通过调整C1和C3可以调节喇叭输出声音的高频和低频特性,对于图中所列参数,R1=33k欧姆,C1=330pF,R3=33k欧姆,C3=0.1uF,增Gain=R1/R3=1,高频截止频率为F=1/(2*π*R1*C1)=14.6kHz,H

低频截止频率为F=1/(2*π*R3*C3)=48.2Hz。从Audio In进来的音频信号可以通过控制从喇叭或耳机出来,并且可以根L

据需要通过R2和C2调节它的低频响应曲线。图中,耳机的输出已用了无耦合电容设计,所以图上没有输出耦合电容,但要

8

注意的是,耳机的公共端不是通常的“地”,需是芯片上的虚拟地脚“HPR”。另外芯片的VDDA脚可以直接与电池的正级相接,在不需芯片工作时,可以用软件来控制芯片进入"Power Down"状态,这时芯片的耗电只有几微安。 相关软件和播放流程

ft1780芯片的工作需要相应的驱动程序支持。驱动程序采用模块化结构,各功能都有相应的程序,在Design In过程中,只要修改硬件相关的地址参数,加入中断服务程序(也可以使用定时器相关的查询模式),然后调用相应的API就可以正常工作(发出声音)了。图3是软件模块示意图,下面简单介绍一下各模块的功能:

图3:软件模块示意图。

1. 硬件平台相关模块:需要根据手机平台的情况修改相应的参数,主要有芯片寄存器的操作地址,输入时钟的频率等; 2. MIDI模块:MIDI数据解析和处理,MIDI播放控制和回调控制;

3. ADPCM模块:ADPCM数据解析和处理,ADPCM播放控制和回调控制;

4. FTF模块:FTF数据解析和处理,FTF播放控制和回调控制;

5. SD/MMC模块:SD/MMC命令解析和处理,SD/MMC播放控制和回调控制;

6. MP3模块:MP3数据解析和处理,MP3播放控制和回调控制;

7. 中断服务模块:对芯片的各个中断事件作相应的处理,主要补充数据,播放结束控制和出错信息处理等; 8. 驱动程序API模块:提供用户所需的所用功能的调用,用户不必关心具体底层模块的细节,只需与上层API打交道; 9. 用户参考模块:如何使用API控制播放的一个例子,也可以作为API的进一步包装,供用户直接使用。

下面我们介绍一下ft1780软件的使用方法。

播放Baseband上文件的流程

图4是播放Baseband上文件的流程图。当用户想播放Baseband上的音频数据时,首先是要对ft1780芯片做初始化,然后对要播放的数据做预处理,驱动程序会分析数据格式,并根据格式自动调用底层处理函数,再下一步是启动中断或定时器、消息等机制,这一步的目的是启动后台处理任务,当进入播放状态时,需由后台任务完成后续的处理工作,最后就是发播放开始命令,开始播放声音,进入播放状态。

图4:播放Baseband上文件的流程图。

9

在播放状态下,ft1780芯片会根据内部运作情况发出中断请求,Baseband必需在一定时间内处理相应事件,否则会出现声音停顿,不连续等现象。在ft1780芯片内部有很大的FIFO(先进先出存储器)来保存播放的数据,可以适应低端Baseband中断反应延时比较大的问题,保证声音播放的顺畅。

在播放过程中,Baseband随时可以调用相应的API来停止当前的播放,或读取播放信息,暂停/恢复等操作。 播放SD/MMC卡上文件的流程

图5是播放SD/MMC卡上文件的流程图。当用户想播放SD/MMC卡上的声音文件时,首先是要对ft1780芯片做初始化,然后读出卡上的声音文件,选择要播放的文件,调用简单的API播放命令后,进入播放状态,芯片会自动读取卡上的数据,播放出声音,再下一步是启动中断或定时器、消息等机制,这一步的目的是启动后台处理任务,处理中断事务。 带SD/MMC存储卡接口的MP3和弦芯片ft1780

图5:播放SD/MMC卡上文件的流程图。

虽然看上去与播放Baseband上文件的流程差不多,但主要有以下不同:当播放Baseband上文件时,Baseband必须不断地送数据到ft1780芯片内部,中断会比较频繁(与所播放的文件的码流率有关),而当播放SD/MMC卡上的文件时,ft1780芯片自己从SD/MMC卡里读取所需数据,不需要Baseband的干预,在播放过程中基本上没有中断任务,只有在播放结束时会发出中断告知Baseband,由Baseband决定下一步的工作,如重复播放、或播放下一个文件,所以对Baseband的要求更低,适应性更广。

在播放过程中,Baseband随时调用相应的API函数,完成停止播放,暂停/恢复等功能。

,,,,,,存储卡控制芯片

凭借优良性能和出色的销售业绩,芯邦自主研发的SD/MMC存储卡控制芯片在

“2007年中国半导体创新产品和技术项目”评选中,荣获了“中国半导体创新产品”称号。

芯邦公司是由归国留学人员于2003年在深圳创立的。公司致力于成为与移动存储和多媒体相关的控制芯片设计及其整体解决方案开发的领导者。

快速成长与发展的闪存(flash)存储器已经成为半导体产业特别是移动存储产业发展的主要推动力,而将闪存与各种接口和应用相连接的控制器芯片起着关键性的作用,它直接影响到闪存的推广和应用,市场空间非常广阔。

移动多媒体是带动消费类电子产品发展的领头羊,例如MP3, MP4, GPS等等,过去几年和未来都显示出巨大的发展空间,为芯片设计公司提供了前所未有的发展机遇。

凭借芯邦核心团队在海外著名芯片设计公司(Broadcom、Philips)几十年芯片设计与管理经验,加上本土化的客户服务与市场开拓优势,在中国良好的集成电路产业发展环境下,芯邦立足和专注于移动存储和多媒体相关控制芯片的开发和应用,为该产业的发展做出了积极的贡献。

成立仅短短4年多的芯邦,依靠不懈地努力自主创新研制推出的第一代产品——U盘系列控制芯片,截至2007年底累计出货量已超过一亿片,单月销售量更突破700万片,已占全球约40%的市场份额,成为U盘控制芯片全球最大供货商;2007年下半年,芯邦又在创新模式下开发出国内第一款SD/MMC卡控制芯片,打破了以往长期被中国台湾的厂商垄断供货的局面。

10

在保留区之后是FAT区,存有文件分配表。一般文件系统中有2份文件分配表FAT1和FAT2,每份FAT表占用空间的大小可从BPB表中查得。

由于采用的是SDHC卡和FAT32文件系统,紧接在FAT区之后的是文件目录数据区,真正意义上的数据从这个区开始,以簇编号,顺序上第1个簇编号为第2簇,此簇通常为FAT32根目录所用。FAT16从根目录所占的32个扇区之后的第一个扇区开始以簇为单位进行数据处理,这之前仍以扇区为单位。目录与数据是统一放到这个区域的,并且都不是在一个连续的区域内存放。没有任何特殊标记来区分哪个簇是目录项,哪个簇是数据项,而是由文件系统从根目录出发通过查找的方法来确定簇的类型。

3.2 FAT32文件系统实现

本文设计的文件系统采用模块化层次结构,其总体框架如图4所示。其中,

箭头表示调用关系。

应用程序是面向用户的,为满足某种功能需求而编写的程序。可以通过调

用文件系统提供的API函数对文件和目录进行相应的操作。

文件管理和目录管理模块是直接与应用程序接口的模块,位于整个文件系

统的最高层。文件管理模块提供所有与文件操作相关的函数,目录管理模

块提供所有与目录操作相关的函数。在对文件操作的大多数情况下,文件

管理模块需要调用目录管理模块的相关功能。

文件分配表管理模块主要用来对文件系统的FAT表进行管理,根据系统的请求对FAT表的内容进行相应的修改。文件目录表管理模块主要提供对文件和目录的基本属性信息的管理。这两个模块管理着文件系统的两个重要数据结构,应用程序不能直接调用它们。

缓存模块是为了降低系统访问SD卡的次数,提高整个系统的处理速度而加入的。它使用了部分RAM作为缓存来保存一些访问过的扇区的数据,一般用来加载FAT表和FDT表的数据;向SD卡写入数据时,也需要用它加载数据。 以上几个模块的操作都建立在底层驱动程序上。底层驱动程序主要是向SD卡读写某个扇区的程序。

11

文件分配表管理模块包含几个处理簇链的函数,如获取指定簇下一簇簇号(fat_next_clus())、建立簇与指定簇的链接关系(fat_link_clus())、在簇后增加一个空白簇到簇链中(fat_add_clus())和删除指定簇的簇链(fat_del_clus_chain())。文件目录表管理模块包含几个处理文件登记项的函数,如在给定目录下查找文件(fat_find_fdt())、在给定目录下添加文件(fat_add_fdt())和在给定目录下删除文件(fat_delete_fdt())。目录管理模块主要是实现建立、删除目录的操作,包含的函数有根据路径查找目录所在簇

(fat_open_dir())、建立目录(fat_make_dir())和删除目录(fat_del_dir())。用户使用文件系统主要是对文件的操作,文件管理模块提供了对文件的创建、修改和删除等操作,包含函数新建文件(file_create())、打开文件(file_open())、读写指针设定(file_seek())、读取文件数据(file_read())、写入文件数据(file_write())、删除文件(file_delete())和关闭文件(file_close())。

结语

本文介绍了SD卡在海洋数据存储中的应用,使用高性能的STM32F103xx系列处理器提高了SD卡的数据读写速率,很好地解决了海洋数据采集中的大容量存储问题和SDl.x与SD2.0的识别问题,并给出了适用于SD卡的FAT32文件系统的参数设置及其实现方法。

以下是相关SD卡和USB电路图

12

深入理解SD卡基础原理以及内部结构

1、 简介:

SD卡(Secure Digital Memory Card)是一种为满足安全性、容量、性能和使用环境等各方面的需求而设计的一种新型存储器件,SD卡允许在两种模式下工作,即SD模式和SPI模式,本 系统采用SPI模式。本小节仅简要介绍在SPI模式下,STM32处理器如何读写SD卡,如果读者如希望详细了解SD卡,可以参考相关资料。

SD 卡内部结构及引脚如下图所示:

13

2、SD卡管脚图:

3、SPI模式下SD各管脚名称为: sd 卡:

SPI模式下SD各管脚名称 为.JPG

注: 一般SD有两种模式:SD模式和SPI模式,管脚定义如下:

(A)、SD MODE 1、CD/DATA3 2、CMD 3、VSS1 4、VDD 5、CLK 6、VSS2 7、DATA0 8、DATA1 9、DATA2 (B)、SPI MODE 1、CS 2、DI 3、VSS 4、VDD 5、SCLK

6、VSS2 7、DO 8、RSV 9、RS SD 卡主要引脚和功能为:

CLK:时钟信号,每个时钟周期传输一个命令或数据位,频率可在0,25MHz之间变化,SD卡的总线管理器可以不受任何限制的自由产生0,25MHz 的频率;

CMD:双向命令和回复线,命令是一次主机到从卡操作的开始,命令可以是从主机到单卡寻址,也可以是到所有卡;回复是对之前命令的回答,回复可以来自单 卡或所有卡;

DAT0,3:数据线,数据可以从卡传向主机也可以从主机传向卡。

SD卡以命令形式来控制SD卡的读写等操作。可根据命令对多块或单块进行读写操作。在SPI模式下其命令由6个字节构成,其中高位在前。SD卡命令 的格式如表1所示,其中相关参数可以查阅SD卡规范。

4、MicroSD卡管脚图:

5、MicroSD卡管脚名称:

MicroSD卡管脚名 称.JPG

SD 卡与MicroSD卡仅仅是封装

上的不同,MicroSD卡更小,大小

上和一个SIM卡差不多,但是协

议与SD卡相同。

14

一般我们用单片机操作SD 卡时,都不需要对FAT分区表信息做处理,原因如下:

1)、操作FAT分区表要增加程序代码量、增加SRAM的消耗,对于便携应用来说代码大小和 占用SRAM的多少至关重要。

2)、即使我们对FAT分区表不做任何了解,实际上我们一样可以向SD卡上写入数据,这就表明使用FAT对我们做数 据存储应用来说如同鸡肋。

3)、耗费大量经历和时间去了解FAT分区表对于我们做嵌入式软件开发的人来说有些得不偿失。 4)、SD卡支持 两种操作模式,SD模式和SPI模式,SPI模式做SD数据操作时根本不需要知道FAT,这时候SD卡对于我们来说实际上就是个大的、快速的、方便的、容 量可变的外部存储器。

基于以上原因,一般情况下对SD卡的操作只需要了解SPI通讯就可以了,而现在大部分单片机都有SPI接口,那么操作

易如反掌。 SD卡

以下是做SD卡试验时使用的电路图:

SD_CS/ 连接到单片机的片选SD管脚,只有单片机设置SD_CS/为低电平时才可以操作SD卡。 MOSI连接单片机SPI总线的MOSI管脚(SPI数据 输入),单片机从这个管脚读取SD卡内的数据。 MISO连接单片机SPI总线的MISO管脚(SPI数据输出)、单片机通过这个管脚向SD卡内写 入数据。 SCK连接单片机SPI总线的SCK(SPI时钟)

SD管脚实际上在SD卡内部连接到了GND,当SD插座上没插入SD卡时,单 片机从这个管脚能读到高电平(前提是使用单片机内部上拉输入,或者外部增加一个上拉电阻),一旦插入SD卡,这个管脚就变成低电平,这个功能用来检测是否 插入SD卡。

RSV1和RSV2是保留功能管脚,不需要操作。

MicroSD卡的连接和SD卡大同小异,只是MicroSD卡比SD卡少 一个GND管脚,所以不能使用上面做的这种插入卡的检测,实际上现在很多SD卡/MicroSD卡插座都有插入检测管脚,当然,一分钱一分货,价格上当然 也要贵一些 顺便提一下,普通SD卡插座最多5块钱。

SPI命令格式

Byte 1 Byte2-5 Byte 6

7 6 5 0 31 0 7 0

0 1 Command Command Argument CRC 1

以下是一个简单的测试SD卡读 写的程序,程序是基于Atmega128单片机编写的,对于Atmega的其他单片机仅需要做管脚改动就可以使用,其他单片机更改要更大。 sd.h

//SPI 各线所占用的端口 #define SD_PORT PORTB #define SD_SS PB6

#define SD_PIN PINB #define SD_SCK PB1 #define SD_SS_H SD_PORT |= (1<

#define SD_MOSI PB2 #define SDSS_L SD_PORT &= ~(1<

#define SD_MISO PB3 #define SD_SCK_H SD_PORT |= (1<

#define SD_DDR DDRB #define SD_SCK_L SD_PORT &= ~(1<

15

#define SD_MOSI_H SD_PORT |= (1< // 串口调试程序

#define SD_MOSI_L SD_PORT &= ~(1< void uart0_init(void) #define

SD_MISO_IN (SD_PIN&(1< {

// 错误号 UCSR0B = 0x00; //disable while setting baud rate

#define INIT_CMD0_ERROR 0xFF UCSR0A = 0x00;

#define INIT_CMD1_ERROR 0xFE UCSR0C = 0x06; // 00000110 UART0设置为异步模式、无奇偶#define WRITE_BLOCK_ERROR 0xFD 校验、1位停止位、8位数据位

#define READ_BLOCK_ERROR 0xFC UBRR0L = 0x17; //set baud rate lo

#define TRUE 0x01 UBRR0H = 0x00; //set baud rate hi 设置UART0口通信速率// MMC/SD 命令(命令号从40开始,只列出基本命令,并9600

没有都使用) UCSR0B = 0x18;

#define SD_RESET 0x40 + 0 }

#define SD_INIT 0x40 + 1 void putchar(unsigned char content) #define

SD_READ_CSD 0x40 + 9 {

#define SD_READ_CID 0x40 + 10 while(!(UCSR0A & (1 << UDRE0))); /* 判断上次发送有没有#define SD_STOP_TRANSMISSION 0x40 + 12 完成

0x40 + 13 /* 发送数据 */ #define SD_SEND_STATUS UDR0 = content;

#define SD_SET_BLOCKLEN 0x40 + 16 }

void putstr(unsigned char *s) #define SD_READ_BLOCK 0x40 + 17

{ #define SD_READ_MULTI_BLOCK 0x40 + 18

0x40 + 24 while(*s) #define SD_WRITE_BLOCK

{ #define SD_WRITE_MULTI_BLOCK 0x40 + 25 //片选关(MMC/SD-Card

Invalid) putchar(*s);

#define SD_Disable() SD_SS_H s++;

//片选开 (MMC/SD-Card Active) }

#define SD_Enable() SD_SS_L }// 端口初始化

SD_TEST.C void SD_Port_Init(void) //ICC-AVR application builder :

03-5-20 8:39:11 {

// Target : M128 SD_PORT |= (1<< // Crystal: 3.6864Mhz SD_DDR |=

(1<<< #include SD_DDR &= ~(1< #include }

#include 'sd.h' // 初始化 MMC/SD 卡为SPI模式

void uart0_init(void); unsigned char SD_Init(void) void

putchar(unsigned char content); {

void putstr(unsigned char *s); unsigned char retry,temp; void

SD_Port_Init(void); unsigned char i; unsigned char SD_Init(void);

SPCR=0x53; //设定SPI为128分频,慢速进行初始化 unsigned char

SD_write_sector(unsigned long addr,unsigned SPSR=0x00;

char *Buffer); for (i=0;i<0x0f;i++) unsigned char

SD_read_sector(unsigned long addr,unsigned {

char *Buffer); SPI_TransferByte(0xff); //延迟74个以上的时钟

unsigned char SPI_TransferByte(unsigned char byte); }

unsigned char Write_Command_SD(unsigned char SD_Enable(); //开片选

cmd,unsigned long address); SPI_TransferByte(SD_RESET); //发送复位命令 unsigned long SD_find(void); SPI_TransferByte(0x00);

16

SPI_TransferByte(0x00); return(tmp);

SPI_TransferByte(0x00); }

SPI_TransferByte(0x00); // 写一个扇区(512Byte) to MMC/SD-Card//如果写完成返回SPI_TransferByte(0x95); TRUE

SPI_TransferByte(0xff); unsigned char SD_write_sector(unsigned long

addr,unsigned char

SPI_TransferByte(0xff); *Buffer)

{ retry=0;

do{ //发送初始化命令 unsigned char temp;

temp="Write"_Command_SD(SD_INIT,0); unsigned int i; retry++; //延迟8个时钟 SPI_TransferByte(0xFF); if(retry==100) //重试100次 SD_Enable();

//开片选

{ temp =

SD_Disable(); //关片选 Write_Command_MMC(MMC_WRITE_BLOCK,addr<<9);

return(INIT_CMD1_ERROR); //如果重试100次失败返 //发送写扇区命令

回错误号 if(temp != 0x00) } {

}while(temp!=0); SD_Disable();

MSD_Disable(); //关片选 return(temp);

SPCR=0x50; //设置SPI为2分频。进行高速读写 }

SPSR=0x01; SPI_TransferByte(0xFF);

//返回成功 return(TRUE); SPI_TransferByte(0xFF); }

SPI_TransferByte(0xFE); // 发送命令给 MMC/SD卡 for (i=0;i<512;i++)

//Return: 返回MMC/SD卡对命令响应的第2字节,作为{

命令成功判断 SPI_TransferByte(*Buffer++); //发送512字节数据

unsigned char Write_Command_SD(unsigned char }

cmd,unsigned long address) //CRC-Byte

{ SPI_TransferByte(0xFF); //Dummy CRC unsigned char tmp;

SPI_TransferByte(0xFF); //CRC Code unsigned char retry="0"; temp =

SPI_TransferByte(0xFF); //读SD卡运行响应 SD_Disable(); if((temp &

0x1F)!=0x05) //如果最后4位为0101,为操作成SPI_TransferByte(0xFF); 功。否则为操作失败。

SD_Enable(); {

SPI_TransferByte(cmd); //将32位地址进行移位作为SD_Disable();

地址字节 return(WRITE_BLOCK_ERROR); //返回错误

SPI_TransferByte(address>>24); }

SPI_TransferByte(address>>16); while (SPI_TransferByte(0xFF) !=

0xFF);

SPI_TransferByte(address>>8); SD_Disable();

SPI_TransferByte(address); return(TRUE); //返回成功

SPI_TransferByte(0xFF); }

SPI_TransferByte(0xFF); // 读512字节 from MMC/SD-Card//如果成功返回TRUE do{ unsigned char SD_read_sector(unsigned long addr,unsigned char

tmp=SPI_TransferByte(0xFF); //发送8个时钟接受最后一*Buffer)

个字节 {

retry++; unsigned char temp; }while((tmp==0xff)&&(retry<8));

unsigned int i;

17

unsigned char data;

&(data[3]=='A')&&(data[4]=='S')&&(data[5]=='T')&&(data[6]=

SPI_TransferByte(0xff); ='A')&&(data[7]=='R')&&(data[8]=='T')));

MMC_Enable(); return tmp; //返回开始标志的下一个扇区 temp =

Write_Command_SD(SD_READ_BLOCK,addr<<9); } // 发送一个字节

//发送读扇区命令 unsigned char SPI_TransferByte(unsigned char byte)

{ if(temp != 0x00)

SPDR = byte; {

//检测线路是否空闲 SD_Disable(); while (!(SPSR & 0x80));

//返回错误号 return SPDR; return(READ_BLOCK_ERROR);

} }// 主程序例子

while(SPI_TransferByte(0xff) != 0xfe); void main(void)

for(i=0;i<512;i++) {

{ unsigned long temp; data = SPI_TransferByte(0xff); //存数据

unsigned char data[512]; *Buffer++=data; unsigned char

data2[512]={'sssssssssssssssssssssssss'};

} unsigned char comm1[]={'rnhello worldrn'};

//读CRC码 SPI_TransferByte(0xff); unsigned char

comm2[]={'rnSD_INIT OKrn'};

SPI_TransferByte(0xff); //读CRC码 uart0_init();

SD_Disable(); SD_Port_Init(); //端口初始化

return(TRUE); //返回成功 if(SD_Init()== 0x01)

始标志(预设DATASTART)根据实际{ //SD卡初始化,并读取返回值 } // 查找数据开

需要删改 putstr(comm2);

unsigned long SD_find(void) }

{ temp="SD"_find(); //查找DATASTART数据开始标志,返unsigned long

tmp="400"; 回下一扇区地址

unsigned char data[512]; SD_read_sector(1001,data); //读取temp地址的512字节数do 据,512字节数据存入data数组

{ putstr(data); SD_read_sector(tmp,data); //从0扇区开始查找

SD_write_sector(temp,data2); //将data2数组512字节数据tmp++; //查找DATASTART 写入temp扇区

}while(!((data[0]=='D')&&(data[1]=='A')&&(data[2]=='T')&}

测试程序很简单,仅仅是做了一下读写SD卡的测试。

关于SD卡的几点注意事项。

1、无论我们愿意不愿意,SD卡每次读写数据的最小单位是1个扇区,即512个字节。

2、SD卡与单片机连接的 SPI总线不能太长,要尽量短。这样的好处是速度可以更快,也不容易出错。 3、虽然我们并不关心FAT文件表,但是我们仍然要关心SD卡的存储结构,如果我们不想使用PC机来读取保存在SD卡上的数据那我们就

不用关心SD存储结构了。但,作为一个大容量的可移动存储设备,不能用PC机来读取是个很大的遗憾,我解决这个遗憾的方法如下:

3-1、因为我不了解FAT复杂的结构,所以我做的程序没法去按照FAT表的各项功能来进行创建文件、删除文件、创建目录等等操作。

3-2、虽然我们的单片机不能创建文件,但是PC机是可以创建文件的啊~所以我使用PC机将SD卡格式化,之后在SD卡上创建一个大文件,比如我的128M的SD卡上我建立了一个100M的文件。这里需要注意一下,一般使用windows创建文件的功能时是没有办法指定创建文件的大小的,空文件就是0个字节的长度,而我们是需要一个固定长度的文件的,所以我用VC编写了一个小软件,这个软件可以为我创建一个100M长度的空文件,记住,这点很重要:一个固定长度的空文件

3-3、虽然我们建立了个文件在SD卡上,可是我们因为不去了解FAT表,所以我们一样不知道这个文件到底位于SD卡

18

的什么地方,不要以为它会在0字节的地方开始,为了找到这个文件的开始位置,我们可以在建立的那个空文件的开头写上几个字符,比如我程序里面写的“DATASTART”,接下来我们要做的就是一个扇区一个扇区的去找这个几个特殊的字符,这是个笨方法,但却是最简单直观的方法。这个方法有两个缺点:a、如果文件建立在整个SD卡的后面,那找到这个文件需要漫长的等待。b、如果碰巧某个文件里面也有我们定义的那个特殊字符串的话,那就乱套了~不过好在我们使用的SD卡一般都是专用的,并不能拿去做其他应用,比如从公司copy点文件回家之类的,那就能保证这个SD卡上

开始的那些扇区中的某一文件的简单性,即只有我们需要的那个文件,其他文件并不存在,而且这个文件肯定会从SD卡

个开始。这样说来的话找到这个字符串也不是那么慢嘛~^_^。不过这里要建议一下,在使用SD卡之前最好用windows将它完全格式话一下。

3-4、一旦我们找到了我们要写入文件的起始位置(它一般表示为一个扇区号),那我们就可以在这个起始扇区的下一个扇区写入数据了。

4、OK,看起来很简单~有了这种存储方式我们还需要IIC接口的 EEPROM干吗呢,

SD卡的SPI模式的初始化顺序介绍

清晰明了的MMC卡时序图(虽然这个是MMC卡的,但是在初始化的时候CMD0的时序是一样的) 电路:我用的SD卡的电路其实很简单,参考SD卡的官方资料中的电路链接就可以的。

供电问题:由于SD卡的电压是3.3V,所以你的CPU必须支持3.3V的IO端口输出。

再来说一说鸡毛蒜皮的细节:

为了使SD卡初始化进入SPI模式,我们需要使用的命令有3个:CMD0,ACMD41,CMD55(使用ACMD类的指令前应先发CMD55,CMD55起到一个切换到ACMD类命令的作用)。

为什么在使用CMD0以后不使用CMD1,CMD1是MMC卡使用的指令,虽然本文并不想讨论MMC卡的问题,但是我还是要说:为了实现兼容性,上电或者发送CMD0后,应该首先发送CMD55+ACMD41确认是否有回应,如果有回应则为SD卡,如果等回应超时,则可能是MMC卡,再发CMD1确认。

正确的回应内容应该是:

CMD0——0x01(SD卡处于in-idle-state)

CMD55——0x01(SD卡处于in-idle-state)

ACMD41——0x00(SD卡跳出in-idle-state,完成初始化准备接受下一条指令)

这里要说的是如果最后的回应内容还是0x01的话,可以循环发送CMD55+ACMD41,直到回应的内容0x00。 在所有的指令中,唯独CMD0特殊,在向SD卡发送以前需要向SD卡发送74+个时钟。那么为什么要74个CLK呢,因为在上电初期,电压的上升过程据SD卡组织的计算约合64个CLK周期才能到达SD卡的正常工作电压他们管这个叫做Supply ramp up time,其后的10个CLK是为了与SD卡同步,之后开始CMD0的操作,严格按照此项操作,一定没有问题。 关于SD卡的SPI总线,在读入数据时SD卡的SPI是CLK的上升沿输入锁存,输出数据也是在上升沿。 向SD卡写入一个CMD或者ACMD指令的过程是这样的:

首先使CS为低电平,SD卡使能;其次在SD卡的Din写入指令;写入指令后还要附加8个填充时钟,是SD卡完成内部操作;之后在SD卡的Dout上接受回应;回应接受完毕使CS为低电平,再附加8个填充时钟。 在SD卡的Din没有数据写入时,应使Din保持高电平。

SD卡在单片机上的应用以及SD卡引脚 电路图及工作原理

SD卡在现在的日常生活与工作中使用非常广泛,时下已经成为最为通用的数据存储卡。在诸如MP3、数码相机等设备上也都采用SD卡作为其存储设备。SD卡之所以得到如此广泛的使用,是因为它价格低廉、存储容量大、使用方便、通用性与安全性强等优点。既然它有着这么多优点,那么如果将它加入到单片机应用开发系统中来,将使系统变得更加出色。这就要求对SD卡的硬件与读写时序进行研究。对于SD卡的硬件结构,在官方的文档上有很详细的介绍,如SD卡内的存储器结构、存储单元组织方式等内容。要实现对它的读写,最核心的是它的时序,笔者在经过了实际的测试后,使用51单片机成功实现了对SD卡的扇区读写,并对其读写速度进行了评

估。下面先来讲解SD卡的读写时序。

(1) SD卡的引脚定义:

SD卡引脚功能详述:

19

引脚 SD模式 SPI模式 编号

名称 类型 描述 名称 类型 描述 1 CD/DAT3 IO或PP 卡检测/ 数据线3 #CS

I 片选 2 CMD PP 命令/ 回应 DI I 数据输入 3 V S 电源地 VSS S 电源地 SS1

4 V S 电源 VDD S 电源 DD

5 CLK I 时钟 SCLK I 时钟 6 V S 电源地 VSS2 S 电源地 SS2

7 DAT0 IO或PP 数据线0 DO O或PP 数据输出 8 DAT1 IO或PP 数据线1

RSV 9 DAT2 IO或PP 数据线2 RSV 注:S:电源供给 I:输入 O:采用推拉驱动的输出 PP:采用推拉驱动的输入输出 SD卡SPI模式下与单片机的连接图:

SD卡支持两种总线方式:SD方式与SPI方式。其

中SD方式采用6线制,使用CLK、CMD、DAT0~DAT3

进行数据通信。而SPI方式采用4线制,使用CS、CLK、

DataIn、DataOut进行数据通信。SD方式时的数据传输

速度与SPI方式要快,采用单片机对SD卡进行读写时

一般都采用SPI模式。采用不同的初始化方式可以使SD

卡工作于SD方式或SPI方式。这里只对其SPI方式进

行介绍。

(2) SPI方式驱动SD卡的方法

SD卡的SPI通信接口使其可以通过SPI通道进行数

据读写。从应用的角度来看,采用SPI接口的好处在于,

很多单片机内部自带SPI控制器,不光给开发上带来方

便,同时也见降低了开发成本。然而,它也有不好的地

方,如失去了SD卡的性能优势,要解决这一问题,就要用SD方式,因为它提供更大的总线数据带宽。SPI接口的选用

是在上电初始时向其写入第一个命令时进行的。以下介绍SD卡的驱

动方法,只实现简单的扇区读写。

1) 命令与数据传输

1. 命令传输

SD卡自身有完备的命令系统,以实现各项操作。命令格式如下:

命令的传输过程采用发送应答机制,过程如下:

20

每一个命令都有自己命令应答格式。在SPI模式中定义了三种应答格式,如下表所示:

字节 位 含义 2 7 溢出,CSD覆盖

6 擦除参数 1 7 开始位,始终为0

5 写保护非法 6 参数错误

4 卡ECC失败 5 地址错误

3 卡控制器错误 4 擦除序列错误

2 未知错误 3 CRC错误

1 写保护擦除跳过,锁,解锁失败 2 非法命令

0 锁卡 1 擦除复位

2,5 全部 操作条件寄存器,高位在前 0 闲置状态

写命令的例程: 向SD卡中写入命令,并返回回应的第二个字节

unsigned char Write_Command_SD(unsigned char *CMD) {

{ Write_Byte_SD(*CMD++);

unsigned char tmp; }

unsigned char retry=0; //获得16位的回应

unsigned char i; Read_Byte_SD(); //read the first byte,ignore it.

//禁止SD卡片选 do

SPI_CS=1; { //读取后8位

//发送8个时钟信号 tmp = Read_Byte_SD();

Write_Byte_SD(0xFF); retry++;

//使能SD卡片选 }

SPI_CS=0; while((tmp==0xff)&&(retry<100));

//向SD卡发送6字节命令 return(tmp);

for (i=0;i<0x06;i++) }

2) 初始化

SD卡的初始化是非常重要的,只有进行了正确的初始化,才能进行后面的各项操作。在初始化过程中,SPI的时钟不能太快,否则会造初始化失败。在初始化成功后,应尽量提高SPI的速率。在刚开始要先发送至少74个时钟信号,这是必须的。在很多读者的实验中,很多是因为疏忽了这一点,而使初始化不成功。随后就是写入两个命令CMD0与CMD1,使SD卡进入SPI模式

初始化时序图:

21

初始化例程:初始化SD卡到SPI模式 }

unsigned char SD_Init() }

{ while(temp!=1); //回应01h,停止写入

unsigned char retry,temp; //发送CMD1到SD卡

unsigned char i; CMD[0] = 0x41; //CMD1

unsigned char CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95}; CMD[5] = 0xFF;

SD_Port_Init(); //初始化驱动端口 retry=0;

Init_Flag=1; //将初始化标志置1 do

for (i=0;i<0x0f;i++) { //为了能成功写入CMD1,写100次

{ temp=Write_Command_SD(CMD);

Write_Byte_SD(0xff); //发送至少74个时钟信号 retry++;

} if(retry==100)

//向SD卡发送CMD0 { //超过100次

retry=0; return(INIT_CMD1_ERROR);//CMD1 Error!

do }

{ //为了能够成功写入CMD0,在这里写200次 }

temp=Write_Command_SD(CMD); while(temp!=0);//回应00h停止写入

retry++; Init_Flag=0; //初始化完毕,初始化标志清零

if(retry==200) SPI_CS=1; //片选无效

{ //超过200次 return(0); //初始化成功

return(INIT_CMD0_ERROR);//CMD0 Error! }

3) 读取CID

CID寄存器存储了SD卡的标识码。每一个卡都有唯一的标识码。

CID寄存器长度为128位。它的寄存器结构如下:

名称 域 数据宽度 CID划分

生产标识号 MID 8 [127:120]

OEM/应用标识 OID 16 [119:104]

产品名称 PNM 40 [103:64]

产品版本 PRV 8 [63:56]

产品序列号 PSN 32 [55:24]

保留 , 4 [23:20]

生产日期 MDT 12 [19:8]

CRC7校验合 CRC 7 [7:1]

未使用,始终为1 , 1 [0:0]

它的读取时序如下:

与此时序相对应的程序如下:

读取SD卡的CID寄存器 16字节 成功返回0

unsigned char Read_CID_SD(unsigned char *Buffer)

22

{//读取CID寄存器的命令

unsigned char CMD[] = {0x4A,0x00,0x00,0x00,0x00,0xFF};

unsigned char temp;

temp=SD_Read_Block(CMD,Buffer,16); //read 16 bytes

return(temp);

}

4)读取CSD

CSD(Card-Specific Data)寄存器提供了读写SD卡的一些

信息。其中的一些单元可以由用户重新编程。具体的CSD结构如下:

名称 域 数据宽度 单元类型 CSD划分 CSD结构 CSD_STRUCTURE 2 R

[127:126] 保留 - 6 R [125:120] 数据读取时间1 TAAC 8 R [119:112] 数据在CLK周期内读取时NSAC 8 R [111:104] 间2(NSAC*100)

最大数据传输率 TRAN_SPEED 8 R [103:96] 卡命令集合 CCC 12 R [95:84]

最大读取数据块长 READ_BL_LEN 4 R [83:80] 允许读的部分块 READ_BL_PARTIAL

1 R [79:79] 非线写块 WRITE_BLK_MISALIGN 1 R [78:78] 非线读块

READ_BLK_MISALIGN 1 R [77:77] DSR条件 DSR_IMP 1 R [76:76] 保留 - 2 R

[75:74] 设备容量 C_SIZE 12 R [73:62] 最大读取电流@V min VDD_R_CURR_MIN 3

R [61:59] DD

最大读取电流@V max VDD_R_CURR_MAX 3 R [58:56] DD

最大写电流@V min VDD_W_CURR_MIN 3 R [55:53] DD

最大写电流@V max VDD_W_CURR_MAX 3 R [52:50] DD

设备容量乘子 C_SIZE_MULT 3 R [49:47]

23

擦除单块使能 ERASE_BLK_EN 1 R [46:46] 擦除扇区大小 SECTOR_SIZE 7 R

[45:39] 写保护群大小 WP_GRP_SIZE 7 R [38:32] 写保护群使能 WP_GRP_ENABLE

1 R [31:31] 保留 - 2 R [30:29] 写速度因子 R2W_FACTOR 3 R [28:26] 最大写数据块长度 WRITE_BL_LEN 4 R [25:22] 允许写的部分部 WRITE_BL_PARTIAL 1 R

[21:21] 保留 - 5 R [20:16] 文件系统群 FILE_OFRMAT_GRP 1 R/W [15:15] 拷贝标志 COPY 1 R/W [14:14] 永久写保护 PERM_WRITE_PROTECT 1 R/W [13:13] 暂时写保护 TMP_WRITE_PROTECT 1 R/W [12:12] 文件系统 FIL_FORMAT 2 R/W [11:10]

保留 - 2 R/W [9:8] CRC CRC 7 R/W [7:1] 未用,始终为1 - 1 [0:0] 读取CSD

的时序: 相应的程序例程如下:

读SD卡的CSD寄存器 共16字节 返回0说明读取

成功

unsigned char Read_CSD_SD(unsigned char *Buffer) { //读取CSD寄存器的命令

unsigned char CMD[] = {0x49,0x00,0x00,0x00,0x00,0xFF};

unsigned char temp;

temp=SD_Read_Block(CMD,Buffer,16); //read 16 bytes

return(temp);

}

4) 读取SD卡信息

综合上面对CID与CSD寄存器的读取,可以知道很多关于SD卡的信息,以下程序可以获取这些信息。如下:

//返回

// SD卡的容量,单位为M // sector count and multiplier MB are in

24

u08 == C_SIZE / (2^(9-C_SIZE_MULT)) //获取SD卡的容量

// SD卡的名称 vinf->size_MB = vinf->sector_count >> void

SD_get_volume_info() (9-vinf->sector_multiply); { // get the name of the

card

unsigned char i; Read_CID_SD();

unsigned char c_temp[5]; vinf->name[0] = [3];

VOLUME_INFO_TYPE SD_volume_Info,*vinf; vinf->name[1] =

[4];

vinf=&SD_volume_Info; //Init the pointoer; vinf->name[2] =

[5]; /读取CSD寄存器 vinf->name[3] = [6];

Read_CSD_SD(); vinf->name[4] = [7];

//获取总扇区数 vinf->name[5] = 0x00; //end flag

vinf->sector_count = [6] & 0x03; } 以上程序将信息装载到一个结构体中,这个结构体的定

vinf->sector_count <<= 8; 义如下:

vinf->sector_count += [7]; typedef struct

SD_VOLUME_INFO

vinf->sector_count <<= 2; { //SD/SD Card info

vinf->sector_count += ([8] & 0xc0) >> 6; unsigned

int size_MB; // 获取multiplier unsigned char sector_multiply;

vinf->sector_multiply = [9] & 0x03; unsigned int

sector_count;

vinf->sector_multiply <<= 1; unsigned char name[6];

vinf->sector_multiply += ([10] & 0x80) >> 7; }

VOLUME_INFO_TYPE;

5) 扇区读

扇区读是对SD卡驱动的目的之一。SD卡的每一个扇区中有512

个字节,一次扇区读操作将把某一个扇区内的512个字节全部读

出。过程很简单,先写入命令,在得到相应的回应后,开始数据

读取。扇区读的时序: 扇区读的程序例程:

unsigned char SD_Read_Sector(unsigned long sector,unsigned char

*buffer)

{

unsigned char retry; //命令16

unsigned char CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF};

unsigned char temp;

//地址变换 由逻辑块地址转为字节地址

sector = sector << 9; //sector = sector * 512 }

CMD[1] = ((sector & 0xFF000000) >>24 ); while(temp!=0);

CMD[2] = ((sector & 0x00FF0000) >>16 ); //Read Start Byte form

MMC/SD-Card (FEh/Start Byte)

CMD[3] = ((sector & 0x0000FF00) >>8 ); //Now data is ready,you can

read it out.

//将命令16写入SD卡 while (Read_Byte_MMC() != 0xfe);

retry=0; readPos=0;

do SD_get_data(512,buffer) ; //512字节被读出到buffer中

{ //为了保证写入命令 一共写100次 return 0;

temp=Write_Command_MMC(CMD); }其中SD_get_data函数如下:获取数据到buffer中

retry++; void SD_get_data(unsigned int Bytes,unsigned char *buffer)

if(retry==100) {

{ unsigned int j;

return(READ_BLOCK_ERROR); //block write Error! for (j=0;j

} *buffer++ = Read_Byte_SD(); }

25

6) 扇区写

扇区写是SD卡驱动的另一目的。每次扇区写操作将向SD

本文标签: 数据芯片操作文件控制