5.24 SDIO 使用说明
SDIO 是 N32H49x 标准外设库中的 SD 卡主机接口,支持 SD 存储卡、SD I/O 卡与 MMC 4.2 卡,具备命令通道、数据通道与数据 FIFO,可配合 DMA 完成块读写与擦除。本章介绍驱动的相关文件、66 个公开函数,以及示例 SD_Card。关于 SDIO 总线协议、命令与响应格式、命令与数据状态机,以及寄存器位定义,请结合用户手册“SDIO接口(SDIO)”一章阅读。
5.24.1 相关文件
| 相对路径 | 用途 |
|---|---|
firmware/n32h49x_std_periph_driver/inc/n32h49x_sdio.h |
定义 SDIO_InitType、SDIO_CmdInitType、SDIO_DataInitType 结构体与电源、时钟分频、总线宽度、命令响应、数据块长度等宏;声明 66 个公开函数,按复位与初始化、中断与 DMA、命令发送与响应、数据通道配置、块读写、擦除、卡识别,以及响应错误检查分组 |
firmware/n32h49x_std_periph_driver/src/n32h49x_sdio.c |
实现 66 个函数:寄存器复位与初始化、电源与时钟控制、命令发送与响应读取、数据通道配置、FIFO 读写、块读写与擦除命令,以及各响应类型的错误检查 |
projects/n32h49x_EVAL/examples/SDIO/ |
SDIO 示例根目录,仅包含一个示例 SD_Card |
projects/n32h49x_EVAL/examples/SDIO/SD_Card/ |
该示例的工程构成:inc/、src/、readme.txt、MDK-ARM/、EWARM/ |
projects/n32h49x_EVAL/bsp/ |
示例引用的板级支持文件:日志打印接口 log.c 与 log.h、延时接口 delay.c,以及评估板的引脚与时钟定义 |
5.24.2 API 参考
以下 66 个公开函数按 n32h49x_sdio.h 的声明顺序列出,分为 13 组;每个函数给出一句功能摘要,并附 n32h49x_sdio.c 中函数正上方的原始注释。
复位与初始化
SDIO_DeInit, SDIO_Init, SDIO_InitStruct, SDIO_EnableClock, SDIO_SetPower, SDIO_GetPower
中断与 DMA
SDIO_ConfigInt, SDIO_DMACmd
命令发送与响应
SDIO_SendCmd, SDIO_InitCmdStruct, SDIO_GetCmdResp, SDIO_GetResp
数据通道配置
SDIO_ConfigData, SDIO_InitDataStruct, SDIO_GetDataCountValue, SDIO_ReadData, SDIO_WriteData, SDIO_GetFifoCounter
读等待
SDIO_EnableReadWait, SDIO_EnableReadWaitMode, SDIO_StartReadWait, SDIO_StopReadWait
SD I/O 模式与命令完成
SDIO_EnableSdioOperation, SDIO_EnableSendSdioSuspend, SDIO_EnableCommandCompletion
标志与中断状态
SDIO_GetFlag, SDIO_ClrFlag, SDIO_GetIntStatus
基础命令
SDIO_CmdShortResponse1, SDIO_CmdShortResponse3, SDIO_CmdLongResponse2, SDIO_CmdBlockLength, SDIO_CmdBlockCount
块读写命令
SDIO_CmdReadSingleBlock, SDIO_CmdReadMultiBlock, SDIO_CmdWriteSingleBlock, SDIO_CmdWriteMultiBlock
擦除命令
SDIO_CmdSDEraseStartAdd, SDIO_CmdSDEraseEndAdd, SDIO_CmdEraseStartAdd, SDIO_CmdEraseEndAdd, SDIO_CmdErase
卡识别命令
SDIO_CmdLockUnlock, SDIO_CmdStopTransfer, SDIO_CmdSelDesel, SDIO_CmdGoIdleState, SDIO_CmdOperCond, SDIO_CmdAppCommand, SDIO_CmdAppOperCommand, SDIO_CmdBusWidth, SDIO_CmdSendSCR, SDIO_CmdAllSendCID, SDIO_CmdSendCID, SDIO_CmdSendCSD
地址与状态命令
SDIO_CmdSetRelAdd, SDIO_CmdSetRelAddMmc, SDIO_CmdSendStatus, SDIO_CmdStatusRegister, SDIO_CmdOpCondition, SDIO_CmdSwitch, SDIO_CmdSendEXTCSD
响应错误检查
SDIO_GetCmdResp1, SDIO_GetCmdResp2, SDIO_GetCmdResp3, SDIO_GetCmdResp6, SDIO_GetCmdResp7
void SDIO_DeInit(void)将 SDIO 外设寄存器复位为默认值。
name SDIO_DeInit.
fun Reset the SDIO peripheral registers to their default reset values.
param none
return none
void SDIO_Init(SDIO_InitType* InitStruct)按 InitStruct 中的参数初始化 SDIO 外设。
name SDIO_Init.
fun Initializes the SDIO peripheral according to the specified
parameters in the InitStruct.
param InitStruct pointer to a SDIO_InitType structure.
The input parameters must be the following values:
- ClkEdge:
- SDIO_CLK_EDGE_RISING
- SDIO_CLK_EDGE_FALLING
- ClkBypass:
- SDIO_CLK_BYPASS_DISABLE
- SDIO_CLK_BYPASS_ENABLE
- ClkPwrSave:
- SDIO_CLK_POWER_SAVE_DISABLE
- SDIO_CLK_POWER_SAVE_ENABLE
- BusWidth:
- SDIO_BUS_WIDTH_1B
- SDIO_BUS_WIDTH_4B
- SDIO_BUS_WIDTH_8B
- HardwareClkCtrl:
- SDIO_HARDWARE_CLKCTRL_DISABLE
- SDIO_HARDWARE_CLKCTRL_ENABLE
- ClkDiv: Must be a value between 0x00 and 0x1FF.
return none
void SDIO_InitStruct(SDIO_InitType* InitStruct)将 InitStruct 的各个成员填充为默认值。
name SDIO_InitStruct.
fun Fills each InitStruct member with its default value.
param InitStruct pointer to an SDIO_InitType structure which will be initialized.
return none
void SDIO_EnableClock(FunctionalState Cmd)使能或关闭 SDIO 时钟。
name SDIO_EnableClock.
fun Enables or disables the SDIO Clock.
param Cmd new state of the SDIO Clock.
This parameter must be one of the following values:
- ENABLE
- DISABLE
return none
void SDIO_SetPower(uint32_t PowerState)设置控制器的电源状态。
name SDIO_SetPower.
fun Sets the power status of the controller.
param PowerState new state of the Power state.
This parameter must be one of the following values:
- SDIO_POWER_CTRL_OFF
- SDIO_POWER_CTRL_ON
return none
uint32_t SDIO_GetPower(void)获取控制器的电源状态。
name SDIO_GetPower.
fun Gets the power status of the controller.
param none
return Current Power status,the value can be:
- SDIO_POWER_CTRL_OFF
- SDIO_POWER_CTRL_UP
- SDIO_POWER_CTRL_ON
void SDIO_ConfigInt(uint32_t Int, FunctionalState Cmd)使能或关闭 SDIO 中断。
name SDIO_ConfigInt.
fun Enables or disables the SDIO interrupts.
param Int specifies the SDIO interrupt sources to be enabled or disabled.
This parameter must be a value or combination of the following values:
- SDIO_INT_CCRCERR
- SDIO_INT_DCRCERR
- SDIO_INT_CMDTIMEOUT
- SDIO_INT_DATTIMEOUT
- SDIO_INT_TXURERR
- SDIO_INT_RXORERR
- SDIO_INT_CMDRESPRECV
- SDIO_INT_CMDSEND
- SDIO_INT_DATEND
- SDIO_INT_SBERR
- SDIO_INT_DATBLKEND
- SDIO_INT_CMDRUN
- SDIO_INT_TXRUN
- SDIO_INT_RXRUN
- SDIO_INT_TFIFOE
- SDIO_INT_TFIFOHE
- SDIO_INT_TFIFOF
- SDIO_INT_TDATVALID
- SDIO_INT_RFIFOE
- SDIO_INT_RFIFOHF
- SDIO_INT_RFIFOF
- SDIO_INT_RDATVALID
- SDIO_INT_SDIOINT
param Cmd new state of the specified SDIO interrupts.Must be one of one of the following values:
- ENABLE
- DISABLE
return none
void SDIO_DMACmd(FunctionalState Cmd)使能或关闭 SDIO 的 DMA 请求。
name SDIO_DMACmd.
fun Enables or disables the SDIO DMA request.
param Cmd new state of the SDIO DMA request.
This parameter must be one of the following values:
- ENABLE
- DISABLE
return none
void SDIO_SendCmd(SDIO_CmdInitType* CmdInitStruct)按 CmdInitStruct 中的参数初始化 SDIO 命令并发送该命令。
name SDIO_SendCmd.
fun Initializes the SDIO Command according to the specified
parameters in the CmdInitStruct and send the command.
param CmdInitStruct pointer to a SDIO_CmdInitType structure.
The input parameters must be the following values:
- CmdArgument: Optional SDIO command argument.
- CmdIndex: SDIO command index, must be lower than 0x40.
- ResponseType:
- SDIO_RESP_NO
- SDIO_RESP_SHORT
- SDIO_RESP_LONG
- WaitType:
- SDIO_WAIT_NO
- SDIO_WAIT_INT
- SDIO_WAIT_PEND
- CPSMConfig:
- SDIO_CPSM_DISABLE
- SDIO_CPSM_ENABLE
return none
void SDIO_InitCmdStruct(SDIO_CmdInitType* CmdInitStruct)将 CmdInitStruct 的各个成员填充为默认值。
name SDIO_InitCmdStruct.
fun Fills each CmdInitStruct member with its default value.
param CmdInitStruct pointer to a SDIO_CmdInitType structure.
return none
uint8_t SDIO_GetCmdResp(void)返回最后收到响应的命令索引。
name SDIO_GetCmdResp.
fun Returns command index of last command for which response received.
param none
return Command index of the last command response received
uint32_t SDIO_GetResp(uint32_t SDIO_RESP)返回上一条命令从卡收到的响应。
name SDIO_GetResp.
fun Returns response received from the card for the last command.
param SDIO_RESP Specifies the SDIO response register.
This parameter must be one of the following values:
- SDIO_RESPONSE_1
- SDIO_RESPONSE_2
- SDIO_RESPONSE_3
- SDIO_RESPONSE_4
return The Corresponding response register value.
void SDIO_ConfigData(SDIO_DataInitType* DataInitStruct)按 DataInitStruct 中的参数初始化 SDIO 数据通道。
name SDIO_ConfigData.
fun Initializes the SDIO data path according to the specified
parameters in the DataInitStruct.
param DataInitStruct pointer to a SDIO_DataInitType structure.
The input parameters must be the following values:
- DatTimeout: data timeout period.
- DatLen: Number of data bytes to be transferred,
must be a value between 0x0 and 0x01FFFFFF
- DatBlkSize:
- SDIO_DATBLK_SIZE_1B
- SDIO_DATBLK_SIZE_2B
- SDIO_DATBLK_SIZE_4B
- SDIO_DATBLK_SIZE_8B
- SDIO_DATBLK_SIZE_16B
- SDIO_DATBLK_SIZE_32B
- SDIO_DATBLK_SIZE_64B
- SDIO_DATBLK_SIZE_128B
- SDIO_DATBLK_SIZE_256B
- SDIO_DATBLK_SIZE_512B
- SDIO_DATBLK_SIZE_1024B
- SDIO_DATBLK_SIZE_2048B
- SDIO_DATBLK_SIZE_4096B
- SDIO_DATBLK_SIZE_8192B
- SDIO_DATBLK_SIZE_16384B
- TransferDirection:
- SDIO_TRANSDIR_TOCARD
- SDIO_TRANSDIR_TOSDIO
- TransferMode:
- SDIO_TRANSMODE_BLOCK
- SDIO_TRANSMODE_STREAM
- DPSMConfig:
- SDIO_DPSM_DISABLE
- SDIO_DPSM_ENABLE
return none
void SDIO_InitDataStruct(SDIO_DataInitType* DataInitStruct)将 DataInitStruct 的各个成员填充为默认值。
name SDIO_InitDataStruct.
fun Fills each DataInitStruct member with its default value.
param DataInitStruct pointer to a SDIO_DataInitType structure.
return none
uint32_t SDIO_GetDataCountValue(void)返回剩余待传输的数据字节数。
name SDIO_GetDataCountValue.
fun Returns number of remaining data bytes to be transferred.
param none
return Number of remaining data bytes to be transferred.
uint32_t SDIO_ReadData(void)从接收 DATFIFO 读取一个字。
name SDIO_ReadData.
fun Read one data word from Rx DATFIFO.
param none
return Data received.
void SDIO_WriteData(uint32_t Data)向发送 DATFIFO 写入一个字。
name SDIO_WriteData.
fun Write one data word to Tx DATFIFO.
param Data 32-bit data word to write.
return none
uint32_t SDIO_GetFifoCounter(void)返回 DATFIFO 中待写入或待读取的字数。
name SDIO_GetFifoCounter.
fun Returns the number of words left to be written to or read from DATFIFO.
param none
return Remaining number of words in the FIFO.
void SDIO_EnableReadWait(FunctionalState Cmd)使能 SD I/O 读等待操作。
name SDIO_EnableReadWait.
fun Enable the SD I/O Read Wait operation.
param Cmd new state of the read wait operation.
This parameter must be one of the following values:
- ENABLE
- DISABLE
return none
void SDIO_EnableReadWaitMode(uint32_t ReadWaitMode)设置插入读等待间隔的两种方式之一。
name SDIO_EnableSdioReadWaitMode.
fun Sets one of the two options of inserting read wait interval.
param ReadWaitMode SD I/O Read Wait operation mode.
This parameter must be one of the following values:
- SDIO_RDWAIT_MODE_CLK
- SDIO_RDWAIT_MODE_DAT2
return none
void SDIO_StartReadWait(void)在 RWAITEN 置位时启动 SD I/O 读等待操作。
name SDIO_StartReadWait.
fun Start the SD I/O Read Wait operation when RWAITEN bit is set.
param none
return none
void SDIO_StopReadWait(void)在 RWAITEN 置位时停止 SD I/O 读等待操作。
name SDIO_StopReadWait.
fun Stop the SD I/O Read Wait operation when RWAITEN bit is set.
param none
return none
void SDIO_EnableSdioOperation(FunctionalState Cmd)使能 SD I/O 模式操作。
name SDIO_EnableSdioOperation.
fun Enables the SD I/O Mode Operation.
param Cmd new state of the SD I/O Mode Operation.
This parameter must be one of the following values:
- ENABLE
- DISABLE
return none
void SDIO_EnableSendSdioSuspend(FunctionalState Cmd)使能 SD I/O 模式挂起命令的发送。
name SDIO_EnableSendSdioSuspend.
fun Enables the SD I/O Mode suspend command sending.
param Cmd new state of the SD I/O Mode suspend command sending.
This parameter must be one of the following values:
- ENABLE
- DISABLE
return none
void SDIO_EnableCommandCompletion(FunctionalState Cmd)使能命令完成信号。
name SDIO_EnableCommandCompletion.
fun Enables the command completion signal.
param Cmd new state of the command completion signal.
This parameter must be one of the following values:
- ENABLE
- DISABLE
return none
FlagStatus SDIO_GetFlag(uint32_t Flag)检查指定的 SDIO 标志是否置位。
name SDIO_GetFlag.
fun Checks whether the specified SDIO flag is set or not.
param Flag specifies the flag to check.
This parameter must be one of the following values:
- SDIO_FLAG_CCRCERR
- SDIO_FLAG_DCRCERR
- SDIO_FLAG_CMDTIMEOUT
- SDIO_FLAG_DATTIMEOUT
- SDIO_FLAG_TXURERR
- SDIO_FLAG_RXORERR
- SDIO_FLAG_CMDRESPRECV
- SDIO_FLAG_CMDSEND
- SDIO_FLAG_DATEND
- SDIO_FLAG_SBERR
- SDIO_FLAG_DATBLKEND
- SDIO_FLAG_CMDRUN
- SDIO_FLAG_TXRUN
- SDIO_FLAG_RXRUN
- SDIO_FLAG_TFIFOE
- SDIO_FLAG_TFIFOHE
- SDIO_FLAG_TFIFOF
- SDIO_FLAG_TDATVALID
- SDIO_FLAG_RFIFOE
- SDIO_FLAG_RFIFOHF
- SDIO_FLAG_RFIFOF
- SDIO_FLAG_RDATVALID
- SDIO_FLAG_SDIOINT
return FlagStatus:
- SET
- RESET
void SDIO_ClrFlag(uint32_t FlagClr)清除 SDIO 的待处理标志。
name SDIO_ClrFlag.
fun Clears the SDIO's pending flags.
param FlagClr specifies the flag to clear.
This parameter must be one of the following values:
- SDIO_FLAG_CCRCERR
- SDIO_FLAG_DCRCERR
- SDIO_FLAG_CMDTIMEOUT
- SDIO_FLAG_DATTIMEOUT
- SDIO_FLAG_TXURERR
- SDIO_FLAG_RXORERR
- SDIO_FLAG_CMDRESPRECV
- SDIO_FLAG_CMDSEND
- SDIO_FLAG_DATEND
- SDIO_FLAG_SBERR
- SDIO_FLAG_DATBLKEND
- SDIO_FLAG_SDIOINT
return none
INTStatus SDIO_GetIntStatus(uint32_t Int)检查指定的 SDIO 中断是否发生。
name SDIO_GetIntStatus.
fun Checks whether the specified SDIO interrupt has occurred or not.
param Int specifies the SDIO interrupt source to check.
This parameter must be one of the following values:
- SDIO_INT_CCRCERR
- SDIO_INT_DCRCERR
- SDIO_INT_CMDTIMEOUT
- SDIO_INT_DATTIMEOUT
- SDIO_INT_TXURERR
- SDIO_INT_RXORERR
- SDIO_INT_CMDRESPRECV
- SDIO_INT_CMDSEND
- SDIO_INT_DATEND
- SDIO_INT_SBERR
- SDIO_INT_DATBLKEND
- SDIO_INT_CMDRUN
- SDIO_INT_TXRUN
- SDIO_INT_RXRUN
- SDIO_INT_TFIFOE
- SDIO_INT_TFIFOHE
- SDIO_INT_TFIFOF
- SDIO_INT_TDATVALID
- SDIO_INT_RFIFOE
- SDIO_INT_RFIFOHF
- SDIO_INT_RFIFOF
- SDIO_INT_RDATVALID
- SDIO_INT_SDIOINT
return INTStatus:
- SET
- RESET
uint32_t SDIO_CmdShortResponse1(uint8_t Cmd, uint32_t Arg, uint32_t timeout)带参数发送命令并按超时检查 R1 响应。
name SDIO_CmdShortResponse1.
fun Send command with argument and check R1 response with timeout.
param Cmd specifies the command index to be sent.
param Arg specifies the command argument.
param timeout timeout value for response, can not be 0.
return SDIO error state
uint32_t SDIO_CmdShortResponse3(uint8_t Cmd, uint32_t Arg)带参数发送命令并检查 R3 响应。
name SDIO_CmdShortResponse3.
fun Send command with argument and check R3 response.
param Cmd specifies the command index to be sent.
param Arg specifies the command argument.
return SDIO error state
uint32_t SDIO_CmdLongResponse2(uint8_t Cmd, uint32_t Arg)带参数发送命令并检查 R2 响应。
name SDIO_CmdLongResponse2.
fun Send command with argument and check the R2 response.
param Cmd specifies the command index to be sent.
param Arg specifies the command argument.
return SDIO error state
uint32_t SDIO_CmdBlockLength(uint32_t BlockSize)发送设置数据块长度命令并检查响应。
name SDIO_CmdBlockLength.
fun Send the Data Block Length command and check the response
param BlockSize specifies the SDIO data block length.
return SDIO error state
uint32_t SDIO_CmdBlockCount(uint32_t BlockCnt)发送设置数据块数量命令并检查响应。
name SDIO_CmdBlockCount.
fun Send the Set Data Block Count command and check the response
param BlockCnt specifies the SDIO block count.
return SDIO error state
uint32_t SDIO_CmdReadSingleBlock(uint32_t ReadAdd)发送读单块命令并检查响应。
name SDIO_CmdReadSingleBlock.
fun Send the Read Single Block command and check the response
param ReadAdd specifies the start address for reading.
return SDIO error state
uint32_t SDIO_CmdReadMultiBlock(uint32_t ReadAdd)发送读多块命令并检查响应。
name SDIO_CmdReadMultiBlock.
fun Send the Read Multi Block command and check the response
param ReadAdd specifies the start address for reading.
return SDIO error state
uint32_t SDIO_CmdWriteSingleBlock(uint32_t WriteAdd)发送写单块命令并检查响应。
name SDIO_CmdWriteSingleBlock.
fun Send the Write Single Block command and check the response
param WriteAdd specifies the start address for writing.
return SDIO error state
uint32_t SDIO_CmdWriteMultiBlock(uint32_t WriteAdd)发送写多块命令并检查响应。
name SDIO_CmdWriteMultiBlock.
fun Send the Write Multi Block command and check the response
param WriteAdd specifies the start address for writing.
return SDIO error state
uint32_t SDIO_CmdSDEraseStartAdd(uint32_t StartAdd)发送 SD 起始地址擦除命令并检查响应。
name SDIO_CmdSDEraseStartAdd.
fun Send the Start Address Erase command for SD and check the response
param StartAdd specifies the start address for erasing.
return SDIO error state
uint32_t SDIO_CmdSDEraseEndAdd(uint32_t EndAdd)发送 SD 结束地址擦除命令并检查响应。
name SDIO_CmdSDEraseEndAdd.
fun Send the End Address Erase command for SD and check the response
param EndAdd specifies the end address for erasing.
return SDIO error state
uint32_t SDIO_CmdEraseStartAdd(uint32_t StartAdd)发送起始地址擦除命令并检查响应。
name SDIO_CmdEraseStartAdd.
fun Send the Start Address Erase command and check the response
param StartAdd specifies the start address for erasing.
return SDIO error state
uint32_t SDIO_CmdEraseEndAdd(uint32_t EndAdd)发送结束地址擦除命令并检查响应。
name SDIO_CmdEraseEndAdd.
fun Send the End Address Erase command and check the response
param StartAdd specifies the start address for erasing.
return SDIO error state
uint32_t SDIO_CmdErase(void)发送擦除命令并检查响应。
name SDIO_CmdErase.
fun Send the Erase command and check the response
param none
return SDIO error state
uint32_t SDIO_CmdLockUnlock(uint32_t Arg)发送上锁或解锁命令并检查响应。
name SDIO_CmdLockUnlock.
fun Send the lock/unlock command and check the response
param none
return SDIO error state
uint32_t SDIO_CmdStopTransfer(void)发送停止传输命令并检查响应。
name SDIO_CmdStopTransfer.
fun Send the Stop Transfer command and check the response.
param none
return SDIO error state
uint32_t SDIO_CmdSelDesel(uint16_t RCA)发送选择或取消选择命令并检查响应。
name SDIO_CmdSelDesel.
fun Send the Select Deselect command and check the response.
param RCA: Address of the card to be selected
return SDIO error state
uint32_t SDIO_CmdGoIdleState(void)发送进入空闲状态命令并检查响应。
name SDIO_CmdGoIdleState.
fun Send the Go Idle State command and check the response.
param none
return SDIO error state
uint32_t SDIO_CmdOperCond(void)发送工作条件命令并检查响应。
name SDIO_CmdOperCond.
fun Send the Operating Condition command and check the response.
param none
return SDIO error state
uint32_t SDIO_CmdAppCommand(uint32_t Arg)发送应用命令,用来说明下一条是应用专用命令而非标准命令,并检查响应。
name SDIO_CmdAppCommand.
fun Send the Application command to verify that that the next command
is an application specific com-mand rather than a standard command
and check the response.
param Arg: Command Argument
return SDIO error state
uint32_t SDIO_CmdAppOperCommand(uint32_t Arg)发送命令请求被访问的卡返回其工作条件寄存器(OCR)。
name SDIO_CmdAppOperCommand.
fun Send the command asking the accessed card to send its operating
condition register (OCR)
param Arg: Command Argument
return SDIO error state
uint32_t SDIO_CmdBusWidth(uint32_t BusWidth)发送总线宽度命令并检查响应。
name SDIO_CmdBusWidth.
fun Send the Bus Width command and check the response.
param BusWidth: Bus width
return SDIO error state
uint32_t SDIO_CmdSendSCR(void)发送获取 SCR 命令并检查响应。
name SDIO_CmdSendSCR.
fun Send the Send SCR command and check the response.
param none
return SDIO error state
uint32_t SDIO_CmdAllSendCID(void)发送广播获取 CID 命令并检查响应。
name SDIO_CmdAllSendCID.
fun Send the Send all CID command and check the response.
param none
return SDIO error state
uint32_t SDIO_CmdSendCID(uint16_t RCA)发送获取 CID 命令并检查响应。
name SDIO_CmdSendCID.
fun Send the Send CID command and check the response.
param RCA: Card RCA
return SDIO error state
uint32_t SDIO_CmdSendCSD(uint16_t RCA)发送获取 CSD 命令并检查响应。
name SDIO_CmdSendCSD.
fun Send the Send CSD command and check the response.
param RCA: Card RCA
return SDIO error state
uint32_t SDIO_CmdSetRelAdd(uint16_t *pRCA)发送设置相对地址命令。
name SDIO_CmdSetRelAdd.
fun Send the Set Relative Address command.
param pRCA: pointer to the Card RCA
return SDIO error state
uint32_t SDIO_CmdSetRelAddMmc(uint16_t RCA)向 MMC 卡(非 SD 卡)发送设置相对地址命令。
name SDIO_CmdSetRelAddMmc.
fun Send the Set Relative Address command to MMC card (not SD card).
param RCA: Card RCA
return SDIO error state
uint32_t SDIO_CmdSendStatus(uint32_t Arg)发送状态命令并检查响应。
name SDIO_CmdSendStatus.
fun Send the Status command and check the response.
param Arg: command argument
return SDIO error state
uint32_t SDIO_CmdStatusRegister(void)发送状态寄存器命令并检查响应。
name SDIO_CmdStatusRegister.
fun Send the Status register command and check the response.
param none
return SDIO error state
uint32_t SDIO_CmdOpCondition(uint32_t Arg)发送主机容量支持信息,并通过 SEND_OP_COND 命令启动卡初始化过程。
name SDIO_CmdOpCondition.
fun Sends host capacity support information and activates the card's
initialization process by send SDMMC_CMD_SEND_OP_COND command.
param Arg: command argument
return SDIO error state
uint32_t SDIO_CmdSwitch(uint32_t Arg)查询可切换功能并切换卡功能,对应 HS_SWITCH 命令。
name SDIO_CmdSwitch.
fun Checks switchable function and switch card function. SDMMC_CMD_HS_SWITCH command
param Arg: command argument
return SDIO error state
uint32_t SDIO_CmdSendEXTCSD(uint32_t Arg)发送获取 EXT_CSD 命令并检查响应。
name SDIO_CmdSendEXTCSD.
fun Send the Send EXT_CSD command and check the response.
param Arg: command argument
return SDIO error state
uint32_t SDIO_GetCmdResp1(uint8_t Cmd, uint32_t Timeout)检查 R1 响应的错误状态。
name SDIO_GetCmdResp1.
fun Checks for error conditions for R1 response.
param Cmd: The sent command index
param Timeout: timeout value, can not be 0.
return SDIO error state
uint32_t SDIO_GetCmdResp2(void)检查 R2(CID 或 CSD)响应的错误状态。
name SDIO_GetCmdResp2.
fun Checks for error conditions for R2 (CID or CSD) response.
param none
return SDIO error state
uint32_t SDIO_GetCmdResp3(void)检查 R3(OCR)响应的错误状态。
name SDIO_GetCmdResp3.
fun Checks for error conditions for R3 (OCR) response.
param none
return SDIO error state
uint32_t SDIO_GetCmdResp6(uint8_t Cmd, uint16_t *pRCA)检查 R6(RCA)响应的错误状态。
name SDIO_GetCmdResp6
fun Checks for error conditions for R6 (RCA) response.
param Cmd: The sent command index
param pRCA: Pointer to the variable that will contain the SD card relative address RCA
return SDIO error state
uint32_t SDIO_GetCmdResp7(void)检查 R7 响应的错误状态。
name SDIO_GetCmdResp7
fun Checks for error conditions for R7 response.
param none
return SDIO error state
5.24.3 Demo 示例说明
本节覆盖 SDIO 的唯一示例 SD_Card,它通过 SDIO 主机接口对板载 TF 卡完成一次读、擦、写测试并核验数据。
5.24.3.1 SD_Card SD 卡读写擦测试
工程目录: projects/n32h49x_EVAL/examples/SDIO/SD_Card/
初始化 SDIO 引脚与外设→上电并识别 TF 卡→切换到传输时钟与 4 位总线→读取指定块并打印数据→擦除后再写入相同数据→再读回逐字节比较→打印测试结果
| 项目 | 源码解读 |
|---|---|
| 功能 | 通过 SDIO 主机接口对板载 TF 卡执行一次完整的读、擦、写测试; 按键触发后先读取起始 4 个数据块,再擦除该区域并写入新的测试数据,最后读回逐字节比较。 |
| 源码组成 | src/main.c:主循环、按键与 LED 处理、卡信息打印和缓冲区比较;src/sdcard.c 与 inc/sdcard.h:SDIO 端口初始化、卡上电与识别、块读写、擦除和 DMA 通道配置;inc/main.h:测试地址、块数、DMA 通道与 LED、按键定义;readme.txt:功能、环境与使用说明;MDK-ARM/ 与 EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | SDIO 主机接口,SDIOCLK 为 120 MHz(HCLK/2),初始化分频 298、传输分频 4; CLK 为 PC12、CMD 为 PD2、D0 为 PB4、D1 为 PB0、D2 为 PC10、D3 为 PC11,均配为复用推挽; 时钟上升沿有效、关闭硬件流控、总线宽度 4 位; 读写走 DMA1 通道 1,测试起始地址为 0、块数为 4、块大小为 512 字节; 按键为 PA0,指示 LED 为 PA3。 系统时钟为 240 MHz,打印串口为 PA9,波特率 115200。 |
| 程序与数据路径 | main 初始化日志、LED 与按键后进入循环;按键按下并释放后调用 SD_Init 初始化卡,随后 SD_ShowCardInfo 打印卡信息;依次调用 SD_ReadBlocks、SD_Erase、SD_WriteBlocks 完成读、擦、写,再读回比较;每一步之后都等待 SD_GetCardState 回到传输状态。 |
| 主要 API | SD_Init, SD_GetCardState, SD_ReadBlocks, SD_WriteBlocks, SD_Erase, SDIO_DMACmd |
| 验证方法 | 在卡座中插入 TF 卡,编译下载并复位开发板; 按一下 PA0 触发一轮测试,串口先打印 demo 起始信息与卡信息,再打印读、擦、写各步骤的结果,最后打印 SD/MMC Card test OK!。 |
| 使用提示 | 测试前必须外接 TF 卡座并插入 TF 卡; 读写擦会破坏起始 4 个数据块,测试前请确认该区域没有有用数据; 工具链为 KEIL MDK-ARM 5.34 与 IAR EWARM 8.50.1。 |
核心代码解读与移植
示例在按键触发后用 SDIO 主机接口对 TF 卡做一轮读、擦、写:先按块读回数据,再擦除该区域并写入新的测试数据,最后读回比较。
数据路径: main → SD_Init 配置 SDIO 外设并上电识别卡 → SD_ShowCardInfo 打印卡信息 → SD_ReadBlocks 用 DMA 读回数据 → SD_Erase 擦除区域 → SD_WriteBlocks 写入测试数据 → 再次 SD_ReadBlocks 读回比较 → SD_GetCardState 等待卡回到传输状态
1. 配置引脚与外设。 SD_PortInit 打开 SDIO 各引脚的 GPIO 时钟并把 CLK、CMD、D0~D3 配为复用推挽,SD_Init 再打开 SDIO 时钟、复位寄存器并按初始化分频写入外设参数。
/* SDIO pin config */
GPIO_InitPara.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitPara.GPIO_Slew_Rate = GPIO_SLEW_RATE_FAST;
GPIO_InitPara.GPIO_Pull = GPIO_NO_PULL;
GPIO_InitPara.GPIO_Current = GPIO_DS_12mA;
/* CLK */
GPIO_InitPara.Pin = SD_CLK_PIN;
GPIO_InitPara.GPIO_Alternate = SD_CLK_AF;
GPIO_InitPeripheral(SD_CLK_PORT, &GPIO_InitPara);
/* CMD */
GPIO_InitPara.Pin = SD_CMD_PIN;
GPIO_InitPara.GPIO_Alternate = SD_CMD_AF;
GPIO_InitPeripheral(SD_CMD_PORT, &GPIO_InitPara);
/* D0 */
GPIO_InitPara.Pin = SD_D0_PIN;
GPIO_InitPara.GPIO_Alternate = SD_D0_AF;
GPIO_InitPeripheral(SD_D0_PORT, &GPIO_InitPara);
/* D1 */
GPIO_InitPara.Pin = SD_D1_PIN;
GPIO_InitPara.GPIO_Alternate = SD_D1_AF;
GPIO_InitPeripheral(SD_D1_PORT, &GPIO_InitPara);
/* D2 */
GPIO_InitPara.Pin = SD_D2_PIN;
GPIO_InitPara.GPIO_Alternate = SD_D2_AF;
GPIO_InitPeripheral(SD_D2_PORT, &GPIO_InitPara);
/* D3 */
GPIO_InitPara.Pin = SD_D3_PIN;
GPIO_InitPara.GPIO_Alternate = SD_D3_AF;
GPIO_InitPeripheral(SD_D3_PORT, &GPIO_InitPara);
/* SDIOCLK = HCLK, SDIO_CLK = HCLK/(2 + ClkDiv) */
/* SDIO_CLK for initialization should not exceed 400 KHz */
SDIO_InitPara.ClkDiv = SD_INIT_CLK_DIV;
SDIO_InitPara.ClkEdge = SDIO_CLK_EDGE_RISING;
SDIO_InitPara.ClkBypass = ClockBypass;
SDIO_InitPara.ClkPwrSave = SDIO_CLK_POWER_SAVE_DISABLE;
SDIO_InitPara.BusWidth = SDIO_BUS_WIDTH_1B;
SDIO_InitPara.HardwareClkCtrl = SDIO_HARDWARE_CLKCTRL_DISABLE;
SDIO_Init(&SDIO_InitPara);
/* Set Power State to ON */
SDIO_SetPower(SDIO_POWER_CTRL_ON);
/* Enable SDIO Clock */
SDIO_EnableClock(ENABLE);
初始化阶段使用 1 位总线与不超过 400 kHz 的时钟,等卡识别完成后再切换到传输时钟与 4 位总线。
2. 上电与卡识别。 SD_PowerON 依次发送 CMD0、CMD8 与 CMD55/ACMD41(MMC 卡走 CMD1)完成上电和电压匹配,SD_InitCard 再用 CMD2、CMD3、CMD9、CMD10 取得卡地址与 CID、CSD 信息。
/*Next, send a series of commands to start the card identification process*/
/* CMD0: GO_IDLE_STATE. No CMDCTRL response required */
error = SDIO_CmdGoIdleState();
if (error != SDMMC_ERROR_NONE)
{
/* CMDCTRL Response TimeOut (wait for CMDSEND flag) */
return (error);
}
/* Required power up waiting time before starting the SD initialization sequence */
Delay(SystemCoreClock/1000); /* about 4ms */
/* CMD8: SEND_IF_COND */
/* Send CMD8 to verify SD card interface operating condition */
/* Argument: - [31:12]: Reserved (shall be set to '0')
- [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)
- [7:0]: Check Pattern (recommended 0xAA) */
/* CMDCTRL Response: R7 */
error = SDIO_CmdOperCond();
if (error == SDMMC_ERROR_NONE) // If there is a response, card follows SD protocol version 2.0
{
SDCardInfo.CardVersion = CARD_V2_X;
}
else // No response, indicates 1.X or MMC card
{
SDCardInfo.CardVersion = CARD_V1_X;
}
/* Send cmd55 to detect SD card, MMC card, or unsupported card */
/* If errorstatus is Command TimeOut, it is a MMC card */
/* If errorstatus is SDMMC_ERROR_NONE it is a SD card: SD card 2.0 (voltage range mismatch)
or SD card 1.x */
error = SDIO_CmdAppCommand(0U);
if (error == SDMMC_ERROR_NONE) // Responded to cmd55, SD card, may be 1.X, may be 2.0
{
/*Start to send the voltage range supported by SDIO circularly for a certain number of times*/
/* Send ACMD41 SD_APP_OP_COND with Argument */
while ((!validvoltage) && (count < SDMMC_MAX_VOLT_TRIAL))
{
/* Because acmd41 is ACMD command. So cmd55 must send to card first */
/* SEND CMD55 APP_CMD with RCA as 0 */
error = SDIO_CmdAppCommand(0U);
if (error != SDMMC_ERROR_NONE)
{
return (error); // No response to cmd55, return
}
// acmd41,The command parameters consist of the supported voltage range and HCs bits. The HCS position is
// used to distinguish whether the card is SDSC or SDHC
error = SDIO_CmdAppOperCommand(SDMMC_VOLTAGE_WINDOW_SD | SDMMC_HIGH_CAPACITY);
if (error != SDMMC_ERROR_NONE)
{
return (error); // Acmd41 not received correctly, error, return
}
/*If the card demand voltage is within the supply voltage range of SDIO, it will automatically power on and
* mark PWR UP bit*/
resp = SDIO_GetResp(SDIO_RESPONSE_1);
validvoltage = (resp & SDMMC_CARD_POWER_UP); // Read the PWR up bit of the card's OCR register to see if it is working at normal voltage
count++; // Calculate number of cycles
}
/* CMD2 */
error = SDIO_CmdAllSendCID();
if (SDMMC_ERROR_NONE != error)
{
return (error);
}
CID_Tab[0] = SDIO_GetResp(SDIO_RESPONSE_1);
CID_Tab[1] = SDIO_GetResp(SDIO_RESPONSE_2);
CID_Tab[2] = SDIO_GetResp(SDIO_RESPONSE_3);
CID_Tab[3] = SDIO_GetResp(SDIO_RESPONSE_4);
CMD8 用来确认卡是否支持 2.0 协议,SD 卡必须在 ACMD41 之前发送 CMD8。
3. 切换到传输时钟与 4 位总线。 SD_Init 在识别完成后用传输分频重新配置外设,SD_CofigBusWidth 通过 ACMD6 把卡与本机同时切到 4 位总线。
error = SD_CofigBusWidth(BusWidth);
if (error != SDMMC_ERROR_NONE)
{
/* CMDCTRL Response TimeOut (wait for CMDSEND flag) */
return (error);
}
return (SDMMC_ERROR_NONE);
else if(CARD_SDIO != SDCardInfo.CardType)
{
if (SDIO_BUS_WIDTH_8B == WideMode) // 2.0 SD does not support 8bits
{
return (SDMMC_ERROR_UNSUPPORTED_FEATURE);
}
else if (SDIO_BUS_WIDTH_4B == WideMode) // 4 data line mode
{
error = SD_EnableWideBus(ENABLE); // Use acmd6 to set the bus width and the transmission mode of the card
if (SDMMC_ERROR_NONE != error)
{
return error;
}
SDIO_InitPara.BusWidth = SDIO_BUS_WIDTH_4B;
SDIO_Init(&SDIO_InitPara);
}
else // Single data line mode
{
error = SD_EnableWideBus(DISABLE); // Use acmd6 to set the bus width and the transmission mode of the card
if (SDMMC_ERROR_NONE != error)
{
return error;
}
SDIO_InitPara.BusWidth = SDIO_BUS_WIDTH_1B;
SDIO_Init(&SDIO_InitPara);
}
}
总线宽度只能在卡被选中(CMD7)后的传输状态切换,本例把两端都切到 4 位。
4. 用 DMA 读写数据块。 SD_ReadBlocks 与 SD_WriteBlocks 先按块数配置数据通道、发送单块或多块命令,再启动 DMA 通道搬运数据,最后等待 DMA 完成标志与数据结束标志。
/* Config data register */
InitData.DatTimeout = SDMMC_DATATIMEOUT;
InitData.DatLen = NumberOfBlocks * SD_BLOCKSIZE;
InitData.DatBlkSize = SDIO_DATBLK_SIZE_512B;
InitData.TransferDirection = SDIO_TRANSDIR_TOSDIO;
InitData.TransferMode = SDIO_TRANSMODE_BLOCK;
InitData.DPSMConfig = SDIO_DPSM_ENABLE;
SDIO_ConfigData(&InitData);
/* Send command for reading */
if(NumberOfBlocks > 1U)
{
error = SDIO_CmdReadMultiBlock(ReadAddr);
}
else
{
error = SDIO_CmdReadSingleBlock(ReadAddr);
}
if(error != SDMMC_ERROR_NONE)
{
/* Clear all the static flags */
SDIO_ClrFlag(SDIO_STATIC_FLAGS);
return (error);
}
#if defined(SD_DMA_MODE)
SD_DMA_RxConfig((uint32_t*)ReadBuf, ((NumberOfBlocks * SD_BLOCKSIZE)/4));
SDIO_DMACmd(ENABLE);
timeout = Timeout;
while(1)
{
if( (DMA_GetFlagStatus(SDIO_DMA_ENDFLAG,SDIO_DMA) == SET)
&&(SDIO_GetFlag(SDIO_FLAG_DATEND) == SET) )
{
break;
}
if(0U == timeout )
{
break;
}
else
{
timeout--;
}
}
SDIO_DMACmd(DISABLE);
if(0U == timeout )
{
/* Clear all the static flags */
SDIO_ClrFlag(SDIO_STATIC_FLAGS);
return (SDMMC_ERROR_TIMEOUT);
}
#if defined(SD_DMA_MODE)
SD_DMA_TxConfig((uint32_t*)SrcBuf, ((NumberOfBlocks * SD_BLOCKSIZE)/4));
SDIO_DMACmd(ENABLE);
timeout = Timeout;
while(1)
{
if( (DMA_GetFlagStatus(SDIO_DMA_ENDFLAG,SDIO_DMA) == SET)
&&(SDIO_GetFlag(SDIO_FLAG_DATEND) == SET) )
{
break;
}
if(0U == timeout )
{
break;
}
else
{
timeout--;
}
}
SDIO_DMACmd(DISABLE);
if(0U == timeout )
{
/* Clear all the static flags */
SDIO_ClrFlag(SDIO_STATIC_FLAGS);
return (SDMMC_ERROR_TIMEOUT);
}
数据长度按“块数 × 512 字节”写入数据控制寄存器,DMA 搬完由结束标志退出等待。
5. 擦除与主循环校验。 SD_Erase 先按卡类型换算地址并发送 CMD32、CMD33 与 CMD38,主循环在每一步之后查询卡状态,再读回写入的数据逐字节比较。
if( (SDCardInfo.CardType == CARD_SDHC_SDXC) \
||(SDCardInfo.CardType == CARD_MMC_HC) ) // The address of the high capacity card is block(512bytes) number, not byte address
{
StrAddr /= 512;
EndAddr /= 512;
}
if( (SDCardInfo.CardType == CARD_MMC_HC) \
||(SDCardInfo.CardType == CARD_MMC_LC) )
{
/* Send CMD35 MMC_ERASE_GRP_START with argument as addr */
error = SDIO_CmdEraseStartAdd(StrAddr);
}
else if(SDCardInfo.CardType != CARD_SDIO)
{
/* Send CMD32 SD_ERASE_GRP_START with argument as addr */
error = SDIO_CmdSDEraseStartAdd(StrAddr);
}
else
{
error = SDMMC_ERROR_NONE;
}
if(error != SDMMC_ERROR_NONE)
{
/* Clear all the static flags */
SDIO_ClrFlag(SDIO_STATIC_FLAGS);
return (error);
}
if( (SDCardInfo.CardType == CARD_MMC_HC) \
||(SDCardInfo.CardType == CARD_MMC_LC) )
{
/* Send CMD36 MMC_ERASE_GRP_END with argument as addr */
error = SDIO_CmdEraseEndAdd(EndAddr);
}
else if(SDCardInfo.CardType != CARD_SDIO)
{
/* Send CMD33 SD_ERASE_GRP_END with argument as addr */
error = SDIO_CmdSDEraseEndAdd(EndAddr);
}
else
{
error = SDMMC_ERROR_NONE;
}
if(error != SDMMC_ERROR_NONE)
{
/* Clear all the static flags */
SDIO_ClrFlag(SDIO_STATIC_FLAGS);
return (error);
}
/* Send CMD38 ERASE */
error = SDIO_CmdErase();
if(error != SDMMC_ERROR_NONE)
{
/* Clear all the static flags */
SDIO_ClrFlag(SDIO_STATIC_FLAGS);
return (error);
}
/* Initialize the SDIO interface and SD card */
error = SD_Init(SDIO_CLK_BYPASS_DISABLE, SD_TRANSFER_CLK_DIV, SDIO_BUS_WIDTH_4B);
if(error != SDMMC_ERROR_NONE)
{
log_debug("SD/MMC Card initialization failed,error=%d!\r\n",error);
while(1);
}
else
{
log_debug("SD/MMC Card initialization success!\r\n");
}
/* Forth step: Check write result by read and compare */
Memset(RxBuf,0x55U,TEST_BUF_LEN);
error = SD_ReadBlocks(RxBuf,TEST_CARD_ADDR,TEST_BLOCK_NUM,SDMMC_DATATIMEOUT);
if(error != SDMMC_ERROR_NONE)
{
log_debug("SD/MMC Card read after write failed,error=%d!\r\n",error);
while(1);
}
/* Check card state */
while(SD_GetCardState() != SDMMC_CARD_TRANSFER);
/* Check write result */
for(i=0;i<TEST_BUF_LEN;i++)
{
if(RxBuf[i] != TxBuf[i])
break;
}
if(i<TEST_BUF_LEN)
{
log_debug("SD/MMC Card write check fail,i=%d,data=0x%02x!\r\n",i,RxBuf[i]);
while(1);
}
else
{
log_debug("SD/MMC Card write success!\r\n");
}
每一步都等待卡回到传输状态,只有读回数据与写入缓冲完全一致时才打印测试通过。
对应源码: src/main.c、src/sdcard.c
5.24.4 注意与排障
| 场景 | 检查与建议 | 来源 |
|---|---|---|
| 卡的数量 | SDIO 同一时间仅支持一个 SD/SDIO/MMC 4.2 卡; MMC 4.1 及更早版本可以挂接多个。 |
用户手册 |
| 数据总线宽度 | 上电或复位后默认只用 SDIO_DAT0 传数据; MMC V3.31 及更早版本只支持 1 位数据线,4 位或 8 位总线须在主机初始化后自行配置。 |
用户手册 |
| 命令状态机空闲时序 | 命令状态机进出空闲状态时至少保持 8 个 SDIO_CLK 周期,以满足 NCC 与 NRC 时序限制。 | 用户手册 |
| 命令超时 | 命令超时时间固定为 64 个 SDIO_CLK 时钟周期,且不可配置。 | 用户手册 |
| 数据通道等待发送时序 | 数据通道在等待发送状态至少保持 2 个时钟周期,以满足 NWR 时序要求,即从收到卡响应到主机开始传输数据之间的间隔。 | 用户手册 |
| SD 卡初始化顺序 | 初始化 SD 卡时必须在发送 ACMD41 之前先发送 CMD8; 卡识别过程中卡应工作在 FOD(400 kHz)时钟频率下。 |
用户手册 |
| 总线宽度切换时机 | 设置总线宽度的 ACMD6 命令仅在传输状态有效,即必须先用 CMD7 选择卡之后才能改变总线宽度。 | 用户手册 |