基于STM32的SDIO用4位总线24MHZ DMA模式操作SDHC卡
更新时间:2023-11-25 10:54:01 阅读量: 教育文库 文档下载
- STM32 SDIO推荐度:
- 相关推荐
基于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_Error SD_PowerON(void) {
SD_Error errorstatus = SD_OK;
uint32_t response = 0, count = 0; bool validvoltage = FALSE;
uint32_t SDType = SD_STD_CAPACITY; int16_t i = 0;
/* Power ON Sequence
-------------------------------------------------------*/ /* Configure the SDIO peripheral */ SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV; /* HCLK = 72MHz, SDIOCLK = 72MHz, SDIO_CK = HCLK/(178 + 2) = 400 KHz */
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 Power State to ON */
SDIO_SetPowerState(SDIO_PowerState_ON); /* Enable SDIO Clock */ SDIO_ClockCmd(ENABLE);
/* CMD0: GO_IDLE_STATE
-------------------------------------------------------*/ /* No CMD response required */
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(\ goto __return; }
rt_kprintf(\ 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_Error SD_EnableWideBusOperation(u32 WideMode) {
SD_Error errorstatus = SD_OK;
/* MMC Card doesn't support this feature */ if (SDIO_MULTIMEDIA_CARD == CardType) {
errorstatus = SD_UNSUPPORTED_FEATURE; rt_kprintf(\ return(errorstatus); }
else if ((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(\ return(errorstatus); }
else if (SDIO_BusWide_4b == WideMode) {
errorstatus = SDEnWideBus(ENABLE);
if (SD_OK == errorstatus) {
/* Configure the SDIO peripheral */
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(\ } else {
errorstatus = SDEnWideBus(DISABLE);
if (SD_OK == errorstatus) {
/* Configure the SDIO peripheral */
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(\ } }
return(errorstatus); }
注意到这个函数SDEnWideBus(ENABLE);
static SD_Error SDEnWideBus(FunctionalState NewState) {
SD_Error errorstatus = SD_OK; uint32_t scr[2] = {0, 0};
if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED) {
errorstatus = SD_LOCK_UNLOCK_FAILED;
rt_kprintf(\ return(errorstatus); }
/* Get SCR Register */
errorstatus = FindSCR(RCA, scr); /*首先注意到这个函数这个函数会卡到。*/
if (errorstatus != SD_OK) {
rt_kprintf(\ return(errorstatus); }
/* If wide bus operation to be enabled */ if (NewState == ENABLE) {
/* If requested card supports wide bus operation */ // if ((scr[1] & SD_WIDE_BUS_SUPPORT) != SD_ALLZERO) // {
/* Send CMD55 APP_CMD with argument as card's RCA.*/
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(\ return(errorstatus); }
/* Send ACMD6 APP_CMD with argument as 2 for wide bus mode */ 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(\ return(errorstatus);
}
return(errorstatus); // } // else
// {
// errorstatus = SD_REQUEST_NOT_APPLICABLE;
// rt_kprintf(\// return(errorstatus); // }
} /* If wide bus operation to be disabled */ else {
/* If requested card supports 1 bit mode operation */ if ((scr[1] & SD_SINGLE_BUS_SUPPORT) != SD_ALLZERO) {
/* Send CMD55 APP_CMD with argument as card's RCA.*/
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(\ return(errorstatus); }
/* Send ACMD6 APP_CMD with argument as 2 for wide bus mode */ 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(\ return(errorstatus); }
return(errorstatus); } else {
errorstatus = SD_REQUEST_NOT_APPLICABLE;
rt_kprintf(\ return(errorstatus); } } }
static SD_Error FindSCR(uint16_t rca, uint32_t *pscr) {
uint32_t index = 0;
SD_Error errorstatus = SD_OK; uint32_t tempscr[2] = {0, 0}; uint16_t delay_time;
/* Set Block Size To 8 Bytes */
/* Send CMD55 APP_CMD with argument as card's RCA */ 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(\ return(errorstatus); }
/* Send CMD55 APP_CMD with argument as card's RCA */
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(\ 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);
/* Send ACMD51 SD_APP_SEND_SCR with argument as 0 */ 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(\ 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(\ return(errorstatus); }
else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET) {
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL); errorstatus = SD_DATA_CRC_FAIL;
rt_kprintf(\ return(errorstatus); }
else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET) {
SDIO_ClearFlag(SDIO_FLAG_RXOVERR); errorstatus = SD_RX_OVERRUN;
rt_kprintf(\ return(errorstatus);
}
else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) {
SDIO_ClearFlag(SDIO_FLAG_STBITERR); errorstatus = SD_START_BIT_ERR;
rt_kprintf(\ return(errorstatus); }
/* Clear all the static flags */ 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(FunctionalState NewState)函数看下里面的以下代码
static SD_Error SDEnWideBus(FunctionalState NewState) {
SD_Error errorstatus = SD_OK; uint32_t scr[2] = {0, 0};
if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED) {
errorstatus = SD_LOCK_UNLOCK_FAILED;
rt_kprintf(\ return(errorstatus); }
/* Get SCR Register */
errorstatus = FindSCR(RCA, scr); /*首先注意到这个函数这个函数会卡到。*/
if (errorstatus != SD_OK) {
rt_kprintf(\ return(errorstatus); }
/* If wide bus operation to be enabled */ if (NewState == ENABLE) {
/* If requested card supports wide bus operation */ // if ((scr[1] & SD_WIDE_BUS_SUPPORT) != SD_ALLZERO) // {
/* Send CMD55 APP_CMD with argument as card's RCA.*/
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(\ return(errorstatus); }
/* Send ACMD6 APP_CMD with argument as 2 for wide bus mode */ 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(\ return(errorstatus);
}
return(errorstatus); // } // else // {
// errorstatus = SD_REQUEST_NOT_APPLICABLE;
// rt_kprintf(\
// return(errorstatus); // }
} /* If wide bus operation to be disabled */
彩 色的这些都是注释掉的呵,因为,事实上, findsrc函数返回的结果本身我就不知道是否是正确的,而且在sd2.0规范里面并没有仔细说明怎么切换总线模式,z只是要求先判断是否是传输模式, 接着是否是上锁,之后就可以直接用CMD6修改总线操作模式了,所以至今没发现findsrc这个函数的作用。另外在规范里面我也没有找到提及 findsrc这个函数的。于是直接忽略,将判断去掉,直接就设置成四位总线24MHZ,一开始不行, 我就降低频率,出现跟原来一样的反应,再降到12MHZ,突然有数据了, 于是又慢慢调试, 升到24MHZ,可以正常读写了。基本上改的就是这两个地方。其它地方因为目前没有研究的更深入没有发现问题,暂时就不改了。
至此,我已经可以用STM32的SDIO4位总线DMA模式读写SHDC卡了。经过测试,可以用文件系统读写文件, 创建文件夹,但是不能替换文件名- -,肯能是文件系统有问题。
附上我用的例程是rt_thread的文件系统, 算是为它小小宣传下,可能大家会用到, 基于MDK的rt_thread.工程在目录的bsp/stm32/里面。
文件我上传到了csdn- -由于是先上传的。后来才打算写这篇博客,见谅。。。。 PS:这是本人的有生以来第一篇博客。。。
http://download.csdn.net/source/2405254 这是例程下载地址- -我真的不是骗分的。。。我不缺。。。。
还记得上次我用RT_thread系统里面的文件系统调试了下STM32的SDIO读取SHDC。自然, 我是写的不好的呵,但是仍然希转载的人注意个人劳动成果,注明转载以及出处。 这次我由于个人兴趣,需要把SIDO驱动移植到到ASP系统里面去。
按理说,上次改好了, 这次应该可以正常编译就可以直接用的了。但是事情总没有你想象中的那么顺利,我发现在读跟写的时候,会出现一个相应超时的错误返回“RSP_TIMEOUT”,然后退出,一般是出现在这个位置
SD_Error SD_WriteBlock(uint32_t addr, uint32_t *writebuff, uint16_t BlockSize) {
SD_Error errorstatus = SD_OK;
uint8_t power = 0, cardstate = 0;
uint32_t timeout = 0, bytestransferred = 0;
uint32_t cardstatus = 0, count = 0, restwords = 0; uint32_t *tempbuff = writebuff; // uint32_t temp; //SYSTIM tim1,tim2; if (writebuff == NULL) {
errorstatus = SD_INVALID_PARAMETER;
return(errorstatus); }
TransferError = SD_OK; TransferEnd = 0;
TotalNumberOfBytes = 0;
SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT; SDIO_DataInitStructure.SDIO_DataLength = 0;
SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_1b; SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard; SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block; SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Disable; SDIO_DataConfig(&SDIO_DataInitStructure); SDIO_DMACmd(DISABLE);
if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED) {
errorstatus = SD_LOCK_UNLOCK_FAILED; return(errorstatus); }
if (CardType == SDIO_HIGH_CAPACITY_SD_CARD) {
BlockSize = 512; addr /= 512; }
/* Set the block size, both on controller and card */
if ((BlockSize > 0) && (BlockSize <= 2048) && ((BlockSize & (BlockSize - 1)) == 0)) {
power = convert_from_bytes_to_power_of_two(BlockSize); SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize; 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); temp = SDIO->STA;
errorstatus = CmdResp1Error(SDIO_SET_BLOCKLEN);
不管读写都是在这个地方命令出错,而且有时候即使不出现RSP_TIMEOUT提示,也会出现ILLEGAL_CMD错误。
但是有时候你写出错后,读就有可以。都很随机,写是肯定失败了。 这个问题很多人都可能遇到吧。
但是其实你有用调试输出的话,就会发现,在你一调用命令发送函数的时候,读取SDIO->STA里面的内容,你会发现已经出错了呵。
这就是未发先错。但是你读取了SDIO->STA会自动清除自己的状态的, 于是 ,一发送后马上读取SDIO->STA的内容,再调用命令回应函数,这个命令有可以通过了。这样一般是可以读正常了。(如上绿色代码)。 上面那个也没花我多少时间, 我更多时间却是浪费在了写shdc上。
写函数也会报这个错误,但是如果你先读再写,有时候又不会报 这个错误。呵呵, 是不是很奇怪。还有基本上写用SD_WriteBlock()函数的话,一般会返回CRC_FAILED错误,也就是校验失败了,于是自然而然的退出了 写,返回错误。但是我在rt_thread系统上是可以正常写的,但是,写不会退出写函数,但是内容早就写完了,这个bug也是我调试两个系统代码的时候 才发现的。而在asp里面,写如果不报错,也是没写进去的。
我自然而然 的想到可能是系统编译器的问题,但是后来我又排除了这个可能, 至于怎么排除,属于个人技巧问题呵。
再接着我就查看了整个读写驱动,每个错误都调试。结果还是没有找出个所以然来,依旧的CRC_FAILED.T_T 难道是读写顺序也有关。。。试了下,一样不行。相反的,更多时候连读也有问题了。。。。 在5个连续通宵到早上7点的惨痛代价后,我想起了一个事情。 那就是关于STM32传输数据的SDIO。
首先,我采用的是4位DMA模式,所以我的读写是自动的,asp系统不可以,但是rt_thread却可以读写,即使是编译器不同,但是时钟晶振总是一样的,不可能一个错误,一个正常的。除非系统中断影响,还有一个致命伤,晶振!!!!!!!!
没错了,就是晶振,在asp里面我的stm32晶振是调到最高72Mhz的,但是rt_thread我没注意过,能够读,但是写会数据出错,就说明是数据太快,SHDC卡跟不上节奏,所以crc校验出错了。 当然,推想还是要靠实践证明的,于是我就把4位总线SDIO的时钟调低了,如下:
SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV+1;
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_Enable; SDIO_Init(&SDIO_InitStructure);
直接加1就是了,这样的话分频出来实际上是72M/(2+2) = 18M
然后试了下, 竟然可以写,而且更重要的是,这个写是没有bug的,rt_thread系统的写会是死循环,回不来了,但是这个写回正常返回。
再接着,我自然也会想那么先前的SDIO->STAs错误是不是也是这个原因造成的。 于是我也把temp = SDIO->STA注释掉,结果: 一切正常。
呵呵,对不起了,各位, 忽悠了你们这么久,其实前面都可以不要的,我直接跟你们说是由于STM32的晶振频率影响了SHDC的写就可以了的。
实际上改慢下SIDO的读写速度,大家应该意见很大把, 那如果你们不写的话, 可以直接用我个temp=SDIO->STA;这样读取速度一样,但是不能写,而且- -读的也很不稳定。
顺便说下把,看到有个论坛一个老大哥用sdio读取shdc跟sd时候不一样, 说用fat的f_open函数失败,
然后说是自己没仔细看, 忽略了SHDC跟SD卡的系统引导区不同,要去查手册的。
我其实很想说的是,“大哥,你的读函数出错了才是。SHDC的系统引导区跟普通SD卡一样的。只是FAt16格式化的SD卡盘格式符跟fat32的SD卡格式符存放地址不一样而已。你读取的数据错误了。” 其它也没啥了,文件已经上传CSDN。
感觉自己好白痴啊, 这门简单的地方现在才发现,白白浪费了5天的光阴的。 http://download.csdn.net/source/2600382 另外,本人不善于文笔,写的不好。不要喷我 还有,请不要张冠李戴,把作者的东西说成自己的。 纯粹的原创,转载的请注明出处。
以前也弄过zigbee的,等有空了就顺便把zigbee协议栈2006的串口弄出个教程把, 发现这个不难,但是纠结在这上面的人很多啊。
正在阅读:
基于STM32的SDIO用4位总线24MHZ DMA模式操作SDHC卡11-25
写材料常用的亮点小标题02-23
2009-2014年上半年华北地区计算机制造行业经营状况分析年报12-22
党课讲稿:不忘初心,牢记使命,做合格党员04-23
马原选择复习题库11-25
英语专转本教案 - 写作05-30
网上商城设计(数据库设计,UML建模)05-10
燃气工程结算管理办法(下发稿)031401-19
小学六年级上册语文教学反思05-19
初一英语根据所给单词的适当形式填空10-04
- exercise2
- 铅锌矿详查地质设计 - 图文
- 厨余垃圾、餐厨垃圾堆肥系统设计方案
- 陈明珠开题报告
- 化工原理精选例题
- 政府形象宣传册营销案例
- 小学一至三年级语文阅读专项练习题
- 2014.民诉 期末考试 复习题
- 巅峰智业 - 做好顶层设计对建设城市的重要意义
- (三起)冀教版三年级英语上册Unit4 Lesson24练习题及答案
- 2017年实心轮胎现状及发展趋势分析(目录)
- 基于GIS的农用地定级技术研究定稿
- 2017-2022年中国医疗保健市场调查与市场前景预测报告(目录) - 图文
- 作业
- OFDM技术仿真(MATLAB代码) - 图文
- Android工程师笔试题及答案
- 生命密码联合密码
- 空间地上权若干法律问题探究
- 江苏学业水平测试《机械基础》模拟试题
- 选课走班实施方案
- 总线
- 基于
- 模式
- 操作
- STM32
- 24MHZ
- SDIO
- SDHC
- DMA
- 三年级上册长江作业答案
- 北京市平谷区2016-2017学年八年级下学期期末考试数学试题(含答案)
- 石灰石矿山事故应急预案
- 人教版小学数学五年级上册《实际问题与方程例5》课堂实录
- 2014年竞聘上岗及双向选择方案 - 图文
- 上海电力学院电力系统专业导师介绍(最新版)
- 数据库原理试题库
- 中国古代史尔雅通识课答案课后习题
- 体育概论简答题
- 操作系统复习简答题
- Review of Printed - Circuit - Board Level EMI - EMC issues and tools
- 学生课堂评价激励机制
- 安徽省淮北师范大学附属实验中学2018-2019学年高一下学期第二次月考化学试题
- 2019-2020年高中语文新人教版必修4教学案:第二单元第五课苏轼词两首 Word版含答案
- 2015年嘉兴市专业技术人员继续教育公需科目考试—心理健康与调适题库
- NE汽车管理案例大赛 - 独立团
- 幼儿园大班十月份计划4篇
- 4-2-4燕尾定理 题库学生版
- 2011机械专业《数控机床及应用技术》期终考试试卷A
- 《汽轮机原理》习题及答案