【项目笔记】STM32 BootLoader(一) 文件系统

  1. 1. 文件系统的选择
  2. 2. 扇区介绍
    1. 2.1. 启动扇区 Boot Sector
  3. 3. 文件分配表 FAT
  4. 4. 根目录 Root Folder

首先放上 项目主页

简单的介绍一下这个 BootLoader:利用 STM32 提供的 USB FS 接口,并设置为 大容量存储设备(MSC, Mass Storage device Class),并在内存中虚拟出一个 FAT16 的文件系统,以此达到让烧录和读取 Flash 像用 U 盘拷贝文件一样便捷。

系统结构如下图所示,这篇文章先介绍一下最主要的 文件系统 部分:

image-20210216134129762

文件系统的选择

先说一下为什么选择了 FAT16 文件系统。首先,相比起 Linux 中常用的 EXT4,以及其他的一些不那么常见的嵌入式文件系统如 YAFFS、SPIFFS,FAT16 文件系统被广泛应用于各类移动存储设备中,并且由于是微软(巨硬)自家的东西,在 Windows 上得到了良好的支持。

其次,为什么不选择 FAT12 和 FAT32?首先,FAT12 的 FAT(File Allocation Table) 计算过于繁琐;其次,FAT32 有着最小 32 MB 的限制,但 BootLoader 又用不着这么大的空间,并且,FAT 文件系统对于 簇(文件分配空间的最小单元)的数量也有限制:

  • FAT12 : 1 ~ 4,084 个簇
  • FAT16 : 4,085 ~ 65,524 个簇
  • FAT32 : 65,525 ~ 268,435,444 个簇

最终我选用的文件系统参数为:FAT16,每个扇区包含 512 字节,每个簇包含 1 个扇区。

扇区介绍

img

启动扇区 Boot Sector

在没有分区表的设备中,第一个扇区是启动扇区,包含了访问该磁盘分卷所需的基本信息,扇区数据解释如下,注意,除文本和特殊数据外,其余数据均按照小段格式存储:

偏移(字节)长度(字节)典型值说明
0x003EB 3C 90x86 跳转指令,JMP 003E NOP
0x088MSDOS5.0OEM 名称,空格补齐不足的字节
0x0B200 02每扇区字节数,一般为 512 字节
0x0D108每簇扇区数,太大会浪费磁盘空间,太小会导致文件碎片过多
0x0E201 00保留扇区数,包括启动扇区,最小值为 1
0x10102FAT 数目
0x11200 02根目录最大条目数,其中第一个条目作为卷标
0x132总扇区数,要求小于 65536,如果扇区数大于 65536,则此字段为 0,使用偏移为 0x20 的 4 字节字段。
0x151F8存储介质类型,0xF8 表示该介质为硬盘
0x16218 00每个 FAT 的扇区数
0x18220 00每轨道扇区数
0x1A240 00磁头数量
0x1C400 00 00 00隐藏扇区数
0x20400 00 00 004 字节扇区数,当 2 字节的扇区数为 0 时,该字段被使用
0x24180物理硬盘号
0x25100当前磁头号,不被 FAT 文件系统使用
0x26129签名,用于被 Windows NT 系统识别
0x274CE 13 46 30分卷序列号
0x2B11NO NAME卷标,但现在卷标被存储在根目录中
0x368FAT 16磁盘文件系统格式,FAT12 或 FAT16
0x3E448启动代码
0x1FE255 AA启动扇区结束标志

文件分配表 FAT

这部分可谓是 FAT 文件系统的精髓,它以 链表 的形式描述了文件各部分数据在磁盘中分布。

数据区域被分成了固定大小的连续区域,被称为 ,簇是 FAT 文件系统中最小的数据单元。

这里以 FAT16 为例。在 FAT 中,每 16 Bits 的数据代表了一个簇,这 16 个字节标识当前文件的下一部分数据所在的簇号。因此在一个扇区中,包含了 256 个簇的信息。不同取值的含义为:

  • 当前簇未被使用 0x0000
  • 簇被文件使用
  • 坏簇 0xFFF7
  • 文件结尾 0xFFF8 - 0xFFFF

image-20210225181735136

0 号簇为保留,1 号簇为根目录,所以取值依次为 0xFFF80xFFFF。接下来就是数据区域,如在上图中,簇 2,3,4 存放着 FILE1.TXT 的数据,文件的起始簇存放在目录索引中。根据 FAT,我们就可以获取一个文件的完整数据。

根目录 Root Folder

数据区域的 1 号簇描述了文件系统的根目录,

偏移长度描述
0x008文件名,空格补全
0x083拓展名,空格补全
0x0b1文件属性
0x0c1保留
0x0d1创建时间的最小时间分辨率:10ms单位,数值从0到199
0x0e2创建时间
0x102创建日期
0x122最近访问日期
0x142FAT12和FAT16中的EA-Index(OS/2和NT使用),FAT32中第一个簇的两个高字节
0x162最后更改时间;参见偏移0x0e处的描述。
0x182最后更改日期; 参见偏移0x10处的描述。
0x1a2FAT12和FAT16中的第一个簇。FAT32中第一个簇的两个低字节。
0x1c4文件大小

文件的属性取值含义如下:

  • 0x01:只读
  • 0x02:隐藏
  • 0x04:系统文件
  • 0x08:卷标(真正的卷标来自此条目)
  • 0x10:子目录
  • 0x20:文件

具体代码的实现思路为:根据 FAT 文件系统的规定,定义好对应的结构体(注意需使用 __attribute__((__packed__)) 声明,不要进行字节对齐优化),以常量的形式放在内存中,在需要读取的时候使用 memcpy() 复制到 MSC 的缓冲区中,FAT 表采用动态计算的方式生成。

本网站所有文章除特别声明外,均采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。