linux开源显卡驱动 dma,官方SD卡SDIO+DMA驱动卡死的完美解决方法

最近在用STM32F103Vet6+STemwin做一个拼音输入法的项目,所以字库必须放到TF卡上,所以必使用到SD卡驱动,因为同时要使用USB访问SD卡,所以SD卡必须保证在最佳性能状态,在网上找了几种驱动测试,都出现卡死现像,包括原子哥的驱动同出现问题.还试了中断模式和查询模式,只有查询模式效果最好,但是要把SD卡的工作频率降到10M以下才能工作正常.就将就用查询模式吧,就在昨晚又开始死机了,没办法了,但是总不能放弃项目吧,只好分析代码了,再静下来想一想,SD的工作频率24M,CPU的频率才72M,在4位模式下那CPU起不是要在10个周期(72\24\2+开销)内处理完SD卡的传送?立该用printf在SD_Read上把结果打印出来,结果返回RXOVRRUN,明显了,就是CPU取数速度跟不上SDIO。好,问题找到了,就开始修改

DRESULT disk_read (

BYTE drv,/* Physical drive nmuber (0..) */

BYTE *buff,/* Data buffer to store read data */

DWORD sector,/* Sector address (LBA) */

BYTE count/* Number of sectors to read (1..255) */

)

{

BYTE i;

SD_Error Status;

if (!count) return RES_PARERR;  //count????????0??·??ò·????????í?ó

if(drv==0)

{

//int i;

//Status = SD_ReadDisk(buff,sector,count);

/*for(i=0;i<512;i++)

{

Debug("0x%02x ",*(buff+i));

}

Debug("\r\n");*/

/*switch(SD_Mode)

{

case 0:  //dma·???

if(count==1)// 1??sector??????×÷

{ */

for(i = 0; i < count; i++)

{

Status = SD_ReadBlock((sector + i) << 9,(u32 *)(&buff[i<<9]),BlockSize);

//Debug("Read:%d\r\n",Status);

}

/*}

else

{

Status = SD_ReadMultiBlocks(sector << 9,(u32 *)(&buff[0]),BlockSize,count);

}

break;

case 1:

DISABLE_INT();

if(count==1)

{

Status = SD_ReadBlock(sector<<9,(u32 *)(&buff[0]),BlockSize);

}

else

{

Status = SD_ReadMultiBlocks(sector<<9 ,(u32 *)(&buff[0]),BlockSize,count);

}

ENABLE_INT();*/

/*break;

default:

Status=SD_ERROR;

}*/

if(Status == SD_OK)

return RES_OK;

else

return RES_ERROR;

}

else//???§??????0????×÷

{

return RES_ERROR;

}

}

从上面代码可以看到我把MutilReadBlock屏蔽了,为什么要屏蔽呢?我们来分析一吓,因为DMA SIZE只有512字节,如果我们用MutilReadBlock来读SD卡的话,由于CPU速度问题,CPU没有把512字节取完,SDIO就会继续向DMA里传数据,这里如果DMA满了,就会产生RXOVRRUN。改了以上代码测试,结果返回OK了,但是STemwin的界面还是没有正确,在这里估计是掉数据了,于是再分析ReadBlock方法

SD_Error SD_ReadBlock(uint32_t addr, uint32_t *readbuff, uint16_t BlockSize)

{

SD_Error errorstatus = SD_OK;

uint32_t count = 0, *tempbuff = readbuff;

uint8_t power = 0;

if (NULL == readbuff)

{

errorstatus = SD_INVALID_PARAMETER;

return(errorstatus);

}

TransferError = SD_OK;

TransferEnd = 0;

TotalNumberOfBytes = 0;

/* Clear all DPSM configuration */

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;

}

if ((BlockSize > 0) && (BlockSize <= 2048) && ((BlockSize & (BlockSize - 1)) == 0))

{

power = convert_from_bytes_to_power_of_two(BlockSize);

/* Set Block Size for Card */

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

errorstatus = CmdResp1Error(SDIO_SET_BLOCKLEN);

if (SD_OK != errorstatus)

{

return(errorstatus);

}

}

else

{

errorstatus = SD_INVALID_PARAMETER;

return(errorstatus);

}

if(DeviceMode == SD_INTERRUPT_MODE)

{

SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_RXFIFOHF | SDIO_IT_STBITERR, ENABLE);

}

else if(DeviceMode == SD_DMA_MODE)

{

SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_STBITERR, ENABLE);

SDIO_DMACmd(ENABLE);

DMA_RxConfiguration(readbuff, BlockSize);

}     //DMA配置代码和中断使能代码放这里

SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;

SDIO_DataInitStructure.SDIO_DataLength = BlockSize;

SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) power << 4;

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

TotalNumberOfBytes = BlockSize;

StopCondition = 0;

DestBuffer = readbuff;

/* Send CMD17 READ_SINGLE_BLOCK */

SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)addr;

SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_READ_SINGLE_BLOCK;

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

//SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_Pend;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SDIO_READ_SINGLE_BLOCK);

if (errorstatus != SD_OK)

{

return(errorstatus);

}

/* In case of single block transfer, no need of stop transfer at all.*/

if (DeviceMode == SD_POLLING_MODE)

{

/* Polling mode */

while (!(SDIO->STA &(SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR)))

{

if (SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET)

{

for (count = 0; count < 8; count++)

{

*(tempbuff + count) = SDIO_ReadData();

}

tempbuff += 8;

}

}

if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)

{

SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);

errorstatus = SD_DATA_TIMEOUT;

return(errorstatus);

}

else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)

{

SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);

errorstatus = SD_DATA_CRC_FAIL;

return(errorstatus);

}

else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)

{

SDIO_ClearFlag(SDIO_FLAG_RXOVERR);

errorstatus = SD_RX_OVERRUN;

return(errorstatus);

}

else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)

{

SDIO_ClearFlag(SDIO_FLAG_STBITERR);

errorstatus = SD_START_BIT_ERR;

return(errorstatus);

}

while (SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)

{

*tempbuff = SDIO_ReadData();

tempbuff++;

}

/* Clear all the static flags */

SDIO_ClearFlag(SDIO_STATIC_FLAGS);

}

else if (DeviceMode == SD_INTERRUPT_MODE)

{

while ((TransferEnd == 0) && (TransferError == SD_OK))

{}

if (TransferError != SD_OK)

{

return(TransferError);

}

}

else if (DeviceMode == SD_DMA_MODE)

{

//这里原来放DMA配置和中断使能代码

while (DMA_GetFlagStatus(DMA2_FLAG_TC4) == RESET)

{}

}

return(errorstatus);

}

分析上面代码,发现官方源码是在SDIO开始传送后,DMA才配置,这样做,在高速的CPU上可能没问题,但在103上肯定掉数据,于上就修改成上面的方式,改好后,STemwin终于正常了,至此SD驱动应该完美解决卡死问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值