当前位置:首页 > 单片机 > 单片机
[导读]问题描述:    TQ2440的官方裸跑程序中,对SD卡先进行读操作,然后再写,发现不能程序卡死。倘若对SD卡先写后读,程序可以正常运行,奇哉怪哉?写数据的关键代码-->while(i SDCard_BlockSize) + 1) &0x0fff; r

问题描述:  

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

写数据的关键代码-->

while(i


调试与问题分析:

  调试的时候发现,当不能在写的时候,FIFO available detectfor 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=0;

U32 status=0;

U16 BlockSize; //定义块大小

U16 BlockNumber;

BlockSize=1 << SDCard_BlockSize; //以byte为单位

BlockNumber = ((Addr >> SDCard_BlockSize) + 1) &0x0fff;

rSDIDTIMER=0x7fffff; // Set timeout count

rSDIBSIZE=0x200; // 512byte(128word)

rSDIFSTA=rSDIFSTA"(1<<16); // FIFO reset

rSDIDCON = (BlockNumber<<0)|(2<<12)|(1<<14)|(1<<16)|(1<<17)|(1<<19)|(0<<22);

while(CMD17(Addr)!=1) //发送读单个块指令

{

#ifdef __SD_MMC_DEBUG__

Uart_Printf("Send read addr failed!n");

#endif

}

/* 开始接收数据到缓冲区 */

while(i

{

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 0;

}

status=rSDIFSTA;

if((status&0x1000)==0x1000) //如果接收FIFO中有数据

{

*RxBuffer=rSDIDAT;

RxBuffer++;

i++;

}

status = rSDIDSTA;

Delay(2); //延时2ms

rSDIDCON=rSDIDCON&~(7<<12); //结束SDMMC模块的接收

rSDIDSTA = status; //清状态标志位


/* 确认SD卡进入了空闲状态--SDIO总线空闲 */

rSDIDCON=(0<<18)|(1<<17)|(1<<16)|(1<<14)|(1<<12)|(BlockNumber<<0);

rSDIDTIMER=0x7fffff;

status = rSDIDSTA;

while( !( ((status&0x08)==0x08) | ((status&0x20)==0x20)| ((status&0x800)==0x800) )){

status=rSDIDSTA;

}

if( (status&0x20) == 0x20 ){

rSDIDSTA = status;

return 0;

}

rSDIDSTA = status;

return 1;

}


写函数

/**********************************************************************************

功 能:该函数用于向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 = 0;

U32 status = 0;

U16 BlockSize; //定义块大小

U16 BlockNumber;

BlockSize = 1<< SDCard_BlockSize; //以byte为单位

BlockNumber = ((Addr >> SDCard_BlockSize) +1) &0x0fff;

rSDIDTIMER=0x7fffff; // Set timeout count

rSDIBSIZE=0x200; // 512 byte(128 word)

rSDIFSTA = rSDIFSTA|(1<<16); // FIFO reset

rSDIDCON = BlockNumber|(3<<12)|(1<<14)|(1<<16)|(1<<17)|(1<<20)|(0<<22);


while(CMD24(Addr)!=1) //发送写单块操作指令

{

#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(5);

rSDIDCON=rSDIDCON&~(7<<12); //结束SDMMC模块的发送

rSDIDSTA = status;

/* 确认SD卡进入了空闲状态--SDIO总线空闲 */

rSDIDCON=(0<<18)|(1<<17)|(1<<16)|(1<<14)|(1<<12)|(BlockNumber<<0);

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 0;

}

rSDIDSTA = status;

return 1;

}


测试效果

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

单块读

单块写

多块读(调用单块读函数实现)

多块写(调用单块写函数实现)

先读后写

先写后读

 移植fatfs文件系统测试:

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

仍然存在

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

  前不久苹果发布的新MacBook Pro仅有一个Thunderblot接口,也去掉了SD卡槽,这让很多用户十分抓狂。应该是早已预料到这种情况,苹果对背后的决定作了很多解释,并且对这种选择很自

关键字: macbook pro sd卡

有时应用需要检查USB设备的加载与卸除消息,如U盘的插上与拔出。一种办法是以轮询的方式调用设备接口尝试访问设备,但这样的做法效率很低,并且实时性不高。本文将介绍更为通用的方法,通过系统API函数

关键字: api函数 sd卡 USB u盘

索尼在电视领域一直以追求高质量的理念进行研发,索尼电视也在消费者中拥有这很好的口碑,选择其产品的也不在少数。但是有很多用户反映,发现系统限制,无法进行第三方软件的安装,这显然无法满足用户的需求。

关键字: sd卡 索尼 索尼电视

SDA协会今天正式发布了SD Express存储卡的新一代标准规范SD 8.0,过引入PCIe 4.0总线协议,可获得最高接近4GB/s的传输速度,媲美旗舰级SSD固态硬盘。 2017年的SD 6.0

关键字: 4.0 8.0 pcie sd sd卡 存储卡

大家好,如果你懒得单独备份你的应用程序、数据、联系人、SMS、日历、书签、通话记录等,那么这对你来说是一个非常有用的应用程序。

关键字: Android sd卡 备份

小编为大家总结了一篇基于 STM32 和 CAN 总线的温度监控系统的设计,通过上位机与下位机的通信,实现对温度数据的监控,并经初步实验达到了设计的要求。1 系统总体方案概述

关键字: can can总线 sd卡 嵌入式开发 电源模块

SDA协会去年发布了SD 7.0标准规范,引入PCIe,定义了全新的SD Express存储卡规格,现在Realtek(瑞昱)展示了第一款符合SD 7.0规范的主控制器“RTS5261”,相关产品也不

关键字: express realtek sd sd卡 主控 存储卡 瑞昱

6月6日消息,在今年的WWDC 2019上,苹果宣布将会让全新的iPadOS支持USB-C的驱动器,用户可以直接将闪存盘或移动硬盘等设备连接到iPad上,方便传送文件。 据悉,此次增加的新功能包括:直

关键字: ipad sd卡 安卓 苹果

近日,索尼宣布推出MRW-S3六合一拓展坞和TOUGH系列SD存储卡。前者可通过USB-C接口连接相应设备提供USB 3.1 Gen 2、HMDI、读卡器等接口,而后者则是专为在恶劣环境下进行拍摄的摄

关键字: sd卡 索尼

进入驱动学习后写的一个针对我们用的2440板子的LED驱动,应用程序略去了,主要通过GPIO_data结构体传递控制信息,支持多线程。/* Ioctl_c.h*/#ifndef __IOCTL_C_H__#define...

关键字: 2440 LED驱动 samsung
关闭
关闭