上一节,介绍了eCos STM32 SD/MMC Card driver前面2个步骤的调试情况,SD卡可以mount成功并能成功打开目录和读取SD卡目录文件列表信息。但是在SD卡中创建新目录和文件时则会失败,严重的是还破坏了SD卡中文件系统数据,导致SD卡目录和文件数据的丢失。

这是怎么一回事呢?本节除了解决这个问题外,还修复了eCos Disk IO层和eCos FAT文件系统中存在的bug,以及更新了读取SD卡存储信息的相关代码。

读取SD卡信息

eCos带的fatfs测试程序fatfs1.c中,有读取SD卡信息(SD卡总大小、可用空间、块大小等信息)相关代码段,但是这段代码使用的一些宏和定义是旧的,所以是不可用的。具体可参考:http://www.sourceware.org/ml/ecos-discuss/2012-07/msg00006.html

根据eCos图形配置工具可知,读取SD卡信息对应的配置项是:CYGSEM_FILEIO_INFO_DISK_USAGE而不是CYGSEM_FILEIO_BLOCK_USAGE,如下图选中的配置项所示:

image

通过搜索CYGSEM_FILEIO_INFO_DISK_USAGE可知,读取SD卡信息的KEY是FS_INFO_DISK_USAGE而非FS_INFO_BLOCK_USAGE,所用的结构体是struct cyg_fs_disk_usage而非struct cyg_fs_block_usage。

修改fatfs.c中fatfs_getinfo()函数,如下代码所示:

#if defined(/*CYGSEM_FILEIO_BLOCK_USAGE*/CYGSEM_FILEIO_INFO_DISK_USAGE)// Modify by reille 2013.07.28
        case /*FS_INFO_BLOCK_USAGE*/FS_INFO_DISK_USAGE: {// Modify by reille 2013.07.28
	  cyg_uint32 total_clusters;
	  cyg_uint32 free_clusters;
      // Modify by reille 2013.07.28
//	  struct cyg_fs_block_usage *usage = (struct cyg_fs_block_usage *) buf;
      struct cyg_fs_disk_usage *usage = (struct cyg_fs_disk_usage *) buf;
	  fatfs_disk_t  *disk   = (fatfs_disk_t *) mte->data;

	  err = fatfs_get_disk_usage(disk, &total_clusters, &free_clusters);
	  if (err)
	    return err;
	  usage->total_blocks = total_clusters;
	  usage->free_blocks = free_clusters;
	  usage->block_size = disk->cluster_size;
	  break;
	}
#endif

同样,fatfs1.c中相关代码也需要修改过来,在此就不多说了。

eCos Disk IO层的bug

在调试SD卡驱动时发现eCos Disk IO层存在bug。该bug正常情况是不会触发的,但一旦SD卡驱动返回出错时则会触发,并导致整个eCos Disk的崩溃。该bug主要存在于disk_bread()和disk_bwrite()两函数中。

以disk_bread()函数来说明。

