1. SD2.0协议中的sector与block
git clone https://github.com/TTowFive/SD2.0-protocol-pdf
在SD协议中,我们可以看到这样的原话:
大意是讲,在高容量卡(SDHC)中,卡的block size是512字节(bytes),这里指的是data block size,也是大容量卡最小的数据操作单位,那么问题来了,还有一个比较重要的参数是sector size,在2.0以下的卡中,sector size被定义在CSD Version 1.0中,但在CSD Version 2.0中sector size固定为0x7F,并且是没有任何意义的,从SD2.0协议中的CSD Version 2.0可以看到:
大意为:sector size固定为0x7F,memory boundary(存储边界)由AU size(Allocation Unit size 可以叫做物理边界)指定,所以对于2.0及以上的卡,是无法从CSD中获取sector size的。
SD协议中AU size
那么问题又来了,这个所谓的AU size又该如何获知呢?
首先我们得知道这个AU size代表什么,在SD2.0协议4.11中可以看到:
大意为:AU是卡的物理边界,这个值可以由一个或多个data block(512 bytes)组成。
- Maximum AU size(最大物理边界)一定程度上定义了memory capacity(卡容量)的大小范围。
- AU size 同时也可以被认为是主机正常操作SD卡的最小单位的保证。(那是不是可以认为最小的AU size == data block size?)
- AU size 也被用来计算卡的擦除时间(不用了解)。
在SD2.0协议4.10.2中,我们可以看到如下定义:

图中红圈表示的正是Maximum AU size,继续往下看:
我们可以从表格中了解到,对于大容量卡(SDHC)且SD协议来说,
Maximum AU size( 最大 ) 一定是 4MB( 4096kb / 512bytes = 8192 data blocks,记住这个值 )
2. FatFs中的sector与block
大家如果使用一些存储设备(例如SPI FLASH 或 SD卡等)的话,可能大多数人会考虑使用FatFs进行项目开发,那么问题就由此衍生出来了,一部分细心的人可能会提出一个问题:如果使用SD卡,那么在SD2.0协议中明明说block为512字节(bytes),那为什么在FatFs中,sector size才是512字节呢?这不是错了吗?
其实文件系统的sector和block 与 SD协议的sector和block含义正好相反。在SD协议中,大小包含关系是:block ⊆ sector。而在FatFs中相反:sector ⊆ blockr,所以使用FatFs在底层驱动编写和移植时,这个关系要清楚。不过也有相当一部分人是“代码搬运工”,只管用,却不研究原理,属实不妥。
由此可知,在disk_ioctl中GET_SECTOR_SIZE和GET_BLOCK_SIZE,可以有以下关系:
最大:8192 data blocks(SD) == 8192 sector(FatFs) == 1 block(FatFs)
或
最小:1 data blocks(SD) == 1 sector(FatFs) == 1 block(FatFs)
有这样的关系就可以开始基于SD卡移植FatFs了。
3. FatFs中底层驱动disk_ioctl的编写及思路
在FatFs的官网,我们可以看到disk_ioctl的cmd参数解释:
这几个参数是系统使用的,除了CTRL_TRIM,其他必须实现,且最后加一条命令CTRL_SYNC。
我们用C代码演示:
/*
* 假设我们已经从SD卡中的CSD中获取并计算得到了当前SD卡的块(blocks)信息,
* 由FatFs与SD协议的关系,定义变量:sect_cnt(FatFs),这个值等于blocks(SD)数量
*/
#define SD 0
#define SPIFLASH 1
extern u32 sect_cnt; //导入sect_cnt
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
) {
switch (pdrv) {
case SD :
switch ( cmd ) {
//fatfs内核使用cmd调用
case GET_SECTOR_COUNT: //sector count, 传入sect_cnt
*(DWORD*)buff = sect_cnt;
return RES_OK;
case GET_SECTOR_SIZE: //sector size, 传入block size(SD),单位bytes
*(DWORD*)buff = 512;
return RES_OK;
case GET_BLOCK_SIZE: //block size, 由上文可得,对于SD2.0卡最大8192,最小 1
*(DWORD*)buff = 1; //单位为 sector(FatFs)
return RES_OK;
case CTRL_SYNC: //同步命令,貌似FatFs内核用来判断写操作是否完成
return RES_OK;
}
default:
printf( "No device %d.\n", pdrv );
break;
}
return RES_PARERR; //默认返回参数错误
}
如果您看到了这里,还请点个赞支持一下吧。
http://elm-chan.org/fsw/ff/doc/dioctl.html
SD2.0 protocol