【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
很早之前,个人对tf卡并不是很重视,觉得它就是一个存储工具而已。后来在移植v3s芯片的时候,才发现很多的soc其实是支持tf卡启动的,大家可以直接基于tf卡开发uboot、dts、kernel和rootfs,很是方便。不仅如此,大部分mcu也是支持tf卡,因为tf卡主要是通过sdio总线访问的,而mcu只要通过sdio总线实现对应的tf卡协议驱动,就可以访问tf卡了,根本不需要经过第三方芯片转一下。
本身sdio是一个基本总线协议,和spi、iic、iis是一样的。
1、电路分析
本身tf卡这里是直接连接到mcu f407上面的,除了vdd电源、gnd之外,就是多了一个c14的电容。所以单单从电路上说,还是很简单的。
2、norflash和tf卡关系
norflash通常都是固定在开发板上,上面有配置文件、字体和一些软件运行时必要的数据文件。而tf卡是可以插拔的,存储空间也更大一点,一般都是用于保存软件运行过程中生成的文件。另外,我们还可以用tf卡对norflash进行配置和升级。不然,只能通过串口之类的外部接口对norflash进行处理,速度也太慢了。
3、fatfs
fatfs本身并不挑存储介质,所以只要做好底层的接口适配,就可以在上层应使用fatfs了。前面,我们说过所有fatfs底层的适配,都是存储在diskio.c文件,主要的接口也是这六个函数,
disk_status
disk_initialize
disk_read
disk_write
disk_ioctl
get_fattime
不仅如此,我们还可以通过这六个函数,知道tf卡的底层是怎么适配的,
SD_Init
SD_ReadMultiBlocks
SD_WaitReadOperation
SD_WriteMultiBlocks
SD_WaitWriteOperation
SD_GetStatus
4、tf卡驱动和协议实现
这部分代码其实基本上可以不用管的。实现代码都是集中在bsp_sdio_sd.c。正如刚才所提示的那样,底层的初始化肯定是从SD_Init开始的。驱动肯定也是分成两部分,一部分是GPIO_InitStructure的初始化,还有一部分是SDIO_InitStructure的初始化。有了这主要的两个部分,相当于sdio协议准备好了。
但是仅仅sdio总线准备好是不够的,还需要用sdio总线实现tf卡的读写协议。这里面最明显的就是各种命令的发送,比如这样,
SD_Error SD_StopTransfer(void)
{
SD_Error errorstatus = SD_OK;
/*!< Send CMD12 STOP_TRANSMISSION */
SDIO_CmdInitStructure.SDIO_Argument = 0x0;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_STOP_TRANSMISSION;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus = CmdResp1Error(SD_CMD_STOP_TRANSMISSION);
return(errorstatus);
}
如代码所示,里面最重要的就是SD_CMD_STOP_TRANSMISSION这个命令,不同的状态下需要发送不同的命令。有兴趣的同学可以读一下相关代码。类似的命令还有,
#define SD_CMD_GO_IDLE_STATE ((uint8_t)0)
#define SD_CMD_SEND_OP_COND ((uint8_t)1)
#define SD_CMD_ALL_SEND_CID ((uint8_t)2)
#define SD_CMD_SET_REL_ADDR ((uint8_t)3) /*!< SDIO_SEND_REL_ADDR for SD Card */
#define SD_CMD_SET_DSR ((uint8_t)4)
#define SD_CMD_SDIO_SEN_OP_COND ((uint8_t)5)
#define SD_CMD_HS_SWITCH ((uint8_t)6)
#define SD_CMD_SEL_DESEL_CARD ((uint8_t)7)
#define SD_CMD_HS_SEND_EXT_CSD ((uint8_t)8)
#define SD_CMD_SEND_CSD ((uint8_t)9)
#define SD_CMD_SEND_CID ((uint8_t)10)
#define SD_CMD_READ_DAT_UNTIL_STOP ((uint8_t)11) /*!< SD Card doesn't support it */
#define SD_CMD_STOP_TRANSMISSION ((uint8_t)12)
#define SD_CMD_SEND_STATUS ((uint8_t)13)
#define SD_CMD_HS_BUSTEST_READ ((uint8_t)14)
#define SD_CMD_GO_INACTIVE_STATE ((uint8_t)15)
#define SD_CMD_SET_BLOCKLEN ((uint8_t)16)
#define SD_CMD_READ_SINGLE_BLOCK ((uint8_t)17)
#define SD_CMD_READ_MULT_BLOCK ((uint8_t)18)
#define SD_CMD_HS_BUSTEST_WRITE ((uint8_t)19)
#define SD_CMD_WRITE_DAT_UNTIL_STOP ((uint8_t)20) /*!< SD Card doesn't support it */
#define SD_CMD_SET_BLOCK_COUNT ((uint8_t)23) /*!< SD Card doesn't support it */
#define SD_CMD_WRITE_SINGLE_BLOCK ((uint8_t)24)
#define SD_CMD_WRITE_MULT_BLOCK ((uint8_t)25)
#define SD_CMD_PROG_CID ((uint8_t)26) /*!< reserved for manufacturers */
#define SD_CMD_PROG_CSD ((uint8_t)27)
#define SD_CMD_SET_WRITE_PROT ((uint8_t)28)
#define SD_CMD_CLR_WRITE_PROT ((uint8_t)29)
#define SD_CMD_SEND_WRITE_PROT ((uint8_t)30)
#define SD_CMD_SD_ERASE_GRP_START ((uint8_t)32) /*!< To set the address of the first write
block to be erased. (For SD card only) */
#define SD_CMD_SD_ERASE_GRP_END ((uint8_t)33) /*!< To set the address of the last write block of the
continuous range to be erased. (For SD card only) */
#define SD_CMD_ERASE_GRP_START ((uint8_t)35) /*!< To set the address of the first write block to be erased.
(For MMC card only spec 3.31) */
#define SD_CMD_ERASE_GRP_END ((uint8_t)36) /*!< To set the address of the last write block of the
continuous range to be erased. (For MMC card only spec 3.31) */
#define SD_CMD_ERASE ((uint8_t)38)
#define SD_CMD_FAST_IO ((uint8_t)39) /*!< SD Card doesn't support it */
#define SD_CMD_GO_IRQ_STATE ((uint8_t)40) /*!< SD Card doesn't support it */
#define SD_CMD_LOCK_UNLOCK ((uint8_t)42)
#define SD_CMD_APP_CMD ((uint8_t)55)
#define SD_CMD_GEN_CMD ((uint8_t)56)
#define SD_CMD_NO_CMD ((uint8_t)64)
5、测试方法
测试方法和norflash一样。上电后,直接加载tf卡。首先判断tf卡是否包含fatfs,没有的话就先格式化,再加载。加载后,先写数据,再读数据,最后卸载fatfs,就是这样一个流程。
6、用usb读卡器进行二次确认
最后,我们就是实际编译、烧录一下,配合串口打印,看看写进去的数据和读出来的数据是否匹配。测试的时候,尽量不要用杂牌子的tf卡,sandisk目前测试下来,是效果最稳定。它既可以做启动卡,还是用作数据存储卡。回到测试,不出意外的话,测试界面是这样的,
另外由于tf卡的特殊性,它本身是可以插拔使用的。所以读写之后,我们可以取下tf卡,用一个usb读卡器插到电脑上,看看是不是真的可以看到对应的文件内容。文件内容用notepad++打开,不然可能是乱码。这也是tf卡区别于norflash的一个验证方法。