disk_bread()函数开头会去检测SD卡对应的controller是否busy?如果busy则一直等待,否则一旦取得执行权,立即置busy信号,如下代码:

    cyg_drv_mutex_lock( &ctlr->lock );

    while( ctlr->busy )
        cyg_drv_cond_wait( &ctlr->queue );

    if (info->connected && chan->valid)
    {
        ctlr->busy = true;

        if (NULL != chan->partition)
        {

再往下面看,调用SD卡驱动read()方法去读取SD block数据:

            cyg_drv_dsr_lock();

            res = (funs->read)(chan, (void*)bbuf, tfr, pos);

            if( res == -EWOULDBLOCK )
            {
                // If the driver replys EWOULDBLOCK, then the transfer is
                // being handled asynchronously and when it is finished it
                // will call disk_transfer_done(). This will wake us up here
                // to continue.

                while( ctlr->result == -EWOULDBLOCK )
                    cyg_drv_cond_wait( &ctlr->async );

                res = ctlr->result;
            }

            cyg_drv_dsr_unlock();

            if (ENOERR != res) {
                goto done;
            }

是否注意:如果res返回出错,即res值不等于ENOERR时,则直接goto done了,而在这里呢,没有清除SD卡controller的busy标志。这种情况下,一旦出现SD卡底层驱动read返回错误情况,则下次read时会一直等待busy标志,导致死等。disk_bwrite()函数亦是如此。

这就是eCos Disk IO层存在的bug。解决方法不难,当res返回出错且goto之前清除busy标志。

SD卡创建目录和文件失败问题

因为SD卡可以mount成功,可以读取SD卡信息、目录和文件列表信息,最重要的是用WinHex工具(下载地址:http://download.csdn.net/detail/rill_zhen/5776013)查看写block数据是正确的,所以一直把这个问题定位在eCos fatfs中,没有想过会是SD卡驱动问题的原因。所以这个问题排查了很久。

后面添加了很多打印信息加以分析,FAT信息、FAT分配表、FAT根目录、读写block数据都打印出来,并且根据FAT文件系统格式分析当创建新文件时,所要更新哪些分配表、根目录数据、以及大概写入的数据块等。

这样分析后发现,umount之前,所有的数据行为都是正确的。umount之后,会把数据写入到相应的block中(这是因为eCos的FATFS采用了类似linux中的块缓存机制,主要用于提高块设备数据读写性能以及降低对块设备的频繁读写,进而延长块设备寿命),但是当更新SD卡FAT的根目录数据时,发现写入的数据实际上是FAT数据区中的数据。

进一步排查发现,原来是stm32_dma_transaction_begin()函数中disk->is_tx标志使用的问题(注意下面代码中文注释部分)。

    // Perform transfer via the bounce buffers.
    if (disk->setup->bbuf_size != 0) {
        // If the requested transfer is too large for the bounce buffer we assert
        // in debug builds and truncate in production builds.
        if (count > disk->setup->bbuf_size) {
            CYG_ASSERT(false, "STM32 SDIO : Transfer exceeds bounce buffer size.");
            count = disk->setup->bbuf_size;
        }

        local_data = disk->setup->bbuf;
        if (is_tx) {// 这里原来是:if (disk->is_tx),而disk->is_tx标志的更新放在了后面,导致write时,数据源错误
            memcpy (local_data, data, count);
        }
    } else {
        local_data = data;
    }

    // Set runtime data
    disk->is_tx     = is_tx;

FAT32兼容问题

上一节,谈到了mount失败是因为fatfs_supp.c中read_boot_record()函数读取SD卡MBR失败引起的,通过修改fatfs_supp.c中read_boot_record()、disk_write()和disk_read()以及在struct fatfs_disk_s结构体添加两成员变量才得以解决。

实际上,这份修改是不完全的。我们知道,在fat32中,读写数据时是以cluster为单位的,所以,当SD卡是FAT32时,还是会出现mount失败。解决办法是修改cluster_to_block_pos()函数,在该函数末尾添加以下一行代码,也就是把block加上SD卡DBR前的隐藏扇区数:

*block += disk->start_block_num;

读取SCR出错

在调试SD卡驱动的时候,会出现读取SCR出错的情况。没有找到原因,网上搜索都说是要加个延时。但即使加了延时,我发现还是会有很小概率出现。如果有网友遇到过,恳请赐教下。

总结

一路下来发现,SD卡不仅本身驱动稍显复杂,而且还涉及eCos Disk驱动体系、FAT文件系统、块缓存等多方面内容,所以像SD卡这种块设备还是有一定难度的。在这里,最重要的是:有难度不要害怕,而要迎难而上。

整个SD卡章节,如果带上SD卡和FAT文件系统知识介绍,多达6个章节。本身的目的是想采纳我同事的建议,叙述时既要有实践经验,更要有理论知识做铺垫。此外,本次同样花了大量篇幅来介绍我的调试过程,最主要是展现我的一个调试过程、调试方法、调试思路。

水平有限,如有更好建议,请留言,本人将积极采纳!

整个代码下载地址:http://52ecos.net/thread-600-1-1.html

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

 Leave a Reply

(必须)

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

*

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

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