版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
基于STM32的SDIO用4位总线24MHZDMA模式操作SHDC卡
很蛋疼的发现网上很多所谓的SDIO操作SHDC无意例外都是官方的那个烂玩意,完全没有修改过,所以很多时候根本无法初始化SHDC,我也在网上看到很多人关于这部分的疑问,虽然STM32的SDIO的确是可以这样操作。但是很佩服那群人,什么都没改就发上来,把哥我害惨了。。。。
经过查资料,追踪,最后运气可佳。我发现自己的金士顿4GSD卡(class4)不能初始化跟用4位总线dma操作的原因。。各位也可以上网去找别人的试试,很多人都说不能用4位总线操作,而且用1位总线也只能是在低速率以及开启流控的情况下。而且经常出错。而4位总线总是提示没有检测到起始位。
但是他们都只会问,都没有去想象为什么,我也是。。但是后来发现。STM32的SDIO是完全没问题的,可以读写SHDC,用4位总线24MHZ工作在DMA模式,大家看我修改出来的例程就知道了。看我改过的地方,对比下官方的。
首先:
在配置的时候,一开始的时候sd卡需要有至少发74个时钟使它自己初始话,这是2.0规范要求的,但是你们自己看看官方的,完全没有这个,我一直追踪,发先在电源初始化那里就已经卡住了--|||。于是我在那里面加入了一个发送74个时钟的小代码。SD_ErrorSD_PowerON(void)
{
SD_Errorerrorstatus=SD_OK;
uint32_tresponse=0,count=0;
boolvalidvoltage=FALSE;
uint32_tSDType=SD_STD_CAPACITY;
int16_ti=0;
/*PowerONSequence-------------------------------------------------------*/
/*ConfiguretheSDIOperipheral*/
SDIO_InitStructure.SDIO_ClockDiv=SDIO_INIT_CLK_DIV;/*HCLK=72MHz,SDIOCLK=72MHz,SDIO_CK=HCLK/(178+2)=400KHz*/
SDIO_InitStructure.SDIO_ClockEdge=SDIO_ClockEdge_Rising;
SDIO_InitStructure.SDIO_ClockBypass=SDIO_ClockBypass_Disable;
SDIO_InitStructure.SDIO_ClockPowerSave=SDIO_ClockPowerSave_Disable;
SDIO_InitStructure.SDIO_BusWide=SDIO_BusWide_1b;
SDIO_InitStructure.SDIO_HardwareFlowControl=SDIO_HardwareFlowControl_Disable;
SDIO_Init(&SDIO_InitStructure);
/*Set
/*EnableSDIOClock*/
SDIO_ClockCmd(ENABLE);
/*CMD0:GO_IDLE_STATE-------------------------------------------------------*/
/*NoCMDresponserequired*/
SDIO_CmdInitStructure.SDIO_Argument=0x0;
SDIO_CmdInitStructure.SDIO_CmdIndex=SDIO_GO_IDLE_STATE;
SDIO_CmdInitStructure.SDIO_Response=SDIO_Response_No;
SDIO_CmdInitStructure.SDIO_Wait=SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM=SDIO_CPSM_Enable;
for(;i<74;i++)
{
SDIO_SendCommand(&SDIO_CmdInitStructure);
CmdError();
}看到没有,就是画线的那个,这个用37也可以了。但是规范点用74、接下来,自己初始化可以通过了,因为上电正确一般是可以初始化正常的,这个没什么问题,到了这个函数就开始有问题了。status=SD_SelectDeselect((u32)(SDCardInfo.RCA<<16));
if(status!=SD_OK)
{
rt_kprintf("SD_SelectDeselectis
error.\n");
goto__return;
}
rt_kprintf("SDsettotransfermode.\n");
status=SD_EnableWideBusOperation(SDIO_BusWide_4b);就是这个函数,使能四位总线模式的函数。事实上,在经过上一次的操作后,配置总线的时候我是这么配置的:
SDIO_InitStructure.SDIO_ClockDiv=SDIO_TRANSFER_CLK_DIV+5;
SDIO_InitStructure.SDIO_ClockEdge=SDIO_ClockEdge_Rising;
SDIO_InitStructure.SDIO_ClockBypass=SDIO_ClockBypass_Disable;
SDIO_InitStructure.SDIO_ClockPowerSave=SDIO_ClockPowerSave_Disable;
SDIO_InitStructure.SDIO_BusWide=SDIO_BusWide_1b;
SDIO_InitStructure.SDIO_HardwareFlowControl=SDIO_HardwareFlowControl_Enable;
SDIO_Init(&SDIO_InitStructure);我发现加入流控是必须的,避免出现数据出错,因为这个模式很不稳定,很多时候会出现overrun的错误,或者crc错误。这时候我们可以先不要调用SD_EnableWideBusOperation(SDIO_BusWide_4b);这样的话,其实我们是可以直接操作读写SHDC的,但是会发现不仅速度低,而且经常出错。这就是我为什么拼命要搞出四位总线的原因。所以首先要SD_SelectDeselect((u32)(SDCardInfo.RCA<<16));命令选择SD为传送模式后,要再调用SD_EnableWideBusOperation(SDIO_BusWide_4b)配置总线为四位总线模式;这是为了能够以更快的速度读取SHDC卡。事实上这个函数是有问题的。传送是命令是没有问题的,但是判断依据问题不小。大家看我的代码SD_ErrorSD_EnableWideBusOperation(u32WideMode)
{
SD_Errorerrorstatus=SD_OK;
/*MMCCarddoesn'tsupportthisfeature*/
if(SDIO_MULTIMEDIA_CARD==CardType)
{
errorstatus=SD_UNSUPPORTED_FEATURE;
rt_kprintf("SDunsupportedfeature.\n");
return(errorstatus);
}
elseif((SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType)||(SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType)||(SDIO_HIGH_CAPACITY_SD_CARD==CardType))
{
if(SDIO_BusWide_8b==WideMode)
{
errorstatus=SD_UNSUPPORTED_FEATURE;
rt_kprintf("SDunsupportedfeature.\n");
return(errorstatus);
}
elseif(SDIO_BusWide_4b==WideMode)
{
errorstatus=SDEnWideBus(ENABLE);
if(SD_OK==errorstatus)
{
/*ConfiguretheSDIOperipheral*/
SDIO_InitStructure.SDIO_ClockDiv=SDIO_TRANSFER_CLK_DIV;
SDIO_InitStructure.SDIO_ClockEdge=SDIO_ClockEdge_Rising;
SDIO_InitStructure.SDIO_ClockBypass=SDIO_ClockBypass_Disable;
SDIO_InitStructure.SDIO_ClockPowerSave=SDIO_ClockPowerSave_Disable;
SDIO_InitStructure.SDIO_BusWide=SDIO_BusWide_4b;
SDIO_InitStructure.SDIO_HardwareFlowControl=SDIO_HardwareFlowControl_Disable;
SDIO_Init(&SDIO_InitStructure);
}
else
rt_kprintf("SDenablewidebusfail.\n");
}
else
{
errorstatus=SDEnWideBus(DISABLE);
if(SD_OK==errorstatus)
{
/*ConfiguretheSDIOperipheral*/
SDIO_InitStructure.SDIO_ClockDiv=SDIO_TRANSFER_CLK_DIV;
SDIO_InitStructure.SDIO_ClockEdge=SDIO_ClockEdge_Rising;
SDIO_InitStructure.SDIO_ClockBypass=SDIO_ClockBypass_Disable;
SDIO_InitStructure.SDIO_ClockPowerSave=SDIO_ClockPowerSave_Disable;
SDIO_InitStructure.SDIO_BusWide=SDIO_BusWide_1b;
SDIO_InitStructure.SDIO_HardwareFlowControl=SDIO_HardwareFlowControl_Disable;
SDIO_Init(&SDIO_InitStructure);
}
else
rt_kprintf("SDdisablewidebusfail.\n");
}
}
return(errorstatus);
}注意到这个函数SDEnWideBus(ENABLE);
staticSD_ErrorSDEnWideBus(FunctionalStateNewState)
{
SD_Errorerrorstatus=SD_OK;
uint32_tscr[2]={0,0};
if(SDIO_GetResponse(SDIO_RESP1)&SD_CARD_LOCKED)
{
errorstatus=SD_LOCK_UNLOCK_FAILED;
rt_kprintf("sdlockeunlockfaile:inline2537.\n");
return(errorstatus);
}
/*GetSCRRegister*/
errorstatus=FindSCR(RCA,scr);/*首先注意到这个函数这个函数会卡到。*/
if(errorstatus!=SD_OK)
{
rt_kprintf("getscrregistererror:inline42547.\n");
return(errorstatus);
}
/*Ifwidebusoperationtobeenabled*/
if(NewState==ENABLE)
{
/*Ifrequestedcardsupportswidebusoperation*/
//
if((scr[1]&SD_WIDE_BUS_SUPPORT)!=SD_ALLZERO)
//
{
/*SendCMD55APP_CMDwithargumentascard'sRCA.*/
SDIO_CmdInitStructure.SDIO_Argument=(uint32_t)RCA<<16;
SDIO_CmdInitStructure.SDIO_CmdIndex=SDIO_APP_CMD;
SDIO_CmdInitStructure.SDIO_Response=SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait=SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM=SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SDIO_APP_CMD);
if(errorstatus!=SD_OK)
{
rt_kprintf("sendcardrcafail:inline2568.\n");
return(errorstatus);
}
/*SendACMD6APP_CMDwithargumentas2forwidebusmode*/
SDIO_CmdInitStructure.SDIO_Argument=0x2;
SDIO_CmdInitStructure.SDIO_CmdIndex=SDIO_APP_SD_SET_BUSWIDTH;
SDIO_CmdInitStructure.SDIO_Response=SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait=SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM=SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SDIO_APP_SD_SET_BUSWIDTH);
if(errorstatus!=SD_OK)
{
rt_kprintf("sendwidebusmodefail:inline2586.\n");
return(errorstatus);
}
return(errorstatus);
//}
//
else
//
{
//
errorstatus=SD_REQUEST_NOT_APPLICABLE;
//
rt_kprintf("sdrequesnoapplicable:inline2592.\n");
//
return(errorstatus);
//
}
}
/*Ifwidebusoperationtobedisabled*/
else
{
/*Ifrequestedcardsupports1bitmodeoperation*/
if((scr[1]&SD_SINGLE_BUS_SUPPORT)!=SD_ALLZERO)
{
/*SendCMD55APP_CMDwithargumentascard'sRCA.*/
SDIO_CmdInitStructure.SDIO_Argument=(uint32_t)RCA<<16;
SDIO_CmdInitStructure.SDIO_CmdIndex=SDIO_APP_CMD;
SDIO_CmdInitStructure.SDIO_Response=SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait=SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM=SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SDIO_APP_CMD);
if(errorstatus!=SD_OK)
{
rt_kprintf("sendwidebusmodefail:inline2586.\n");
return(errorstatus);
}
/*SendACMD6APP_CMDwithargumentas2forwidebusmode*/
SDIO_CmdInitStructure.SDIO_Argument=0x00;
SDIO_CmdInitStructure.SDIO_CmdIndex=SDIO_APP_SD_SET_BUSWIDTH;
SDIO_CmdInitStructure.SDIO_Response=SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait=SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM=SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SDIO_APP_SD_SET_BUSWIDTH);
if(errorstatus!=SD_OK)
{
rt_kprintf("sendwidebusmodefail:inline2586.\n");
return(errorstatus);
}
return(errorstatus);
}
else
{
errorstatus=SD_REQUEST_NOT_APPLICABLE;
rt_kprintf("sdrequesnoapplicable:inline2592.\n");
return(errorstatus);
}
}
}staticSD_ErrorFindSCR(uint16_trca,uint32_t*pscr)
{
uint32_tindex=0;
SD_Errorerrorstatus=SD_OK;
uint32_ttempscr[2]={0,0};
uint16_tdelay_time;
/*SetBlockSizeTo8Bytes*/
/*SendCMD55APP_CMDwithargumentascard'sRCA*/
SDIO_CmdInitStructure.SDIO_Argument=(uint32_t)8;
SDIO_CmdInitStructure.SDIO_CmdIndex=SDIO_SET_BLOCKLEN;
SDIO_CmdInitStructure.SDIO_Response=SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait=SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM=SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SDIO_SET_BLOCKLEN);
if(errorstatus!=SD_OK)
{
rt_kprintf("sendcardrcafail:inline2829.\n");
return(errorstatus);
}
/*SendCMD55APP_CMDwithargumentascard'sRCA*/
SDIO_CmdInitStructure.SDIO_Argument=(uint32_t)RCA<<16;
SDIO_CmdInitStructure.SDIO_CmdIndex=SDIO_APP_CMD;
SDIO_CmdInitStructure.SDIO_Response=SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait=SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM=SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SDIO_APP_CMD);
if(errorstatus!=SD_OK)
{
rt_kprintf("sendrcafail:inline2845.\n");
return(errorstatus);
}
SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT;
SDIO_DataInitStructure.SDIO_DataLength=8;
SDIO_DataInitStructure.SDIO_DataBlockSize=SDIO_DataBlockSize_8b;
SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToSDIO;
SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
SDIO_DataConfig(&SDIO_DataInitStructure);
/*经过测试,发现原来没有反应或者出错是因为缺少必要的处理时间,我这里是慢慢调试出来的比较理想的延时。
大家可以试试不加,有的卡运气好的可能通过了,但是不好的--肯定没有数据。。。可能是看卡的质量吧,我只试过我的SD卡,不敢定论*/for(delay_time=0;delay_time<20;delay_time++)
__nop();
//SDIO_ClearFlag(SDIO_FLAG_STBITERR);
/*SendACMD51SD_APP_SEND_SCRwithargumentas0*/
SDIO_CmdInitStructure.SDIO_Argument=0x0;
SDIO_CmdInitStructure.SDIO_CmdIndex=SDIO_SD_APP_SEND_SCR;
SDIO_CmdInitStructure.SDIO_Response=SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait=SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM=SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SDIO_SD_APP_SEND_SCR);
if(errorstatus!=SD_OK)
{
rt_kprintf("cmdResp1error:inline2870.\n");
return(errorstatus);
}
while(!(SDIO->STA&(SDIO_FLAG_RXOVERR|SDIO_FLAG_DCRCFAIL|SDIO_FLAG_DTIMEOUT|SDIO_FLAG_DBCKEND|SDIO_FLAG_STBITERR
)))
{
if(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL)!=RESET)
{
*(tempscr+index)=SDIO_ReadData();
index++;
if(index==2)
break;
}
}
if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT)!=RESET)
{
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
errorstatus=SD_DATA_TIMEOUT;
rt_kprintf("sddatatimeout:inline2886.\n");
return(errorstatus);
}
elseif(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL)!=RESET)
{
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
errorstatus=SD_DATA_CRC_FAIL;
rt_kprintf("sddatafail:inline2886.\n");
return(errorstatus);
}
elseif(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR)!=RESET)
{
SDIO_ClearFlag(SDIO_FLAG_RXOVERR);
errorstatus=SD_RX_OVERRUN;
rt_kprintf("sdrxoverrun:inline2886.\n");
return(errorstatus);
}
elseif(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR)!=RESET)
{
SDIO_ClearFlag(SDIO_FLAG_STBITERR);
errorstatus=SD_START_BIT_ERR;
rt_kprintf("sdcan'tnotfindstartbit:inline2886.\n");
return(errorstatus);
}
/*Clearallthestaticflags*/
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
*(pscr+1)=((tempscr[0]&SD_0TO7BITS)<<24)|((tempscr[0]&SD_8TO15BITS)<<8)|((tempscr[0]&SD_16TO23BITS)>>8)|((tempscr[0]&SD_24TO31BITS)>>24);
*(pscr)=((tempscr[1]&SD_0TO7BITS)<<24)|((tempscr[1]&SD_8TO15BITS)<<8)|((tempscr[1]&SD_16TO23BITS)>>8)|((tempscr[1]&SD_24TO31BITS)>>24);
return(errorstatus);
}看上面这个函数的里面的彩色代码。那个是我自己添加的,正如我所说的,官方的SDcard文件忽视了sd卡自己处理所需要的延时问题。我在这里面发现,如果不加入我这个延时,基本上,如果不先对SDIO_FLAG_STBITER置位的话,就会报错(一开始初始化成四位总线的,),要嘛没有反应(1位总线),进入死循环。。基本上能退出这个函数就是因为出错--。官方库忽略掉了这个延时,才导致这样的结果(所以BS那些只拿官方的东西直接忽悠我们骗点数的人)。再注意下下一个彩色代码
if(index==2)
break;知道为什么要等于2就退出吗?因为定义index的时候初始值是0,但是你们自己追踪下,事实上发送这条命令只会返回两个数据,我的返回的是两个0.而返回两个数据后基本总线就没反映了,成了死循环--(至少我的卡是这样,别人的卡我就不知道了,不过市面的SHDC卡大多买的都是金士顿的吧?不知道我的金士顿卡有没有代表性。)基本上这样是能正常退出的,如果你们的卡不行,试着再降低下频率,我发现我的金士顿4G(class4)只有在小于12MHZ的一位总线下才有反应。当然,是在没有配置为4位总线前。基本上这个函数就到这里,接着再返回SDEnWideBus(FunctionalStateNewState)函数看下里面的以下代码staticSD_ErrorSDEnWideBus(FunctionalStateNewState)
{
SD_Errorerrorstatus=SD_OK;
uint32_tscr[2]={0,0};
if(SDIO_GetResponse(SDIO_RESP1)&SD_CARD_LOCKED)
{
errorstatus=SD_LOCK_UNLOCK_FAILED;
rt_kprintf("sdlockeunlockfaile:inline2537.\n");
return(errorstatus);
}
/*GetSCRRegister*/
errorstatus=FindSCR(RCA,scr);/*首先注意到这个函数这个函数会卡到。*/
if(errorstatus!=SD_OK)
{
rt_kprintf("getscrregistererror:inline42547.\n");
return(errorstatus);
}
/*Ifwidebusoperationtobeenabled*/
if(NewState==ENABLE)
{
/*Ifrequestedcardsupportswidebusoperation*/
//
if((scr[1]&SD_WIDE_BUS_SUPPORT)!=SD_ALLZERO)
//
{
/*SendCMD55APP_CMDwithargumentascard'sRCA.*/
SDIO_CmdInitStructure.SDIO_Argument=(uint32_t)RCA<<16;
SDIO_CmdInitStructure.SDIO_CmdIndex=SDIO_APP_CMD;
SDIO_CmdInitStructure.SDIO_Response=SDIO_Response_Short;
SDI
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 资金安全运营风险控制承诺书(5篇)
- 确保食品质量安全卫生健康承诺书(7篇)
- 客户满意度提升与服务改进指南
- 专业服务标准履行承诺书8篇
- 企业人力资源规划及分析工具包
- 物联网农业智能设备操作指南
- 山东省济南长清区六校联考2026年初三下学期线上模拟考试(2)英语试题含解析
- 辽宁省抚顺本溪铁岭辽阳葫芦岛市重点中学2026年初三第六次模拟语文试题含解析
- 2026届重庆市渝中区名校初三下学期三诊考试语文试题试卷含解析
- 质量控制检测流程标准化模板产品抽检与质量评估版
- 企业绩效管理系统的构建
- 《电视摄像教程》课件第6章
- 消化系统常见症状课件
- DISC性格分析与情绪管理课件
- 《小学生C++创意编程》第6单元课件-do-while循环
- 离婚协议书免费下载-完整离婚协议书
- 旅游产品策划与设计课件(完整版)
- 百凤冈厚积人文沃土和谐发展培育世纪英才
- ISO22000标准培训课件
- 【原创】高二数学校本课程教材:生活中的数学校本课程
- 钢筋笼加工与安装施工方案完整
评论
0/150
提交评论