FSDev_SD_Card_BSP_CmdStart()

void  FSDev_SD_Card_BSP_CmdStart (FS_QTY               unit_nbr,
                                  FS_DEV_SD_CARD_CMD  *p_cmd,
                                  void                *p_data,
                                  FS_DEV_SD_CARD_ERR  *p_err);

File

Called from

Code enabled by

fs_dev_sd_card_bsp.c

SD/MMC cardmode driver

N/A

Start a command.

Arguments

unit_nbr

Unit number of SD/MMC card.

p_cmd

Pointer to command to transmit (see Note #2).

p_data

Pointer to buffer address for DMA transfer (see Note #3).

p_err

Pointer to variable that will receive the return error code from this function:

FS_DEV_SD_CARD_ERR_NONE

No error.

FS_DEV_SD_CARD_ERR_NO_CARD

No card present.

FS_DEV_SD_CARD_ERR_BUSY

Controller is busy.

FS_DEV_SD_CARD_ERR_UNKNOWN

Unknown or other error.

Returned Value

None.

Notes/Warnings

  1. The command start will be followed by zero, one or two additional BSP function calls, depending on whether data should be transferred and on whether any errors occur.
    1. FSDev_SD_Card_BSP_CmdStart() starts execution of the command. IT may also set up the DMA transfer (if necessary).
    2. FSDev_SD_Card_BSP_CmdWaitEnd() waits for the execution of the command to end, getting the command response (if any).
    3. If data should transferred from the card to the host, FSDev_SD_Card_BSP_CmdDataRd() will read that data; if data should be transferred from the host to the card, FSDev_SD_Card_BSP_CmdDataWr() will write that data.
  2. The command p_cmd has the following parameters:
    1. p_cmd->Cmd is the command index.
    2. p_cmd->Arg is the 32-bit argument (or 0 if there is no argument).
    3. p_cmd->Flags is a bit-mapped variable with zero or more command flags:

      FS_DEV_SD_CARD_CMD_FLAG_INITInitialization sequence before command.
      FS_DEV_SD_CARD_CMD_FLAG_BUSYBusy signal expected after command.
      FS_DEV_SD_CARD_CMD_FLAG_CRC_VALIDCRC valid after command.
      FS_DEV_SD_CARD_CMD_FLAG_IX_VALIDIndex valid after command.
      FS_DEV_SD_CARD_CMD_FLAG_OPEN_DRAINCommand line is open drain.
      FS_DEV_SD_CARD_CMD_FLAG_DATA_STARTData start command.
      FS_DEV_SD_CARD_CMD_FLAG_DATA_STOPData stop command.
      FS_DEV_SD_CARD_CMD_FLAG_RESPResponse expected.
      FS_DEV_SD_CARD_CMD_FLAG_RESP_LONGLong response expected.
    4. p_cmd->DataDir indicates the direction of any data transfer that should follow this command, if any:

      FS_DEV_SD_CARD_DATA_DIR_NONENo data transfer.
      FS_DEV_SD_CARD_DATA_DIR_HOST_TO_CARDTransfer host-to-card (write).
      FS_DEV_SD_CARD_DATA_DIR_CARD_TO_HOSTTransfer card-to-host (read).
    5. p_cmd->DataType indicates the type of the data transfer that should follow this command, if any:

      FS_DEV_SD_CARD_DATA_TYPE_NONENo data transfer.
      FS_DEV_SD_CARD_DATA_TYPE_SINGLE_BLOCKSingle data block.
      FS_DEV_SD_CARD_DATA_TYPE_MULTI_BLOCKMultiple data blocks.
      FS_DEV_SD_CARD_DATA_TYPE_STREAMStream data.
    6. p_cmd->RespType indicates the type of the response that should be expected from this command:

      FS_DEV_SD_CARD_RESP_TYPE_NONENo response.
      FS_DEV_SD_CARD_RESP_TYPE_R1R1 response: Normal Response Command.
      FS_DEV_SD_CARD_RESP_TYPE_R1BR1b response.
      FS_DEV_SD_CARD_RESP_TYPE_R2R2 response: CID, CSD Register.
      FS_DEV_SD_CARD_RESP_TYPE_R3R3 response: OCR Register.
      FS_DEV_SD_CARD_RESP_TYPE_R4R4 response: Fast I/O Response (MMC).
      FS_DEV_SD_CARD_RESP_TYPE_R5R5 response: Interrupt Request Response (MMC).
      FS_DEV_SD_CARD_RESP_TYPE_R5BR5B response.
      FS_DEV_SD_CARD_RESP_TYPE_R6R6 response: Published RCA Response.
      FS_DEV_SD_CARD_RESP_TYPE_R7R7 response: Card Interface Condition.
    7. p_cmd->BlkSize and p_cmd->BlkCnt are the block size and block count of the data transfer that should follow this command, if any.
  3. The pointer to the data buffer that will receive the data transfer that should follow this command, p_data, is given so that a DMA transfer can be set up.

Example

The example implementation of FSDev_SD_Card_BSP_CmdStart() , like the examples in subsequent sections, targets a generic host conformant to the SD card association’s host controller specification. While few hosts do conform, most have a similar mixture of registers and registers fields and require the same sequences of basic actions.

FSDev_SD_Card_BSP_CmdStart ()
void  FSDev_SD_Card_BSP_CmdStart (FS_QTY               unit_nbr,
                                  FS_DEV_SD_CARD_CMD  *p_cmd,
                                  void                *p_data,
                                  FS_DEV_SD_CARD_ERR  *p_err)
{
    CPU_INT16U  command;
    CPU_INT32U  present_state;
    CPU_INT16U  transfer_mode;
    present_state = REG_STATE;                     /* Chk if controller busy.    */  (1)
    if (DEF_BIT_IS_SET_ANY(present_state, BIT_STATE_CMD_INHIBIT_DAT |
                                          BIT_STATE_CMD_INHIBIT_CMD) == DEF_YES) {
       *p_err = FS_DEV_SD_CARD_ERR_BUSY;
        return;
    }
    transfer_mode = DEF_BIT_NONE;                 /* Calc transfer mode reg value. */  (2)
    if (p_cmd->DataType == FS_DEV_SD_CARD_DATA_TYPE_MULTIPLE_BLOCK) {
        transfer_mode |= BIT_TRANSFER_MODE_MULTIPLE_BLOCK 
                      |  BIT_TRANSFER_MODE_AUTO_CMD12
                      |  BIT_TRANSFER_MODE_BLOCK_COUNT_ENABLE;
    }
    if (p_cmd->DataDir == FS_DEV_SD_CARD_DATA_DIR_CARD_TO_HOST) {
        transfer_mode |= BIT_TRANSFER_MODE_READ | BIT_TRANSFER_MODE_DMA_ENABLE;
    } else {
        transfer_mode |= BIT_TRANSFER_MODE_DMA_ENABLE;
    }
    command = (CPU_INT16U)p_cmd->Cmd << 8;        /* Calc command register value  */  (3)
    if (DEF_BIT_IS_SET(p_cmd->Flags, FS_DEV_SD_CARD_CMD_FLAG_DATA_START) == DEF_YES) {
        command |= BIT_COMMAND_DATA_PRESENT;
    }
    if (DEF_BIT_IS_SET(p_cmd->Flags, FS_DEV_SD_CARD_CMD_FLAG_IX_VALID) == DEF_YES) {
        command |= BIT_COMMAND_DATA_COMMAND_IX_CHECK;
    }
    if (DEF_BIT_IS_SET(p_cmd->Flags, FS_DEV_SD_CARD_CMD_FLAG_CRC_VALID) == DEF_YES) {
        command |= BIT_COMMAND_DATA_COMMAND_CRC_CHECK;
    }
    if (DEF_BIT_IS_SET(p_cmd->Flags, FS_DEV_SD_CARD_CMD_FLAG_RESP) == DEF_YES) {
        if (DEF_BIT_IS_SET(p_cmd->Flags, FS_DEV_SD_CARD_CMD_FLAG_RESP_LONG) == DEF_YES) {
            command |= BIT_COMMAND_DATA_COMMAND_RESPONSE_LENGTH_136;
        } else {
            if (DEF_BIT_IS_SET(p_cmd->Flags, FS_DEV_SD_CARD_CMD_FLAG_BUSY) == DEF_YES) {
                command |= BIT_COMMAND_DATA_COMMAND_RESPONSE_LENGTH_48;
            } else {
                command |= BIT_COMMAND_DATA_COMMAND_RESPONSE_LENGTH_48_BUSY;
            }
        }
    }
                                                  /* Write registers to exec cmd. */  (4)
    REG_SDMA_ADDESS   = p_data;
    REG_BLOCK_COUNT   = p_cmd->BlkCnt;
    REG_BLOCK_SIZE    = p_cmd->BlkSize;
    REG_ARGUMENT      = p_cmd->Arg;
    REG_TRANSFER_MODE = transfer_mode;
    REG_COMMAND       = command;
   *p_err = FS_DEV_SD_CARD_ERR_NONE;
}

(1) Check whether the controller is busy. Though no successful operation should return without the controller idle, an error condition, programming mistake or unexpected condition could make an assumption about initial controller state false. This simple validation is recommended to avoid side-effects and to aid port debugging.

(2) Calculate the transfer mode register value. The command’s DataType and DataDir members specify the type and direction of any transfer. Since this examples uses DMA, DMA is enabled in the transfer mode register.

(3) Calculate the command register value. The command index is available in the command’s Cmd member, which is supplemented by the bits OR’d into Flags to describe the expected result—response and data transfer—following the command execution.

(4) The hardware registers are written to execute the command. The sequence in which the registers are written is important. Typically, as in this example, the assignment to the command register actually triggers execution.