问题描述:  

  TQ2440的官方裸跑程序中,对SD卡先进行读操作,然后再写,发现不能程序卡死。倘若对SD卡先写后读,程序可以正常运行,奇哉怪哉?

写数据的关键代码-->

while(i < BlockSize)
{
//开始传递数据到缓冲区
status=rSDIFSTA;
if((status&0x2000)==0x2000)
{ //如果发送FIFO可用,即FIFO未满
rSDIDAT = *TxBuffer;
TxBuffer++;
i++;
}
}

调试与问题分析:

  调试的时候发现,当不能在写的时候,FIFO available detect for Tx (TFDET)为0,也即是说是fifo满了。此时,程序循环了16次(i=0x10)。循环一次写入4个字节,16次刚好是fifo的最大容量64字节。这证明了,写入fifo中的数据,本应该发送给SD卡,腾空fifo以供用户继续写,却被搁置在fifo中,有进无出。就像下水道中转站被堵,上游的污水就不能继续排放一行的道理。

先写后读是可以正常工作的,我打印了执行写函数之后部分寄存器的值,如左图所示。可以发现写后的寄存器rSDIDCNT、rSDIDSTA都恢复到了初始值。右图是执行读函数之后寄存器的值,可以发现执行读函数之后,rSDIDCNT、rSDIDSTA都没有回到初始值,都仍然停留在读函数执行的状态中。也就是说,读函数没有执行彻底,SDMMC模块没有进入到空闲状态。在没有准备好的情况下,继续进行写操作,是不可能成功的。

修复

  修复的方法主要是无论读操作,还是写操作,都确认SDIO总线空闲时,然后再才退出当前的函数。这样可以保证在随后的操作中,SDMMC模块处于准备好的状态,而非遗留状态。

读函数 

