前前后后经过了一个多月时间,终于在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与文件系统框架示意图

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卡底层操作则大大的不同,需要重新实现,而且代码量超大。这也是本次驱动实现的最重要的工作内容。

» 文章出处: reille博客—http://velep.com , 如果没有特别声明,文章均为reille博客原创作品
» 郑重声明: 原创作品未经允许不得转载,如需转载请联系reille#qq.com(#换成@)
分享到:

 Leave a Reply

(必须)

(我会替您保密的)(必须)

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.

   
© 2012 velep.com | reille blog | 管理| 粤ICP备15065318号-2| 谷歌地图| 百度地图| Suffusion theme|Sayontan Sinha

无觅相关文章插件,快速提升流量