//*----------------------------------------------------------------------------
//* ATMEL Microcontroller Software Support - ROUSSET -
//*----------------------------------------------------------------------------
//* The software is delivered "AS IS" without warranty or condition of any
//* kind, either express, implied or statutory. This includes without
//* limitation any warranty or condition with respect to merchantability or
//* fitness for any particular purpose, or against the infringements of
//* intellectual property rights of others.
//*----------------------------------------------------------------------------
//* File Name : mci_device.c
//* Object : TEST DataFlash Functions
//* Creation : FB 26/11/2002
//*
//*----------------------------------------------------------------------------
#include "AT91C_MCI_Device.h"
//*----------------------------------------------------------------------------
//* \fn AT91F_MCI_SendCommand
//* \brief Generic function to send a command to the MMC or SDCard
//*----------------------------------------------------------------------------
AT91S_MCIDeviceStatus AT91F_MCI_SendCommand (
AT91PS_MciDevice pMCI_Device,
unsigned int Cmd,
unsigned int Arg)
{
unsigned int error,status;
//unsigned int tick=0;
// Send the command
AT91C_BASE_MCI->MCI_ARGR = Arg;
AT91C_BASE_MCI->MCI_CMDR = Cmd;
// wait for CMDRDY Status flag to read the response
do
{
status = AT91C_BASE_MCI->MCI_SR;
//tick++;
}
while( !(status & AT91C_MCI_CMDRDY) );//&& (tick<100) );
// Test error ==> if crc error and response R3 ==> don't check error
error = (AT91C_BASE_MCI->MCI_SR) & AT91C_MCI_SR_ERROR;
if(error != 0 )
{
// if the command is SEND_OP_COND the CRC error flag is always present (cf : R3 response)
if ( (Cmd != AT91C_SDCARD_APP_OP_COND_CMD) && (Cmd != AT91C_MMC_SEND_OP_COND_CMD) )
return ((AT91C_BASE_MCI->MCI_SR) & AT91C_MCI_SR_ERROR);
else
{
if (error != AT91C_MCI_RCRCE)
return ((AT91C_BASE_MCI->MCI_SR) & AT91C_MCI_SR_ERROR);
}
}
return AT91C_CMD_SEND_OK;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_MCI_SDCard_SendAppCommand
//* \brief Specific function to send a specific command to the SDCard
//*----------------------------------------------------------------------------
AT91S_MCIDeviceStatus AT91F_MCI_SDCard_SendAppCommand (
AT91PS_MciDevice pMCI_Device,
unsigned int Cmd_App,
unsigned int Arg )
{
unsigned int status;
//unsigned int tick=0;
// Send the CMD55 for application specific command
AT91C_BASE_MCI->MCI_ARGR = (pMCI_Device->pMCI_DeviceFeatures->Relative_Card_Address << 16 );
AT91C_BASE_MCI->MCI_CMDR = AT91C_APP_CMD;
// wait for CMDRDY Status flag to read the response
do
{
status = AT91C_BASE_MCI->MCI_SR;
//tick++;
}
while( !(status & AT91C_MCI_CMDRDY) );//&& (tick<100) );
// if an error occurs
if (((AT91C_BASE_MCI->MCI_SR) & AT91C_MCI_SR_ERROR) != 0 )
return ((AT91C_BASE_MCI->MCI_SR) & AT91C_MCI_SR_ERROR);
// check if it is a specific command and then send the command
if ( (Cmd_App && AT91C_SDCARD_APP_ALL_CMD) == 0)
return AT91C_CMD_SEND_ERROR;
return( AT91F_MCI_SendCommand(pMCI_Device,Cmd_App,Arg) );
}
//*----------------------------------------------------------------------------
//* \fn AT91F_MCI_GetStatus
//* \brief Addressed card sends its status register
//*----------------------------------------------------------------------------
AT91S_MCIDeviceStatus AT91F_MCI_GetStatus(AT91PS_MciDevice pMCI_Device,unsigned int relative_card_address)
{
if (AT91F_MCI_SendCommand(pMCI_Device,
AT91C_SEND_STATUS_CMD,
relative_card_address <<16) == AT91C_CMD_SEND_OK)
return (AT91C_BASE_MCI->MCI_RSPR[0]);
return AT91C_CMD_SEND_ERROR;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_MCI_Device_Handler
//* \brief MCI C interrupt handler
//*----------------------------------------------------------------------------
void AT91F_MCI_Device_Handler(
AT91PS_MciDevice pMCI_Device,
unsigned int status)
{
// If End of Tx Buffer Empty interrupt occurred
if ( status & AT91C_MCI_TXBUFE )
{
AT91C_BASE_MCI->MCI_IDR = AT91C_MCI_TXBUFE;
AT91C_BASE_PDC_MCI->PDC_PTCR = AT91C_PDC_TXTDIS;
pMCI_Device->pMCI_DeviceDesc->state = AT91C_MCI_IDLE;
} // End of if AT91C_MCI_TXBUFF
// If End of Rx Buffer Full interrupt occurred
if ( status & AT91C_MCI_RXBUFF )
{
AT91C_BASE_MCI->MCI_IDR = AT91C_MCI_RXBUFF;
AT91C_BASE_PDC_MCI->PDC_PTCR = AT91C_PDC_RXTDIS;
pMCI_Device->pMCI_DeviceDesc->state = AT91C_MCI_IDLE;
} // End of if AT91C_MCI_RXBUFF
}
//*----------------------------------------------------------------------------
//* \fn AT91F_MCI_ReadBlock
//* \brief Read an ENTIRE block or PARTIAL block
//*----------------------------------------------------------------------------
AT91S_MCIDeviceStatus AT91F_MCI_ReadBlock(
AT91PS_MciDevice pMCI_Device,
int src,
unsigned int *dataBuffer,
int sizeToRead )
{
////////////////////////////////////////////////////////////////////////////////////////////
if(pMCI_Device->pMCI_DeviceDesc->state != AT91C_MCI_IDLE)
return AT91C_READ_ERROR;
if( (AT91F_MCI_GetStatus(pMCI_Device,pMCI_Device->pMCI_DeviceFeatures->Relative_Card_Address) & AT91C_SR_READY_FOR_DATA) != AT91C_SR_READY_FOR_DATA)
return AT91C_READ_ERROR;
if ( (src + sizeToRead) > pMCI_Device->pMCI_DeviceFeatures->Memory_Capacity )
return AT91C_READ_ERROR;
// If source does not fit a begin of a block
if ( (src % pMCI_Device->pMCI_DeviceFeatures->Max_Read_DataBlock_Length) != 0 )
return AT91C_READ_ERROR;
// Test if the MMC supports Partial Read Block
// ALWAYS SUPPORTED IN SD Memory Card
if( (sizeToRead < pMCI_Device->pMCI_DeviceFeatures->Max_Read_DataBlock_Length)
&& (pMCI_Device->pMCI_DeviceFeatures->Read_Partial == 0x00) )
return AT91C_READ_ERROR;
if( sizeToRead > pMCI_Device->pMCI_DeviceFeatures->Max_Read_DataBlock_Length)
return AT91C_READ_ERROR;
////////////////////////////////////////////////////////////////////////////////////////////
// Init Mode Register
AT91C_BASE_MCI->MCI_MR |= ((pMCI_Device->pMCI_DeviceFeatures->Max_Read_DataBlock_Length << 16) | AT91C_MCI_PDCMODE);
if (sizeToRead %4)
sizeToRead = (sizeToRead /4)+1;
else
sizeToRead = sizeToRead/4;
AT91C_BASE_PDC_MCI->PDC_PTCR = (AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS);
AT91C_BASE_PDC_MCI->PDC_RPR = (unsigned int)dataBuffer;
AT91C_BASE_PDC_MCI->PDC_RCR = sizeToRead;
// Send the Read single block command
if ( AT91F_MCI_SendCommand(pMCI_Device, AT91C_READ_SINGLE_BLOCK_CMD, src) != AT91C_CMD_SEND_OK )
return AT91C_READ_ERROR;
pMCI_Device->pMCI_DeviceDesc->state = AT91C_MCI_RX_SINGLE_BLOCK;
// Enable AT91C_MCI_RXBUFF Interrupt
AT91C_BASE_MCI->MCI_IER = AT91C_MCI_RXBUFF;
// (PDC) Receiver Transfer Enable
AT91C_BASE_PDC_MCI->PDC_PTCR = AT91C_PDC_RXTEN;
return AT91C_READ_OK;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_MCI_WriteBlock
//* \brief Write an ENTIRE block but not always PARTIAL block !!!
//*----------------------------------------------------------------------------
AT91S_MCIDeviceStatus AT91F_MCI_WriteBlock(
AT91PS_MciDevice pMCI_Device,
int dest,
unsigned int *dataBuffer,
int sizeToWrite )
{
////////////////////////////////////////////////////////////////////////////////////////////
if( pMCI_Device->pMCI_DeviceDesc->state != AT91C_MCI_IDLE)
return AT91C_WRITE_ERROR;
if( (AT91F_MCI_GetStatus(pMCI_Device,pMCI_Device->pM