详解SD协议与FatFs文件系统中的Block、Sector的差异,与FatFs中底层驱动disk_ioctl的编写及思路

1. SD2.0协议中的sector与block

点我下载SD2.0协议

git clone https://github.com/TTowFive/SD2.0-protocol-pdf

在SD协议中,我们可以看到这样的原话:

block size

大意是讲,在高容量卡(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

大意为: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 size

大意为: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

猜你喜欢

转载自blog.csdn.net/qq_26106317/article/details/108195898