前前后后经过了一个多月时间,终于在eCos中实现了STM32的SD卡驱动。相比而言,SD卡驱动不仅代码量大,还涉及eCos块驱动(disk驱动)体系、SD/MMC存储卡、FAT文件系统、块缓存、文件操作等多方面的知识点。
从本节开始,以eCos STM32 SD卡驱动为切入点,一起来了解eCos块设备驱动、文件系统、文件操作等知识点。本节主要介绍eCos disk设备驱动体系结构。
SD卡驱动源码包
因为SD卡驱动涉及面较多,将分多个章节连载介绍,所以如果你着急的话,可以点击这个链接下载驱动源码自行研究:http://52ecos.net/thread-600-1-1.html
eCos块设备驱动
在eCos中,注册一个块设备必须使用宏BLOCK_DEVTAB_ENTRY进行定义,其具体定义如下(详见:devtab.h文件):
#define BLOCK_DEVTAB_ENTRY(_l,_name,_dep_name,_handlers,_init,_lookup,_priv) \ cyg_devtab_entry_t _l CYG_HAL_TABLE_ENTRY(devtab) = { \ _name, \ _dep_name, \ _handlers, \ _init, \ _lookup, \ _priv, \ CYG_DEVTAB_STATUS_BLOCK \ };
与块设备相对应的是字符设备,使用宏CHAR_DEVTAB_ENTRY进行注册。我们知道,在linux中,还有一类设备是网络设备。不难发现,eCos中没有规划出此类设备,而且eCos块设备驱动体系相对linux而言相当简洁但保持完整。
eCos disk驱动
在eCos中,有两类典型的块设备:flash和disk。flash指NAND FLASH、NOR FLASH、SPI FLASH等,而disk指硬盘、SD/MMC卡、CF卡等。所以,SD/MMC卡驱动应归属到disk驱动体系中。
与其它驱动一样,eCos disk驱动分为设备驱动层和一般IO抽象层。前者对应devs/disk目录,后者对应io/disk目录。在这里简单分别介绍下。
eCos Disk驱动与其它中间件组成的系统结构如下图所示。
eCos disk IO层
如上所述,eCos disk IO抽象一般的disk设备。向上提供了bread、bwrite等API接口实现,向下提供了统一的数据结构体和接口,大大简化了设备驱动层的设计。
块设备API接口实现
位于disk.c源文件中,它向上层提供了read/write等方法,如下代码所示:
BLOCK_DEVIO_TABLE(cyg_io_disk_devio, disk_bwrite, disk_bread, disk_select, disk_get_config, disk_set_config );
在调试SD卡驱动的时候,发现disk_bwrite()和disk_bread()两函数中存在bug,虽不影响正常的read/write操作,但一旦发生还是致命性的。这些bug将会放到后面章节进行讨论。
重要数据结构体
disk IO层为disk设备驱动层提供了一些重要的数据结构体来描述disk,并提供了相关宏来定义这些结构体对象。它们分别描述如下:
1. struct cyg_disk_identify_t,描述disk硬件信息,如disk序列号、固件版本、CHS信息、扇区总数等,其定义如下:
struct cyg_disk_identify_t { char serial[20+1]; // serial number char firmware_rev[8+1]; // firmware revision char model_num[40+1]; // model number cyg_uint32 cylinders_num; // number of cylinders (CHS) cyg_uint32 heads_num; // number of heads (CHS) cyg_uint32 sectors_num; // number of sectors per track (CHS) cyg_uint32 lba_sectors_num; // total number of sectors in LBA mode cyg_uint32 phys_block_size; // physical block size in sectors cyg_uint32 max_transfer; // Maximum transfer size in bytes };
这里有一点需要了解,disk IO层不仅抽象SD卡等设备,还抽象了硬盘等设备,因此在结构体struct cyg_disk_identify_t中,用CHS(Cylinder(柱面),Head(磁头),Sector(扇区))格式来描述disk扇区信息。但我们知道,对于SD卡,它只有sector,没有所谓的Cylinder,Head等概念,这就涉及到LBA(Logic Block Address)与CHS的转换。
如果没有了解过CHS 、LBA的知识,也没有关系,暂时先把这些放在一边,因为对于SD卡而言,这些信息不太重要。
2. struct cyg_disk_partition_t,描述disk MBR中记录的分区信息,如分区类型、起始扇区编号、终止扇区编号、扇区大小等。当格式化SD卡时,这些信息会自动保存到MBR所在的扇区中。
3. struct cyg_disk_info_t,描述了disk信息,包含struct cyg_disk_identify_t和struct cyg_disk_partition_t两个结构体描述的信息;
以上3个结构体定义在diskio.h中,它们共同描述了disk的硬件信息。
4. struct disk_controller,disk控制器,对于SD卡而言,可以不用太关注。
5. struct disk_channel,定义如下:
// --------------------------------------------------------------------------- // Private data which describes this channel struct disk_channel { disk_funs *funs; disk_callbacks_t *callbacks; void *dev_priv; // device private data disk_controller *controller; // pointer to controller cyg_disk_info_t *info; // disk info cyg_disk_partition_t *partition; // partition data struct cyg_devtab_entry *pdevs_dev; // partition devs devtab ents disk_channel *pdevs_chan; // partition devs disk chans cyg_bool mbr_support; // true if disk has MBR cyg_bool valid; // true if device valid cyg_bool init; // true if initialized cyg_ucount16 mounts; // count of number of mounts };
这是一个非常重要的数据结构体,描述disk通道。controller和channel共同构成了disk的拓扑关系。这就好比一台电脑,它可能连接了多个不同参数的硬盘,也可能只连接了一个硬盘。其中,电脑好比是controller,每个硬盘则是channel。
在eCos的驱动体系中,像这种channel的概念运用的非常多,典型的就是serial的驱动。深入理解这个含义,对于理解eCos的驱动体系特征是非常重要的。
6. struct disk_funs,描述disk设备驱动层接口,提供了read/write等接口原型。
7. disk_callbacks_t,为disk设备驱动层提供回调disk IO层函数的功能。
eCos disk设备驱动层
该层是具体disk设备的驱动实现。在eCos中, 提供了SPI接口的一般SD/MMC卡驱动实现,对应devs/disk/generic/mmc下面的mmc_spi.c源文件。也就是说,eCos本身支持SPI接口SD/MMC卡。先来大概分析下mmc_spi.c。
mmc_spi.c主要由3部分组成:设备入口定义、设备接口实现和SD/MMC卡底层操作。
设备入口定义
这部分定义了设备接口、controller、channel、设备入口等对象以及设备私有数据等,代码如下:
// ---------------------------------------------------------------------------- // And finally the data structures that define this disk. Some of this // should be moved into an exported header file so that applications can // define additional disks. // // It is not obvious why there are quite so many structures. Apart // from the devtab entries there are no tables involved, so there is // no need to keep everything the same size. The cyg_disk_info_t could // be the common part of a h/w info_t. The channel structure is // redundant and its fields could be merged into the cyg_disk_info_t // structure. That would leave a devtab entry, a disk info structure // (h/w specific but with a common base), and a disk controller // structure (ditto). DISK_FUNS(cyg_mmc_spi_disk_funs, mmc_spi_disk_read, mmc_spi_disk_write, mmc_spi_disk_get_config, mmc_spi_disk_set_config ); static cyg_mmc_spi_disk_info_t cyg_mmc_spi_disk0_hwinfo = { .mmc_spi_dev = &cyg_spi_mmc_dev0, #ifdef MMC_SPI_BACKGROUND_WRITES .mmc_writing = 0, #endif .mmc_connected = 0 }; // No h/w controller structure is needed, but the address of the // second argument is taken anyway. DISK_CONTROLLER(cyg_mmc_spi_disk_controller_0, cyg_mmc_spi_disk0_hwinfo); DISK_CHANNEL(cyg_mmc_spi_disk0_channel, cyg_mmc_spi_disk_funs, cyg_mmc_spi_disk0_hwinfo, cyg_mmc_spi_disk_controller_0, true, /* MBR support */ 1 /* Number of partitions supported */ ); BLOCK_DEVTAB_ENTRY(cyg_mmc_spi_disk0_devtab_entry, CYGDAT_DEVS_DISK_MMC_SPI_DISK0_NAME, 0, &cyg_io_disk_devio, &mmc_spi_disk_init, &mmc_spi_disk_lookup, &cyg_mmc_spi_disk0_channel);
设备接口实现
这部分对应mmc_spi_disk_init()、mmc_spi_disk_lookup()、mmc_spi_disk_read()、mmc_spi_disk_write()、mmc_spi_disk_get_config()、mmc_spi_disk_set_config()等函数。其中:
- mmc_spi_disk_init(),实现设备驱动的初始化;
- mmc_spi_disk_lookup(),实现SD/MMC卡的mount;
SD/MMC卡底层操作
这部分主要实现SD/MMC卡初始化、卡识别、卡命令发送和响应接收、卡数据读写等操作。对于SPI接口的SD/MMC卡而言,这些底层操作都是通过SPI传输协议来实现,因此这部分实现相对较简单。
本次实现的SD/MMC卡驱动采用SDIO接口,设备入口定义和设备接口实现这两部分可以直接使用mmc_spi.c中的实现,但SD/MMC卡底层操作则大大的不同,需要重新实现,而且代码量超大。这也是本次驱动实现的最重要的工作内容。
推荐阅读相关文章:
- stm32移植ecos #34,ecos sd driver,SD卡驱动(4)
- stm32移植ecos #32,ecos sd driver,SD卡驱动(2)
- stm32移植ecos #33,ecos sd driver,SD卡驱动(3)
- stm32移植ecos #30,ecos i2s driver,音频驱动(下)
- stm32移植ecos #29,ecos i2s driver,音频驱动(中)
- stm32移植ecos #28,ecos i2s driver,音频驱动(上)
- stm32移植ecos #27,串行SPI flash驱动移植(下)
- stm32移植ecos #26,串行SPI flash驱动移植(上)