你的位置:
首页
>
IT圈
>
SD卡读写开发文档
2024年6月15日发(作者:出博赡)
文档从互联网中收集,已重新修正排版,word格式支持编辑,如有帮助欢迎下载支持。
SD卡读写关键是对SD的初始化、块扇区的读写、以及SD卡文件结构的掌握,
初始化SD首先发送 0x40 0x 00 0x00 0x00 0x00 0x59 应答 0x01 进入空闲模式
在发送 0x41 0x 00 0x00 0x00 0x00 0x59 应答 0x00 激活SD卡
使用WinHex分析SD卡可以得到第一数据区即根目录区,在第520区,每扇区512字节,
等等,分析后得结果用于,读数据的验证。
本SD卡为1G的金士顿卡,扇区宽度为512字节,根据WinHex和读SD卡的结论得出解
读,可以得出表一:
读本SD卡的第0块物理扇区512字节, 即常说的引导扇区。
MBR(主引导的区)的长度为446字节(0x00~0x1BD),以后每16个字节代表一个分区,
共四个,该卡仅一个分区所以后面三个都是空的,这16个就是分区表:
地址
1BE
1BF
1C0
1C2
1C3
1C4
1C6
1CA
长度
1
1
2
1
1
2
4
4
内容
00
01
01 00
06
29
7F E0
00 00 00 20
003C 7B E0
详解
激活则为 00 ,否则80
分区起始的磁头号
起始扇区和柱面号,低6位时扇区号,?????
分区类型,0B代表FAT32, 06代表FAT16
分区结束的磁头号
分区结束的扇区和柱面号
地址20由该地址读到内容就是逻辑地址的0扇区
分区的总扇区数。493979
由上述分析得出本SD卡的逻辑地址的0扇区应该在隐藏扇区中,块的扇区地址为
0x00000020,读扇区得到的内容:如下图所示:
具体分析如下图所示 :
名称
BS_jmpBoot
OEMName
每扇区字节数
每簇的扇区数
保留扇区数
FAT表份数
根目录项数
总扇区数
TotSec16
介质种类
FATSz16
SecPerTrk
磁头数
HiddSec
TotSec32
DrvNum
保留
偏
移
0
3
0B
0D
0E
10
11
13
15
16
18
1A
1C
20
24
25
长
度
3
8
2
1
2
1
2
2
1
2
2
2
4
4
1
1
内容
BUFF[0..2]
BUFF[3..A]
BUFF[B..C]
BUFF[D]
04 00
02
00 02
00 00
F8
F2 00
3F 00
0x00000020
详细
一般为EB XX 90 或 E9 xx xx
仅一个名字。无所谓
即0x0200 =512 即每个扇区有512个字节
即每个簇有(64个)0x40扇区,也就是每个
簇有64*512=32k
从第一扇区开始被保留的扇区数为04
一般都是两个FAT表。两者宽度一样
一般FAT16为512即0x0200
当容量大于1M时,总扇区数就放在TotSec32
处,此处放置0
表示固定存储介质,F0表示移动存储介质
0X00F2表示一个分区占242个扇区共两分区
表示每磁道的扇区数。这里不是硬盘,无意义
无意义
FAT表前隐藏的扇区数32
0x003C7BE0 该卡的总扇区数,也即该卡的最大容量为
0x003C7BE0*512=1981936M
00
00
一般硬盘为80 软盘为00
共NT使用,此处必须为0
1word格式支持编辑,如有帮助欢迎下载支持。
文档从互联网中收集,已重新修正排版,word格式支持编辑,如有帮助欢迎下载支持。
BootSig
VolID
VolLab
FilesysType
可执行代码
1分区头
2分区
签名
26
27
2B
36
3E
1
4
11
8
29
55 AA
扩展引导标记,表示后面的域可用
内容随便,仅一ID
卷标11个字节,此处NO MAME
即文件类型,此处为FAT16
…….引导分区字节…..
无
结构同上
结束标志
448
1BE -
1BF -
1C0
1C2
1C3
1C4
1C6
-
-
-
-
-
1CA -
1CE -
1FE 2
分析得出主目录所在扇区地址:
主引导区数(1个) + 保留扇区数(0x04个) + 隐藏数(0x20个)+2个 FAT表宽度(0Xf2*2)
=521,即从第521个扇区(扇区地址为520)开始的32个扇区中存放根目录。
读本SD卡的根目录的第一个扇区得出如图数据:
本卡卷标名为UJNX,可见第一个32字节的文件为该根目录,但是他以文件夹的形式呈现,
并且大小Size为0,在大多数正常情况下我们可以认为无后缀名的,大小为零的文件为文件
夹(我知道这个并不科学,谁有好的建议?)。可以看出32个扇区的根目录最多可以存储
512个目录文件。文件就简单了,直接根据FAT表簇的地址读数据就是了。
读FAT表:
在FAT表中每两个字节的数据对应唯一的一个簇地址,每个簇有64个扇区,例如在第一个(地
址为0x24)FAT表的第一个扇区中的数据如下:
读文件
1、根据32字节的目录获取文件名、类型、大小、起始簇的地址
2、根据簇的地址高位和低位计算出簇的位置,并与对应的计算出该簇的起始扇区地址
簇的起始扇区地址=根目录起始扇区+目录扇区宽度+(簇地址-2)*每个簇的扇区宽度。
3、读下一个簇的地址,根据上个簇对应的FAT表中的两个字节,计算出下个簇所在的簇地
址,然后执行1步骤再读出64扇区个连续的数据,直到簇的地址为0xFFFF为止表示文件
结束。
读文件夹
1、 根据目录获取文件名,并跟踪簇地址,到所在第一个扇区,读该扇区下图视
可见该扇区的内容是一张目录表,2E标示目录的级别,其簇地址应该代表上级目录地址,
根据每32字节为一文件标示,E5标示已删除的文件,同样读出文件的簇地址,计算所在
64个扇区地址,并读出数据,再读取对应的FAT表中的下个簇的地址,如此反复直到FAT
表中数据为0xFF。
读文件时,有时候SD卡不能初始化,但反复格式化FAT32,和FAT后会很好用,原因不明。
写文件:
1、首先根据新建的文件,获得其所在目录的索引ID,并的到其size1大小(字节),起始簇
Start_clus,起始扇区Start_sctor,
2word格式支持编辑,如有帮助欢迎下载支持。
文档从互联网中收集,已重新修正排版,word格式支持编辑,如有帮助欢迎下载支持。
2、处理FAT中簇的文件链表
根据新建文件的大小size2(字节),计算总文件大小File_Size= size1+ size2;
源文件占用的簇数:clus_cnt= size1/(512*64)+1
写入后的占用总簇数:File_Clus=File_Size/(512*64)
那么最后一个簇的ID为:last_clus=Start_clus+ clus_cnt-1
For(i= 0;i< File_Clus - clus_cnt;i++) {Writeclusid(last_clus,getnextclus());
last_clus= getnextclus();
}
Writeclusid(last_clus,0xffff);
3、 写扇区内容
源文件所占的扇区数:sctor_cnt= size1/512+1;
文件所占的总的扇区数:File_sctor=File_Size/512
最后一个扇区地址:Last_sctor=Start_sctor+ sctor_cnt-1
读出最后一个扇区数据到BUFFER中ReadBlock(Last_sctor);
写最后一个扇区For(i= size1%512;i<512;i++)BUFFER[i]=dat[i-(size1%512) ]
Last_sctor= Last_sctor+1;
在根据簇的地址写剩余的扇区。………….
………………………………………..
…………………………………………………
4、更改文件目录的SIZE项
根据索引ID,读出其所在的根目录扇区。
更改ID的32字节中最后4个为File_Size&0xff、(File_Size&0Xff00)>>8、
(File_Size&0Xff0000)>>16、File_Size >>24.
假设得到文件在接结束时的,簇结束地址writesdclus_addr,以及文件在簇内的扇区偏移
writesdsctor_lab,以及文件内容在扇区内的字节偏移writesdbety_lab,
假设目录项ID,所在扇区地址writesddir_sctor_lab,以及字节数据在该扇区内的偏移地址
writesdA4、writesdA3、writesdA2、writesdA1。
再写文件步骤:
1、计算该文件的所占的总簇数。修改FAT簇的练表。
for(i=0;i WriteFAT(ClusID,0xffff);
ClusNext=GetNextFAT();
WriteFAT(ClusID,ClusNext);
ClusID=ClusNext;
}
WriteFAT(ClusID, 0xffff);
2、写扇区数据。
3、更改SIZE项
3word格式支持编辑,如有帮助欢迎下载支持。
2024年6月15日发(作者:出博赡)
文档从互联网中收集,已重新修正排版,word格式支持编辑,如有帮助欢迎下载支持。
SD卡读写关键是对SD的初始化、块扇区的读写、以及SD卡文件结构的掌握,
初始化SD首先发送 0x40 0x 00 0x00 0x00 0x00 0x59 应答 0x01 进入空闲模式
在发送 0x41 0x 00 0x00 0x00 0x00 0x59 应答 0x00 激活SD卡
使用WinHex分析SD卡可以得到第一数据区即根目录区,在第520区,每扇区512字节,
等等,分析后得结果用于,读数据的验证。
本SD卡为1G的金士顿卡,扇区宽度为512字节,根据WinHex和读SD卡的结论得出解
读,可以得出表一:
读本SD卡的第0块物理扇区512字节, 即常说的引导扇区。
MBR(主引导的区)的长度为446字节(0x00~0x1BD),以后每16个字节代表一个分区,
共四个,该卡仅一个分区所以后面三个都是空的,这16个就是分区表:
地址
1BE
1BF
1C0
1C2
1C3
1C4
1C6
1CA
长度
1
1
2
1
1
2
4
4
内容
00
01
01 00
06
29
7F E0
00 00 00 20
003C 7B E0
详解
激活则为 00 ,否则80
分区起始的磁头号
起始扇区和柱面号,低6位时扇区号,?????
分区类型,0B代表FAT32, 06代表FAT16
分区结束的磁头号
分区结束的扇区和柱面号
地址20由该地址读到内容就是逻辑地址的0扇区
分区的总扇区数。493979
由上述分析得出本SD卡的逻辑地址的0扇区应该在隐藏扇区中,块的扇区地址为
0x00000020,读扇区得到的内容:如下图所示:
具体分析如下图所示 :
名称
BS_jmpBoot
OEMName
每扇区字节数
每簇的扇区数
保留扇区数
FAT表份数
根目录项数
总扇区数
TotSec16
介质种类
FATSz16
SecPerTrk
磁头数
HiddSec
TotSec32
DrvNum
保留
偏
移
0
3
0B
0D
0E
10
11
13
15
16
18
1A
1C
20
24
25
长
度
3
8
2
1
2
1
2
2
1
2
2
2
4
4
1
1
内容
BUFF[0..2]
BUFF[3..A]
BUFF[B..C]
BUFF[D]
04 00
02
00 02
00 00
F8
F2 00
3F 00
0x00000020
详细
一般为EB XX 90 或 E9 xx xx
仅一个名字。无所谓
即0x0200 =512 即每个扇区有512个字节
即每个簇有(64个)0x40扇区,也就是每个
簇有64*512=32k
从第一扇区开始被保留的扇区数为04
一般都是两个FAT表。两者宽度一样
一般FAT16为512即0x0200
当容量大于1M时,总扇区数就放在TotSec32
处,此处放置0
表示固定存储介质,F0表示移动存储介质
0X00F2表示一个分区占242个扇区共两分区
表示每磁道的扇区数。这里不是硬盘,无意义
无意义
FAT表前隐藏的扇区数32
0x003C7BE0 该卡的总扇区数,也即该卡的最大容量为
0x003C7BE0*512=1981936M
00
00
一般硬盘为80 软盘为00
共NT使用,此处必须为0
1word格式支持编辑,如有帮助欢迎下载支持。
文档从互联网中收集,已重新修正排版,word格式支持编辑,如有帮助欢迎下载支持。
BootSig
VolID
VolLab
FilesysType
可执行代码
1分区头
2分区
签名
26
27
2B
36
3E
1
4
11
8
29
55 AA
扩展引导标记,表示后面的域可用
内容随便,仅一ID
卷标11个字节,此处NO MAME
即文件类型,此处为FAT16
…….引导分区字节…..
无
结构同上
结束标志
448
1BE -
1BF -
1C0
1C2
1C3
1C4
1C6
-
-
-
-
-
1CA -
1CE -
1FE 2
分析得出主目录所在扇区地址:
主引导区数(1个) + 保留扇区数(0x04个) + 隐藏数(0x20个)+2个 FAT表宽度(0Xf2*2)
=521,即从第521个扇区(扇区地址为520)开始的32个扇区中存放根目录。
读本SD卡的根目录的第一个扇区得出如图数据:
本卡卷标名为UJNX,可见第一个32字节的文件为该根目录,但是他以文件夹的形式呈现,
并且大小Size为0,在大多数正常情况下我们可以认为无后缀名的,大小为零的文件为文件
夹(我知道这个并不科学,谁有好的建议?)。可以看出32个扇区的根目录最多可以存储
512个目录文件。文件就简单了,直接根据FAT表簇的地址读数据就是了。
读FAT表:
在FAT表中每两个字节的数据对应唯一的一个簇地址,每个簇有64个扇区,例如在第一个(地
址为0x24)FAT表的第一个扇区中的数据如下:
读文件
1、根据32字节的目录获取文件名、类型、大小、起始簇的地址
2、根据簇的地址高位和低位计算出簇的位置,并与对应的计算出该簇的起始扇区地址
簇的起始扇区地址=根目录起始扇区+目录扇区宽度+(簇地址-2)*每个簇的扇区宽度。
3、读下一个簇的地址,根据上个簇对应的FAT表中的两个字节,计算出下个簇所在的簇地
址,然后执行1步骤再读出64扇区个连续的数据,直到簇的地址为0xFFFF为止表示文件
结束。
读文件夹
1、 根据目录获取文件名,并跟踪簇地址,到所在第一个扇区,读该扇区下图视
可见该扇区的内容是一张目录表,2E标示目录的级别,其簇地址应该代表上级目录地址,
根据每32字节为一文件标示,E5标示已删除的文件,同样读出文件的簇地址,计算所在
64个扇区地址,并读出数据,再读取对应的FAT表中的下个簇的地址,如此反复直到FAT
表中数据为0xFF。
读文件时,有时候SD卡不能初始化,但反复格式化FAT32,和FAT后会很好用,原因不明。
写文件:
1、首先根据新建的文件,获得其所在目录的索引ID,并的到其size1大小(字节),起始簇
Start_clus,起始扇区Start_sctor,
2word格式支持编辑,如有帮助欢迎下载支持。
文档从互联网中收集,已重新修正排版,word格式支持编辑,如有帮助欢迎下载支持。
2、处理FAT中簇的文件链表
根据新建文件的大小size2(字节),计算总文件大小File_Size= size1+ size2;
源文件占用的簇数:clus_cnt= size1/(512*64)+1
写入后的占用总簇数:File_Clus=File_Size/(512*64)
那么最后一个簇的ID为:last_clus=Start_clus+ clus_cnt-1
For(i= 0;i< File_Clus - clus_cnt;i++) {Writeclusid(last_clus,getnextclus());
last_clus= getnextclus();
}
Writeclusid(last_clus,0xffff);
3、 写扇区内容
源文件所占的扇区数:sctor_cnt= size1/512+1;
文件所占的总的扇区数:File_sctor=File_Size/512
最后一个扇区地址:Last_sctor=Start_sctor+ sctor_cnt-1
读出最后一个扇区数据到BUFFER中ReadBlock(Last_sctor);
写最后一个扇区For(i= size1%512;i<512;i++)BUFFER[i]=dat[i-(size1%512) ]
Last_sctor= Last_sctor+1;
在根据簇的地址写剩余的扇区。………….
………………………………………..
…………………………………………………
4、更改文件目录的SIZE项
根据索引ID,读出其所在的根目录扇区。
更改ID的32字节中最后4个为File_Size&0xff、(File_Size&0Xff00)>>8、
(File_Size&0Xff0000)>>16、File_Size >>24.
假设得到文件在接结束时的,簇结束地址writesdclus_addr,以及文件在簇内的扇区偏移
writesdsctor_lab,以及文件内容在扇区内的字节偏移writesdbety_lab,
假设目录项ID,所在扇区地址writesddir_sctor_lab,以及字节数据在该扇区内的偏移地址
writesdA4、writesdA3、writesdA2、writesdA1。
再写文件步骤:
1、计算该文件的所占的总簇数。修改FAT簇的练表。
for(i=0;i WriteFAT(ClusID,0xffff);
ClusNext=GetNextFAT();
WriteFAT(ClusID,ClusNext);
ClusID=ClusNext;
}
WriteFAT(ClusID, 0xffff);
2、写扇区数据。
3、更改SIZE项
3word格式支持编辑,如有帮助欢迎下载支持。