
前前后后经过了一个多月时间,终于在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驱动移植(上)