/**********************************************************************************
功 能:该函数用于从SD卡中读出指定块起始地址的单个数据块
参 数:
U32 Addr 被读块的起始地址
U8* RxBuffer 用于接收读出数据的缓冲区
返回值:
0 读块操作不成功
1 读块操作成功
举 例:
在主调函数中定义一个数组作为接收缓冲区,如U8 Rx_buffer[BlockSize];
然后开始调用Read_One_Block(addr,Rx_buffer);
**********************************************************************************/
U8 Read_One_Block(U32 Addr,U8 * RxBuffer)
{
U16 i=;
U32 status=;
U16 BlockSize; //定义块大小
U16 BlockNumber; BlockSize= << SDCard_BlockSize; //以byte为单位
BlockNumber = ((Addr >> SDCard_BlockSize) + ) &0x0fff; rSDIDTIMER=0x7fffff; // Set timeout count
rSDIBSIZE=0x200; // 512byte(128word)
rSDIFSTA=rSDIFSTA|(<<); // FIFO reset
rSDIDCON = (BlockNumber<<)|(<<)|(<<)|(<<)|(<<)|(<<)|(<<); while(CMD17(Addr)!=) //发送读单个块指令
{
#ifdef __SD_MMC_DEBUG__
Uart_Printf("Send read addr failed!\n");
#endif
} /* 开始接收数据到缓冲区 */
while(i<BlockSize)
{
status = rSDIDSTA;
if(status&0x60) //检查是否超时和CRC校验是否出错
{
rSDIDSTA=(0x3<<0x5); //清除超时标志和CRC错误标志
#ifdef __SD_MMC_DEBUG__
Uart_Printf("there is wrong when reading: %s.\n",status&0x20 ? "time out" :"CRC error");
#endif
return ;
}
status=rSDIFSTA;
if((status&0x1000)==0x1000) //如果接收FIFO中有数据
{
*RxBuffer=rSDIDAT;
RxBuffer++;
i++;
}
status = rSDIDSTA;
Delay(); //延时2ms
rSDIDCON=rSDIDCON&~(<<); //结束SDMMC模块的接收
rSDIDSTA = status; //清状态标志位 /* 确认SD卡进入了空闲状态--SDIO总线空闲 */
rSDIDCON=(<<)|(<<)|(<<)|(<<)|(<<)|(BlockNumber<<);
rSDIDTIMER=0x7fffff;
status = rSDIDSTA;
while( !( ((status&0x08)==0x08) | ((status&0x20)==0x20)| ((status&0x800)==0x800) )){
status=rSDIDSTA;
} if( (status&0x20) == 0x20 ){
rSDIDSTA = status;
return ;
}
rSDIDSTA = status;
return ;
}

写函数

/**********************************************************************************
功 能:该函数用于向SD卡的一个数据块写入数据
参 数:
U32 Addr 被写块的起始地址
U8* TxBuffer 用于发送数据的缓冲区
返回值:
0 数据写入操作失败
1 数据写入操作成功
举 例:
在主调函数中定义一个数组作为发送缓冲区,如U8 Tx_buffer[BlockSize];
然后开始调用Write_One_Block(addr,Tx_buffer);
**********************************************************************************/
U8 Write_One_Block(U32 Addr,const U8 * TxBuffer)
{
U16 i = ;
U32 status = ;
U16 BlockSize; //定义块大小
U16 BlockNumber; BlockSize = << SDCard_BlockSize; //以byte为单位
BlockNumber = ((Addr >> SDCard_BlockSize) +) &0x0fff; rSDIDTIMER=0x7fffff; // Set timeout count
rSDIBSIZE=0x200; // 512 byte(128 word)
rSDIFSTA = rSDIFSTA|(<<); // FIFO reset
rSDIDCON = BlockNumber|(<<)|(<<)|(<<)|(<<)|(<<)|(<<); while(CMD24(Addr)!=) //发送写单块操作指令
{
#ifdef __SD_MMC_DEBUG__
Uart_Printf("Send write addr failed!\n");
#endif
}
/* 开始传递数据到缓冲区 */
while(i < BlockSize)
{ status=rSDIFSTA;
if((status&0x2000)==0x2000) //如果发送FIFO可用,即FIFO未满
{
rSDIDAT = *TxBuffer;
TxBuffer++;
i++;
}
} status = rSDIDSTA;
Delay();
rSDIDCON=rSDIDCON&~(<<); //结束SDMMC模块的发送
rSDIDSTA = status; /* 确认SD卡进入了空闲状态--SDIO总线空闲 */
rSDIDCON=(<<)|(<<)|(<<)|(<<)|(<<)|(BlockNumber<<);
rSDIDTIMER=0x7fffff; // Set timeout count
status = rSDIDSTA;
while( !( ((status&0x08)==0x08) | ((status&0x20)==0x20)| ((status&0x800)==0x800) )){
status=rSDIDSTA;
} if( (status&0x20) == 0x20 ){
rSDIDSTA = status;
return ;
}
rSDIDSTA = status;
return ;
}

测试效果

  以下操作都得到成功验证:

  • 单块读
  • 单块写
  • 多块读(调用单块读函数实现)
  • 多块写(调用单块写函数实现)
  • 先读后写
  • 先写后读

 移植fatfs文件系统测试:

  大多数操作没有故障出现,偶尔也会出现写函数卡死的情况

仍然存在的Bug

  1、读函数在确认SDIO总线空闲时候,经常进入超时状态,这导致读函数的速度很慢。

  2、移植fatfs文件系统测试,偶尔也会出现写函数卡死的情况。由于底层驱动运行缓慢,所以文件系统很卡。保存一张

482KB的bmp文件,耗费了十几秒种。

关于2440的裸跑程序中SD卡读后不能成功写入问题的讨论的更多相关文章

  1. Android_(控件)使用ListView显示Android系统中SD卡的文件列表

    使用ListView显示Android SD卡中的文件列表 父类布局activity_main.xml,子类布局line.xml(一个文件的单独存放) 运行截图: 程序结构: <?xml ver ...

  2. Genymotion中SD卡目录在Eclipse中查看,以及创建SDCard

    咦?这后面似乎指向一个目录,我就去找/mnt/shell/emulated/0 Wow~好熟悉的目录..不熟悉的同学可以打开android模拟器的File Manger App 里面就是这些目录了,然 ...

  3. FPGA之SPI SD卡读操作

    这几天在FPGA调试与SD通信,读SD卡里的图片,之前接触32时没有去研究过SD卡,不太熟悉操作流程,在网上找了很多资料,也看了几个32开发板的资料,但大多数都讲得不是特别清楚,只能瞎操作了一番,在别 ...

  4. 树莓派SD卡制作,并成功启动

    需要条件: 硬件部分: 1.SD卡一张(树莓派支持的) 2.树莓派3 B + 一个(其他的版本也是可以的,这里默3B+). 1.下载树莓派镜像(NOOBS_v1_9_2.zip) wget http: ...

  5. 小程序中input设置宽度后宽度还有空间,但是placeholder被遮挡问题

    最近在做小程序,已经设置了宽高,placeholder没有超出input宽度,却被挡住了一部分,上代码看一下: wxml: <view class='container'> <inp ...

  6. 直击根源:微信小程序中web-view再次刷新后页面需要退两次

    背景 在上一章(直击根源:vue项目微信小程序页面跳转web-view不刷新)解决了vue在小程序回退不刷新的问题之后,会引出了一个刷新的页面需要点击返回两次才能返回上一个页面 问题描述 在A页面从B ...

  7. Android eclipse 运行项目设置程序默认安装到SD卡

    Android eclipse 运行项目设置程序默认安装到SD卡  1.在Android手机启用USB调试功能 2.在Windows系统中打开命令提示符(开始菜单,选择运行,输入cmd回车即可),使用 ...

  8. 如何在 C# 程序中注入恶意 DLL?

    一:背景 前段时间在训练营上课的时候就有朋友提到一个问题,为什么 Windbg 附加到 C# 程序后,程序就处于中断状态了?它到底是如何实现的? 其实简而言之就是线程的远程注入,这一篇就展开说一下. ...

  9. 使用CefSharp在.Net程序中嵌入Chrome浏览器(二)——参数设置

    在实现了.Net程序中嵌入Chrome浏览器后,下一步的个性化操作就是加入一些设置了,在前面的文章中,我们可以看到在使用Chrome控件前,有如下一个操作: var setting = new Cef ...

随机推荐

  1. [转]在BBB启动时自动加载dtbo(或执行脚本、运行程序)

    启动时自动加载dtbo,实际上就是做了一个cape.官方推荐的方法是用eeprom来实现,请参考我的博文<为BBB制作专属自己的cape(一)>和<为BBB制作专属自己的cape(四 ...

  2. Servlet, Listener 、 Filter.

    Java Web的三大组件:Servlet, Listener . Filter. 使用Listener监听器:八大监听器: 第一组:用于监听Servlet三个域对象的创建与销毁 1. Servlet ...

  3. ruby 把字符串转为正则匹配表达式

    需求 函数,需要通过参数传递字符串,用来做正则匹配 reg = '[0-9]+' def func(str, reg) str.scan(reg) end 由于 reg 在其它地方定义, reg 是字 ...

  4. IE, FF, Safari前端开发常用调试工具

    一些前端开发 IE 中的常用调试工具: Microsoft Script Debugger —— Companion.JS need to install this Companion.JS —— J ...

  5. Apache Mesos总体架构

    http://developer.51cto.com/art/201401/426507.htm 1. 前言 同其他大部分分布式系统一样,Apache Mesos为了简化设计,也是采用了master/ ...

  6. ASP.Net_入门准备

    基础篇:(学习能力取决于你的基础扎不扎实) 第一步 掌握一门.NET面向对象语言,C#或VB.NET 我强烈反对在没系统学过一门面向对象(OO)语言的前提下去学ASP.NET. ASP.NET是一个全 ...

  7. 之前做web性能优化的一些个人心得

    一个web项目后期的维护主要在于性能方面.数据吞吐量一旦增大各种bug都出来了.那些通过硬件<数据库分表,数据库主从分离,读写分离>等的一些手段此处就不多说了.本文主要在编码方面做一个性能 ...

  8. java--简单排序算法

    1.冒泡排序 排序原理: 过程简单,首先将第一个记录的关键字和第二个记录的关键字进行比较,若为逆序,则将两个记录交换,然后比较第二个记录与第三个记录得关键字.以此类推,直至第n-1个记录和第n个记录的 ...

  9. Android Studio如何显示行号

    Android Studio默认没有显示行号,很多同学在使用中很不习惯.本经验介绍怎样让Android Studio显示行号. 首先我们打开我们下载安装好的Android Studio 然后右击工具按 ...

  10. ASP.NET 4.0 来了

    伴随着VS2010的公开测试,ASP.NET4.0也进入了我们的视线.ASP.NET4.0究竟给我们带来了什么,将在哪些方面提高我们的生产力? 在何时你需要使用ASP.NET4.0开发你的网站程序? ...