Hello everybody,
I am looking for reference C codes (reading and writing from memory) to use MMC with the p2020.
解決済! 解決策の投稿を見る。
Please refer to the following SendCommand function provided in NetCommSw.
static e_EsdhcCmdStatus SendCommand(t_Esdhc* p_Esdhc, uint32_t command, uint32_t argument, bool transferCmd)
{
uint32_t xfertypeReg = 0, tmp, prsstat;
e_EsdhcCmdStatus cmdStatus;
uint32_t timeout;
xfertypeReg |= ((command << XFERTYPE_CMDINX_SHIFT) & XFERTYPE_CMDINX_MASK);
timeout = p_Esdhc->timeout + XX_CurrentTime();
do
{
prsstat = GET_UINT32(p_Esdhc->p_MemMap->prsstat) & PRSSTAT_CIHB_MASK;
} while((XX_CurrentTime() < timeout) && (prsstat));
if (prsstat)
return e_ESDHC_CANNOT_ISSUE_CMD;
/* Check if card can issue command using DAT lines */
if ((glbCmdArgArray[command].dataPresent) && (command != e_ESDHC_CMD_STOP_TRANS) && (command != e_ESDHC_CMD_IO_RW_DIRECT))
{
if ((GET_UINT32(p_Esdhc->p_MemMap->prsstat) & PRSSTAT_CDIHB_MASK))
return e_ESDHC_CANNOT_ISSUE_CMD;
while ((GET_UINT32(p_Esdhc->p_MemMap->prsstat) & PRSSTAT_DLSL31_MASK) != PRSSTAT_DLSL31_MASK){}
}
/* Switch command*/
if (e_ESDHC_CMD_SWITCH == command)
{
glbCmdArgArray[command] = (e_SDHC_MMC_CARD == p_Esdhc->cardDetails.cardType) ?
SwitchCmdArgs[ESDHC_MMC_INDEX] : SwitchCmdArgs[ESDHC_SD_INDEX];
}
xfertypeReg |= (glbCmdArgArray[command].dataPresent << XFERTYPE_DPSEL_SHIFT);
xfertypeReg |= (glbCmdArgArray[command].read << XFERTYPE_DTDSEL_SHIFT);
if (transferCmd)
{
if (e_SDHC_TRANS_MODE_INTERNAL_DMA == p_Esdhc->transferParam.dmaMode)
xfertypeReg |= XFERTYPE_DMAEN_MASK; /* enable internal DMA */
if (1 < p_Esdhc->transferParam.blkNum)
{
xfertypeReg |= XFERTYPE_MSBSEL_MASK;
xfertypeReg |= XFERTYPE_BCEN_MASK;
xfertypeReg |= XFERTYPE_AC12EN_MASK;
}
}
switch (glbCmdArgArray[command].cmdType) {
case e_ESDHC_NORMAL_CMD:
case e_ESDHC_SUSPEND_CMD:
case e_ESDHC_RESUME_CMD:
case e_ESDHC_ABORT_CMD:
xfertypeReg |= (glbCmdArgArray[command].cmdType << XFERTYPE_CMDTYPE_SHIFT);
break;
default:
return e_ESDHC_CMD_INVALID_PARAMS;
break;
}
switch (glbCmdArgArray[command].respType) {
case e_ESDHC_NO_RESP:
xfertypeReg |= (glbCmdArgArray[command].respType << XFERTYPE_RSPTYPE_SHIFT);
break;
case e_ESDHC_R2_RESP:
xfertypeReg |= (glbCmdArgArray[command].respType << XFERTYPE_RSPTYPE_SHIFT);
xfertypeReg |= XFERTYPE_CCCEN_MASK;
break;
case e_ESDHC_R3_RESP:
xfertypeReg |= (e_ESDHC_R1_RESP << XFERTYPE_RSPTYPE_SHIFT);
break;
case e_ESDHC_R1_RESP:
case e_ESDHC_R1b_RESP:
xfertypeReg |= (glbCmdArgArray[command].respType << XFERTYPE_RSPTYPE_SHIFT);
xfertypeReg |= XFERTYPE_CCCEN_MASK;
xfertypeReg |= XFERTYPE_CICEN_MASK;
break;
default:
return e_ESDHC_CMD_INVALID_PARAMS;
break;
}
WRITE_UINT32(p_Esdhc->p_MemMap->cmdarg, argument);
tmp = GET_UINT32(p_Esdhc->p_MemMap->cmdarg);
/* Send the command to the card*/
WRITE_UINT32(p_Esdhc->p_MemMap->xfertyp, xfertypeReg);
cmdStatus = WaitCmdDone(p_Esdhc);
return cmdStatus;
}
Please refer to drivers/mmc/card/mmc_test.c in Linux Kernel.
i tried to view drivers / mmc / card / mmc_test.c, but it's too generic.
I'm trying to follow the flows found in the p2020 datasheet
for example this one which implements the function to send a command:
send_command(cmd_index, cmd_arg, other requirements)
{
WORD wCmd; // 32-bit integer to make up the data to write into the XFERTYP register, it is
// recommended to implement in a bit-field manner
wCmd = (<cmd_index> & 0x3f) << 24; // set the first 8 bits as '00'+<cmd_index>
set CMDTYP, DPSEL, CICEN, CCCEN, RSTTYP, and DTDSEL according to the command index;
// XFERTYP register bits
if (internal DMA is used) wCmd |= 0x1;
if (multi-block transfer) {
set XFERTYP[MSBSEL] bit;
if (finite block number) {
set XFERTYP[BCEN] bit;
if (auto12 command is to use) set XFERTYP[AC12EN] bit;
}
}
write_reg(CMDARG, <cmd_arg>); // configure the command argument
write_reg(XFERTYP, wCmd); // set XFERTYP register as wCmd value to issue the command
}
wait_for_response(cmd_index)
{
while (IRQSTAT[CC] is not set); // wait until command complete bit is set
read IRQSTAT register and check if any error bits about command are set;
if (any error bits are set) report error;
write 1 to clear IRQSTAT[CC] and all command error bits;
}
Please refer to the following driver source code in Linux Kernel.
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-of-esdhc.c
Following the example of pseudocode on the datasheet of p2020 I have implemented the function that allows me to send commands.
void send_command(int cmd_index)
{
int count;
unsigned int wCmd;
unsigned int temp0,temp1;
// cmd_index
wCmd = (cmd_index & 0x3F) << 24;
// -No response
// -Data present
// -Enable. The eSDHC checks the index field in the response to see if it has the same value as the command index. If it is not, it is reported as a command index error.
// -Enable. The eSDHC checks the CRC field in the response if it contains the CRC field. If an error is detected, it is reported as a command CRC error.
// -No response
// -Write (host to card)
(*MMC_REG.XFERTYP)= CMDTYP | DPSEL | CICEN | CCCEN | RSPTYP | DTDSEL;
// Command Argument
(*MMC_REG.CMDARG) = 0x00000000;
// set XFERTYP register as wCmd value to issue the command
(*MMC_REG.XFERTYP)= wCmd;
// wait_for_response
while(1)
{
temp0=(*MMC_REG.IRQSTAT) & 0x00000001;
temp1 = (*MMC_REG.CMDRSP0);
printf("%x\n",temp1);
printf("%x\n",(*MMC_REG.CMDRSP1));
printf("%x\n",(*MMC_REG.CMDRSP2));
printf("%x\n",(*MMC_REG.CMDRSP2));
if ( temp0 == 0x00000001) break;
}
// write 1 to clear IRQSTAT[CC] and all command error bits;
(*MMC_REG.IRQSTAT) = 0x00000001;
}
set CMDTYP, DPSEL, CICEN, CCCEN, RSTTYP, and DTDSEL according to the command index;
XFERTYP register bits
i can't understand these two steps.
How does a status register be able to send the command
write_reg(XFERTYP, wCmd); // set XFERTYP register as wCmd value to issue the command
for now the send command function has been implemented only to send the Zero command, just to verify correct operation
Please refer to the following SendCommand function provided in NetCommSw.
static e_EsdhcCmdStatus SendCommand(t_Esdhc* p_Esdhc, uint32_t command, uint32_t argument, bool transferCmd)
{
uint32_t xfertypeReg = 0, tmp, prsstat;
e_EsdhcCmdStatus cmdStatus;
uint32_t timeout;
xfertypeReg |= ((command << XFERTYPE_CMDINX_SHIFT) & XFERTYPE_CMDINX_MASK);
timeout = p_Esdhc->timeout + XX_CurrentTime();
do
{
prsstat = GET_UINT32(p_Esdhc->p_MemMap->prsstat) & PRSSTAT_CIHB_MASK;
} while((XX_CurrentTime() < timeout) && (prsstat));
if (prsstat)
return e_ESDHC_CANNOT_ISSUE_CMD;
/* Check if card can issue command using DAT lines */
if ((glbCmdArgArray[command].dataPresent) && (command != e_ESDHC_CMD_STOP_TRANS) && (command != e_ESDHC_CMD_IO_RW_DIRECT))
{
if ((GET_UINT32(p_Esdhc->p_MemMap->prsstat) & PRSSTAT_CDIHB_MASK))
return e_ESDHC_CANNOT_ISSUE_CMD;
while ((GET_UINT32(p_Esdhc->p_MemMap->prsstat) & PRSSTAT_DLSL31_MASK) != PRSSTAT_DLSL31_MASK){}
}
/* Switch command*/
if (e_ESDHC_CMD_SWITCH == command)
{
glbCmdArgArray[command] = (e_SDHC_MMC_CARD == p_Esdhc->cardDetails.cardType) ?
SwitchCmdArgs[ESDHC_MMC_INDEX] : SwitchCmdArgs[ESDHC_SD_INDEX];
}
xfertypeReg |= (glbCmdArgArray[command].dataPresent << XFERTYPE_DPSEL_SHIFT);
xfertypeReg |= (glbCmdArgArray[command].read << XFERTYPE_DTDSEL_SHIFT);
if (transferCmd)
{
if (e_SDHC_TRANS_MODE_INTERNAL_DMA == p_Esdhc->transferParam.dmaMode)
xfertypeReg |= XFERTYPE_DMAEN_MASK; /* enable internal DMA */
if (1 < p_Esdhc->transferParam.blkNum)
{
xfertypeReg |= XFERTYPE_MSBSEL_MASK;
xfertypeReg |= XFERTYPE_BCEN_MASK;
xfertypeReg |= XFERTYPE_AC12EN_MASK;
}
}
switch (glbCmdArgArray[command].cmdType) {
case e_ESDHC_NORMAL_CMD:
case e_ESDHC_SUSPEND_CMD:
case e_ESDHC_RESUME_CMD:
case e_ESDHC_ABORT_CMD:
xfertypeReg |= (glbCmdArgArray[command].cmdType << XFERTYPE_CMDTYPE_SHIFT);
break;
default:
return e_ESDHC_CMD_INVALID_PARAMS;
break;
}
switch (glbCmdArgArray[command].respType) {
case e_ESDHC_NO_RESP:
xfertypeReg |= (glbCmdArgArray[command].respType << XFERTYPE_RSPTYPE_SHIFT);
break;
case e_ESDHC_R2_RESP:
xfertypeReg |= (glbCmdArgArray[command].respType << XFERTYPE_RSPTYPE_SHIFT);
xfertypeReg |= XFERTYPE_CCCEN_MASK;
break;
case e_ESDHC_R3_RESP:
xfertypeReg |= (e_ESDHC_R1_RESP << XFERTYPE_RSPTYPE_SHIFT);
break;
case e_ESDHC_R1_RESP:
case e_ESDHC_R1b_RESP:
xfertypeReg |= (glbCmdArgArray[command].respType << XFERTYPE_RSPTYPE_SHIFT);
xfertypeReg |= XFERTYPE_CCCEN_MASK;
xfertypeReg |= XFERTYPE_CICEN_MASK;
break;
default:
return e_ESDHC_CMD_INVALID_PARAMS;
break;
}
WRITE_UINT32(p_Esdhc->p_MemMap->cmdarg, argument);
tmp = GET_UINT32(p_Esdhc->p_MemMap->cmdarg);
/* Send the command to the card*/
WRITE_UINT32(p_Esdhc->p_MemMap->xfertyp, xfertypeReg);
cmdStatus = WaitCmdDone(p_Esdhc);
return cmdStatus;
}