📄 mmc.c
字号:
Int32U Freq;
Int64U Tmp;
// Calculate SPI max clock
Freq = MmcTransfExp[CSD_GET_TRAN_SPEED_EXP()] * MmcCsdMant[CSD_GET_TRAN_SPEED_MANT()];
Freq = MmcSetClockFreq(Freq);
if(MmcDskCtrlBlk.DiskType == DiskMMC)
{
// Calculate Time outs for MMC cards
Tmp = MmmcAccessTime[CSD_GET_TAAC_EXP()] * MmcCsdMant[CSD_GET_TAAC_MANT()];
Tmp /= 10000; // us
// Freq [Hz], Tmp[1 us], *10
Tmp = (Freq*Tmp)/100000LL;
// NSAC*100*10
Tmp += 1000*CSD_GET_NSAC();
// Max time out
Tnac = Tmp;
Twr = Tmp * (1<<CSD_GET_R2W_FACTOR());
}
else
{
// Calculate Time outs for SD cards
// Freq [Hz], RD_TIME_OUT[ms]
Tmp = Freq/1000;
Tnac = Tmp * RD_TIME_OUT;
Twr = Tmp * WR_TIME_OUT;
}
// Calculate Block size and Block Number
MmcDskCtrlBlk.BlockSize = 1<<CSD_GET_READ_BL_LEN();
MmcDskCtrlBlk.BlockNumb = (CSD_GET_C_SIZE()+1)*(4<<CSD_GET_C_SIZE_MULT());
// Set Write Protect
bMmcPermWriteProtect = CSD_GET_PERM_WRITE_PROTECT() |\
CSD_GET_TMP_WRITE_PROTECT();
MmcDskCtrlBlk.WriteProtect = MmcWriteProtect() |\
bMmcPermWriteProtect;
}
/*************************************************************************
* Function Name: MmcRead
* Parameters: pInt8U pData, Int32U Add, Int32U Length
*
* Return: MmcState_t
*
* Description: Read from a Mmc
*
*************************************************************************/
inline
MmcState_t MmcRead(pInt8U pData, Int32U Add, Int32U Length)
{
Int32U Data;
MmcState_t Status = MmcOk;
DataCtrl_t DataCtrl = {0};
if(Length == 0)
{
return(Status);
}
// Check data length size - it must be divisible of the card's block size
assert((Length % MmcDskCtrlBlk.BlockSize) == 0);
// Set read time out
MCIDATATIMER = Tnac;
// Clear all related flags
MCICLEAR = 0x0000072A;
// DMA init
// set source address
DMACC0SRCADDR = (Int32U)&MCIFIFO0;
// set destination address
DMACC0LLI = 0; // no linked list
DMACC0CONTROL_bit.SWIDTH = 2; // source width 32 bits
DMACC0CONTROL_bit.DWIDTH = 0; // destination width 8 bits
DMACC0CONTROL_bit.SBSIZE = 2; // 8 words
DMACC0CONTROL_bit.DBSIZE = 2; // 8 words
DMACC0CONTROL_bit.DI = 1; // destination address increment
DMACC0CONTROL_bit.SI = 0; // source address increment
DMACC0CONTROL_bit.I = 1; // enable terminal count interrupt
while(Length)
{
// Set data size for one block
MCIDATALENGTH = MmcDskCtrlBlk.BlockSize;
Data = Add;
Status = MmcSendCmd(CMD17,&Data);
if(MmcOk != Status)
{
return(Status);
}
if(!(Data & READY_FOR_DATA) ||
((Data & CURRENT_STATE) != CARD_TRAN))
{
MmcSendCmd(CMD12,NULL);
return(MmcCardError);
}
DMACC0DESTADDR = (Int32U)pData;
// Peripheral to memory. Peripheral control
DMACC0CONFIGURATION_bit.SRCPERIPHERAL = DMA_MMCSD;
DMACC0CONFIGURATION_bit.DESTPERIPHERAL = 0;
DMACC0CONFIGURATION_bit.FLOWCNTRL = 6;
DMACC0CONFIGURATION_bit.L = 1;
DMACC0CONFIGURATION_bit.E = 1;
// block length
DataCtrl.BLOCKSIZE = CSD_GET_READ_BL_LEN();
// Data direction
DataCtrl.DIRECTION = 1;
// Block transfer
DataCtrl.MODE = 0;
// DMA disable
DataCtrl.DMAENABLE = 1;
// Enable data path
DataCtrl.ENABLE = 1;
MCIDATACTRL = DataCtrl.Data;
MCI_BUS_DLY();
// wait receive complete
while(MCISTATUS_bit.RXACTIVE);
DMACC0CONFIGURATION_bit.E = 0;
if(DMACRAWINTERRORSTATUS_bit.RAWINTERRORSTATUS0)
{
// clear error flag and terminate transfer
DMACINTERRCLR_bit.INTERRCLR0 = 1;
return(MmcDmaError);
}
DMACINTTCCLEAR_bit.INTTCCLEAR0 = 1;
MCIDATACTRL = 0;
MCI_BUS_DLY();
// data timeout
if(MCISTATUS_bit.DATATIMEOUT)
{
MCICLEAR = 1UL << 3;
return(MmcNoResponse);
}
// Start bit not detected on all data signals in wide bus mode.
if(MCISTATUS_bit.STARTBITERR)
{
MCICLEAR = 1UL << 9;
return(MmcCardError);
}
// CRC error
if(MCISTATUS_bit.DATACRCFAIL)
{
MCICLEAR = 1UL << 1;
return(MmcCardError);
}
// rx overrun
if(MCISTATUS_bit.RXOVERRUN)
{
MCICLEAR = 1UL << 5;
return(MmcCardError);
}
Length -= MmcDskCtrlBlk.BlockSize;
Add += MmcDskCtrlBlk.BlockSize;
pData += MmcDskCtrlBlk.BlockSize;
// Clear data end and data block end
MCICLEAR = (1UL << 8) | (1UL << 10);
// data end
if(!Length)
{
return(Status);
}
// loop read next block
}
return(Status);
}
/*************************************************************************
* Function Name: MmcWrite
* Parameters: const Int8U * pData, Int32U Add, Int32U Length
*
* Return: MmcState_t
*
* Description: Write to a Mmc
*
*************************************************************************/
inline
MmcState_t MmcWrite(const Int8U * pData, Int32U Add, Int32U Length)
{
Int32U Data;
MmcState_t Status = MmcOk;
DataCtrl_t DataCtrl = {0};
if(!Length)
{
return(Status);
}
// Check data length size - it must be divisible of the card's block size
assert((Length % MmcDskCtrlBlk.BlockSize) == 0);
// Set write time out
MCIDATATIMER = Twr;
// Clear all related flags
MCICLEAR = 0x0000072A;
// DMA init
// set source address
DMACC0DESTADDR = (Int32U)&MCIFIFO0;
DMACC0LLI = 0; // no linked list
DMACC0CONTROL_bit.SWIDTH = 0; // source width 8 bits
DMACC0CONTROL_bit.DWIDTH = 2; // destination width 32 bits
DMACC0CONTROL_bit.SBSIZE = 2; // 8 words
DMACC0CONTROL_bit.DBSIZE = 2; // 8 words
DMACC0CONTROL_bit.DI = 0; // destination address increment
DMACC0CONTROL_bit.SI = 1; // source address increment
DMACC0CONTROL_bit.I = 1; // enable terminal count interrupt
while(Length)
{
// Set data size for one block
MCIDATALENGTH = MmcDskCtrlBlk.BlockSize;
Data = Add;
Status = MmcSendCmd(CMD24,&Data);
if(MmcOk != Status)
{
return(Status);
}
if(!(Data & READY_FOR_DATA) ||
((Data & CURRENT_STATE) != CARD_TRAN))
{
MmcSendCmd(CMD12,NULL);
return(MmcCardError);
}
// set destination address
DMACC0SRCADDR = (Int32U)pData;
// Peripheral to memory. Peripheral control
DMACC0CONFIGURATION_bit.SRCPERIPHERAL = 0;
DMACC0CONFIGURATION_bit.DESTPERIPHERAL = DMA_MMCSD;
DMACC0CONFIGURATION_bit.FLOWCNTRL = 5;
DMACC0CONFIGURATION_bit.L = 1;
DMACC0CONFIGURATION_bit.E = 1;
// block length
DataCtrl.BLOCKSIZE = CSD_GET_READ_BL_LEN();
// Data direction
DataCtrl.DIRECTION = 0;
// Block transfer
DataCtrl.MODE = 0;
// DMA disable
DataCtrl.DMAENABLE = 1;
// Enable data path
DataCtrl.ENABLE = 1;
MCIDATACTRL = DataCtrl.Data;
MCI_BUS_DLY();
// wait transfer complete
while(MCISTATUS_bit.TXACTIVE);
DMACC0CONFIGURATION_bit.E = 0;
if(DMACRAWINTERRORSTATUS_bit.RAWINTERRORSTATUS0)
{
// clear error flag and terminate transfer
DMACINTERRCLR_bit.INTERRCLR0 = 1;
return(MmcDmaError);
}
DMACINTTCCLEAR_bit.INTTCCLEAR0 = 1;
MCIDATACTRL = 0;
MCI_BUS_DLY();
// data timeout
if(MCISTATUS_bit.DATATIMEOUT)
{
MCICLEAR = 1UL << 3;
return(MmcNoResponse);
}
// Start bit not detected on all data signals in wide bus mode.
if(MCISTATUS_bit.STARTBITERR)
{
MCICLEAR = 1UL << 9;
return(MmcCardError);
}
// CRC error
if(MCISTATUS_bit.DATACRCFAIL)
{
MCICLEAR = 1UL << 1;
return(MmcCardError);
}
// tx underrun
if(MCISTATUS_bit.TXUNDERRUN)
{
MCICLEAR = 1UL << 4;
return(MmcCardError);
}
Length -= MmcDskCtrlBlk.BlockSize;
Add += MmcDskCtrlBlk.BlockSize;
pData += MmcDskCtrlBlk.BlockSize;
// Clear data end and data block end
MCICLEAR = (1UL << 8) | (1UL << 10);
// data end
if(!Length)
{
return(Status);
}
// loop write next block
}
return(Status);
}
/*************************************************************************
* Function Name: MmcVerify
* Parameters: const Int8U * pData, Int32U Add, Int32U Length
*
* Return: MmcState_t
*
* Description: Verify on a Mmc
*
*************************************************************************/
static inline
MmcState_t MmcVerify(const Int8U * pData, Int32U Add, Int32U Length)
{
#pragma segment="USB_DMA_RAM"
#pragma location="USB_DMA_RAM"
__no_init static Int8U TempBuffer[2048]; // maximum block length is 2048
MmcState_t Status = MmcOk;
while(Length)
{
Status = MmcRead(TempBuffer,Add,MmcDskCtrlBlk.BlockSize);
if(Status != MmcOk)
{
break;
}
for(Int32U i = 0; i < MmcDskCtrlBlk.BlockSize; ++i)
{
if(TempBuffer[i] != *pData++)
{
return(MmcMiscompare);
}
}
Length -= MmcDskCtrlBlk.BlockSize;
Add += MmcDskCtrlBlk.BlockSize;
}
return(Status);
}
/*************************************************************************
* Function Name: MmcGetLastError
* Parameters: none
*
* Return: Int32U
*
* Description: Return Last error
*
*************************************************************************/
Int32U MmcGetLastError(void)
{
return(MmcLastError);
}
/*************************************************************************
* Function Name: MmcStatusUpdate
* Parameters: none
*
* Return: none
*
* Description: Update status of SD/MMC card
*
*************************************************************************/
void MmcStatusUpdate (void)
{
Int32U Data = CardRCA;
// Update WP state
MmcDskCtrlBlk.WriteProtect = MmcWriteProtect() |\
bMmcPermWriteProtect;
if(!MmcPresent())
{
MmcDskCtrlBlk.DiskStatus = DiskNotPresent;
MmcPowerDown();
return;
}
if((MmcDskCtrlBlk.DiskStatus != DiskCommandPass))
{
switch (MmcInitMedia())
{
case MmcOk:
MmcDskCtrlBlk.DiskStatus = DiskCommandPass;
MmcDskCtrlBlk.MediaChanged = TRUE;
break;
case MmcCardError:
MmcDskCtrlBlk.DiskStatus = DiskNotReady;
break;
default:
MmcDskCtrlBlk.DiskStatus = DiskNotPresent;
break;
}
}
else if(MmcSendCmd(CMD13,&Data) != MmcOk)
{
MmcDskCtrlBlk.DiskStatus = DiskNotReady;
}
else if (!(Data & READY_FOR_DATA))
{
MmcDskCtrlBlk.DiskStatus = DiskNotReady;
}
else if ((Data & CURRENT_STATE) == CARD_TRAN)
{
MmcDskCtrlBlk.DiskStatus = DiskCommandPass;
}
else
{
MmcDskCtrlBlk.DiskStatus = DiskNotReady;
}
}
/*************************************************************************
* Function Name: MmcDiskInit
* Parameters: none
*
* Return: none
*
* Description: Init MMC/SD disk
*
*************************************************************************/
void MmcDiskInit (void)
{
MmcDskCtrlBlk.BlockNumb =\
MmcDskCtrlBlk.BlockSize =\
MmcLastError = 0;
// Init SPI
MmcInit();
// Media Init
switch (MmcInitMedia())
{
case MmcOk:
MmcCsdImplemet();
MmcDskCtrlBlk.DiskStatus = DiskCommandPass;
MmcDskCtrlBlk.MediaChanged = TRUE;
break;
case MmcCardError:
MmcDskCtrlBlk.DiskStatus = DiskNotReady;
break;
default:
MmcDskCtrlBlk.DiskStatus = DiskNotPresent;
break;
}
}
#ifdef MMC_DISK_INFO
/*************************************************************************
* Function Name: MmcDiskInfo
* Parameters: pInt8U pData, DiskInfoType_t DiskInfoType
*
* Return: Int32U
*
* Description: Return pointer to Info structure of the disk
* (Inquiry or Format capacity)
*
*************************************************************************/
Int32U MmcDiskInfo (pInt8U pData, DiskInfoType_t DiskInfoType)
{
pMmc3FormatCapResponse_t pFormatCapacity;
switch (DiskInfoType)
{
case DiskInquiry:
memcpy(pData,MmcDskInquiry,SizeOfInquiryDescMmcDsk);
return(SizeOfInquiryDescMmcDsk);
case DiskFormatCapacity:
pFormatCapacity = (pMmc3FormatCapResponse_t)pData;
memset(pFormatCapacity,0,sizeof(Mmc3FormatCapResponse_t));
pFormatCapacity->CapacityListLength = sizeof(Mmc3FormatCapDescriptor_t);
if (MmcDskCtrlBlk.DiskStatus != DiskCommandPass)
{
pFormatCapacity->MaximumDescriptor.DescriptorType = FormattedMedia;
pFormatCapacity->MaximumDescriptor.BlockLength[0] = (MmcDskCtrlBlk.BlockSize >> 16) & 0xFF;
pFormatCapacity->MaximumDescriptor.BlockLength[1] = (MmcDskCtrlBlk.BlockSize >> 8) & 0xFF;
pFormatCapacity->MaximumDescriptor.BlockLength[2] = (MmcDskCtrlBlk.BlockSize ) & 0xFF;
pFormatCapacity->MaximumDescriptor.NumberofBlocks[0] = (MmcDskCtrlBlk.BlockNumb >> 24) & 0xFF;
pFormatCapacity->MaximumDescriptor.NumberofBlocks[1] = (MmcDskCtrlBlk.BlockNumb >> 16) & 0xFF;
pFormatCapacity->MaximumDescriptor.NumberofBlocks[2] = (MmcDskCtrlBlk.BlockNumb >> 8) & 0xFF;
pFormatCapacity->MaximumDescriptor.NumberofBlocks[3] = (MmcDskCtrlBlk.BlockNumb ) & 0xFF;
}
else
{
pFormatCapacity->MaximumDescriptor.DescriptorType = NoMediaPresent;
pFormatCapacity->MaximumDescriptor.BlockLength[0] = (2048 >> 16) & 0xFF;
pFormatCapacity->MaximumDescriptor.BlockLength[1] = (2048 >> 8) & 0xFF;
pFormatCapacity->MaximumDescriptor.BlockLength[2] = (2048 ) & 0xFF;
pFormatCapacity->MaximumDescriptor.NumberofBlocks[0] = (0xFFFFFFFF >> 24) & 0xFF;
pFormatCapacity->MaximumDescriptor.NumberofBlocks[1] = (0xFFFFFFFF >> 16) & 0xFF;
pFormatCapacity->MaximumDescriptor.NumberofBlocks[2] = (0xFFFFFFFF >> 8) & 0xFF;
pFormatCapacity->MaximumDescriptor.NumberofBlocks[3] = (0xFFFFFFFF ) & 0xFF;
}
return(sizeof(Mmc3FormatCapResponse_t));
}
return(0);
}
#endif // MMC_DISK_INFO
/*************************************************************************
* Function Name: MmcGetDiskCtrlBkl
* Parameters: none
*
* Return: pDiskCtrlBlk_t
*
* Description: Return pointer to control block structure of the disk
*
*************************************************************************/
pDiskCtrlBlk_t MmcGetDiskCtrlBkl (void)
{
return(&MmcDskCtrlBlk);
}
/*************************************************************************
* Function Name: MmcDiskIO
* Parameters: pInt8U pData,Int32U BlockStart,
* Int32U BlockNum, DiskIoRequest_t IoRequest
*
* Return: DiskStatusCode_t
*
* Description: MMC/SD disk I/O
*
*************************************************************************/
DiskStatusCode_t MmcDiskIO (pInt8U pData,Int32U BlockStart,
Int32U BlockNum, DiskIoRequest_t IoRequest)
{
if((pData == NULL) || (BlockStart+BlockNum > MmcDskCtrlBlk.BlockNumb))
{
return(DiskParametersError);
}
if (MmcDskCtrlBlk.DiskStatus != DiskCommandPass)
{
return(MmcDskCtrlBlk.DiskStatus);
}
switch (IoRequest)
{
case DiskWrite:
if(MmcDskCtrlBlk.WriteProtect)
{
return(DiskParametersError);
}
switch (MmcWrite(pData,BlockStart*MmcDskCtrlBlk.BlockSize,BlockNum*MmcDskCtrlBlk.BlockSize))
{
case MmcOk:
break;
case MmcCardError:
MmcDskCtrlBlk.DiskStatus = DiskNotReady;
break;
default:
MmcDskCtrlBlk.DiskStatus = DiskNotPresent;
break;
}
break;
case DiskRead:
switch (MmcRead(pData,BlockStart*MmcDskCtrlBlk.BlockSize,BlockNum*MmcDskCtrlBlk.BlockSize))
{
case MmcOk:
break;
case MmcCardError:
MmcDskCtrlBlk.DiskStatus = DiskNotReady;
break;
default:
MmcDskCtrlBlk.DiskStatus = DiskNotPresent;
break;
}
break;
case DiskVerify:
switch (MmcVerify(pData,BlockStart*MmcDskCtrlBlk.BlockSize,BlockNum*MmcDskCtrlBlk.BlockSize))
{
case MmcOk:
break;
case MmcMiscompare:
return(DiskMiscompareError);
case MmcCardError:
MmcDskCtrlBlk.DiskStatus = DiskNotReady;
break;
default:
MmcDskCtrlBlk.DiskStatus = DiskNotPresent;
break;
}
break;
default:
return(DiskParametersError);
}
return(MmcDskCtrlBlk.DiskStatus);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -