当前位置:首页 > 单片机 > 单片机
[导读]问题描述:    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文件系统测试:

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

仍然存在

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

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