SDK2.0之SDIF驱动分析

SD_WriteBlocks如何最终调用host.transfer来进行command和data的传输

D_WriteBlocks—(block 计算)—>SD_Write—>card->host.transfer(card->host.base, &content)

fsl_sd.c
SD_SendRca content.data = NULL;
SD_SwitchFunction content.data = &data;
SD_SendScr content.data = NULL;
SD_SetDataBusWidth content.data = NULL;
SD_SendCsd content.data = NULL;
SD_AllSendCid content.data = NULL;
SD_ApplicationSendOperationCondition content.data = NULL;
SD_SendInterfaceCondition content.data = NULL;
SD_Read content.data = &data;
SD_Write content.data = &data;
SD_Erase content.data = NULL;

整体总结一下SDCARD MMCARD的传输过程

SD_ReadBlocks—>transfer的过程

SD_ReadBlocks
SD_WriteBlocks
SD_EraseBlocks
这些函数先进行block的处理然后调用
SD_Read
SD_Write
SD_Erase
这些函数里就会配置具体的命令和数据,然后用指针card->host.transfer(card->host.base, &content) 来实现调用Transfer函数。
content.command = &command;
content.data = &data;

Transfer函数的处理过程:

先进行DMA和IRQ的配置:
如果用IRQ就用SDIF_TransferNonBlocking函数,然后执行EVENT_Wait进行等待;EVENT_Wait其实就是等待传输完成触发中断(中断函数里会EVENT_Notify(kEVENT_TransferComplete); 也就是告知传输完成这件事件;)
如果没用IRQ就用SDIF_TransferBlocking函数,这里面肯定有一个do while循环等待的;

完成非阻塞发送命令后,要等待发送完成。这是就需要执行EVENT_Wait来进行等待。
EVENT_Wait函数退出有两种情况:

  • 最大发送允许时间到了。
  • 发送完成Callback函数SDIF_TransferCompleteCallback里执行SDIF_TransferCompleteCallback;告诉EVENT_Wait函数可以退出了。

SDIF_TransferNonBlocking; SDIF_TransferBlocking 的处理过程

SDIF_TransferNonBlocking(也就是有IRQ),如何不用DMA,进行数据的传输的???
SDIF_TransferNonBlocking 里面在这种情况下只会执行SDIF_SendCommand,但是我们配置了IRQ,当Com发送完成后会产生中断,会进入中断函数,这在下面的文件中
fsl_sdif.c SDIF_TransferHandleIRQ
因为之前我们有配置对应的寄存器(IRQ noDMA)所以这里会自动产生kSDIF_DataTransferStatus这个状态标识,你在中断处理函数里判断出这个标识之后用FIFO再去发送接受数据就好了。详见SDIF_TransferHandleData函数。

fsl_sd.c里的库函数分两部分

a.直接调用fsl_sdmmmc.c里的(这是SD和MMC通用的)

static status_t inline SD_SelectCard(sd_card_t *card, bool isSelected)
{
    assert(card);

    return SDMMC_SelectCard(card->host.base, card->host.transfer, card->relativeAddress, isSelected);
}

static status_t inline SD_WaitWriteComplete(sd_card_t *card)
{
    assert(card);

    return SDMMC_WaitWriteComplete(card->host.base, card->host.transfer, card->relativeAddress);
}

static status_t inline SD_SendApplicationCmd(sd_card_t *card)
{
    assert(card);

    return SDMMC_SendApplicationCommand(card->host.base, card->host.transfer, card->relativeAddress);
}

static status_t inline SD_GoIdle(sd_card_t *card)
{
    assert(card);

    return SDMMC_GoIdle(card->host.base, card->host.transfer);
}

static status_t inline SD_StopTransmission(sd_card_t *card)
{
    assert(card);

    return SDMMC_StopTransmission(card->host.base, card->host.transfer);
}



static status_t inline SD_SetBlockSize(sd_card_t *card, uint32_t blockSize)
{
    assert(card);

    return SDMMC_SetBlockSize(card->host.base, card->host.transfer, blockSize);
}

sdmmSDMMC_SelectCard
SDMMC_WaitWriteComplete
SDMMC_SendApplicationCommand
SDMMC_SetBlockCount
SDMMC_GoIdle
SDMMC_StopTransmission
SDMMC_SetBlockSize

/! @brief SD/MMC card common commands /
typedef enum _sdmmc_command
{
kSDMMC_GoIdleState = 0U, /!< Go Idle State /
kSDMMC_AllSendCid = 2U, /!< All Send CID /
kSDMMC_SetDsr = 4U, /!< Set DSR /
kSDMMC_SelectCard = 7U, /!< Select Card /
kSDMMC_SendCsd = 9U, /!< Send CSD /
kSDMMC_SendCid = 10U, /!< Send CID /
kSDMMC_StopTransmission = 12U, /!< Stop Transmission /
kSDMMC_SendStatus = 13U, /!< Send Status /
kSDMMC_GoInactiveState = 15U, /!< Go Inactive State /
kSDMMC_SetBlockLength = 16U, /!< Set Block Length /
kSDMMC_ReadSingleBlock = 17U, /!< Read Single Block /
kSDMMC_ReadMultipleBlock = 18U, /!< Read Multiple Block /
kSDMMC_SendTuningBlock = 19U, /!< Send Tuning Block /
kSDMMC_SetBlockCount = 23U, /!< Set Block Count /
kSDMMC_WriteSingleBlock = 24U, /!< Write Single Block /
kSDMMC_WriteMultipleBlock = 25U, /!< Write Multiple Block /
kSDMMC_ProgramCsd = 27U, /!< Program CSD /
kSDMMC_SetWriteProtect = 28U, /!< Set Write Protect /
kSDMMC_ClearWriteProtect = 29U, /!< Clear Write Protect /
kSDMMC_SendWriteProtect = 30U, /!< Send Write Protect /
kSDMMC_Erase = 38U, /!< Erase /
kSDMMC_LockUnlock = 42U, /!< Lock Unlock /
kSDMMC_ApplicationCommand = 55U, /!< Send Application Command /
kSDMMC_GeneralCommand = 56U, /!< General Purpose Command /
kSDMMC_ReadOcr = 58U, /!< Read OCR /
} sdmmc_command_t;

发送以上command都会调用transfer(base, &content)

b.独立定义的。

SD_Read            
SD_Write                
SD_Erase     

sdif_Handle学习

typedef struct _sdif_handle
{
/* Transfer parameter */
sdif_data_t volatile data; /!< Data to transfer */
sdif_command_t volatile command; /!< Command to send */
/* Transfer status */
volatile uint32_t interruptFlags; /!< Interrupt flags of last transaction /
volatile uint32_t dmaInterruptFlags; /!< DMA interrupt flags of last transaction/
volatile uint32_t transferredWords; /!< Words transferred by polling way /
/* Callback functions */
sdif_transfer_callback_t callback; /!< Callback function */
void userData; /!< Parameter for transfer complete callback */
} sdif_handle_t;

void SDIF_DriverIRQHandler(void)
{
assert(s_sdifHandle[0]);
s_sdifIsr(SDIF, s_sdifHandle[0]);
}
上面这个s_sdifHandle是哪儿来的,什么时候设定好的?

a.
一个是在创建IRQ handler (Sdif 模块的系统向量入口函数SDIF_DriverIRQHandler内需要调用跳转的具体的处理函数;以及这个跳转处理函数需要传入的结构体参数 s_sdifHandle[0]) ,将callback成员赋值到handle中。

/* Load SDIF and SD configuration */
void SetTestConfig(const test_config_t *config)
{
if (config->enableTransferIRQ)
{
/* Set callback for SDHC driver. */
sdifCallback.TransferComplete = SDIF_TransferCompleteCallback;
/* Create handle for SDHC driver */
SDIF_TransferCreateHandle(BOARD_SDIF_BASEADDR, &g_sdifHandle, &sdifCallback, NULL);
}
}

void SDIF_TransferCreateHandle(SDIF_Type *base,
sdif_handle_t *handle,
sdif_transfer_callback_t *callback,
void *userData)
{
assert(handle);
assert(callback);
/* reset the handle. */
memset(handle, 0U, sizeof(*handle));
/* Set the callback. */
handle->callback = callback;
handle->userData = userData;
/* Save the handle in global variables to support the double weak mechanism. */
s_sdifHandle[SDIF_GetInstance(base)] = handle;
/* save IRQ handler */
s_sdifIsr = SDIF_TransferHandleIRQ;
/* enable the global interrupt */
SDIF_EnableGlobalInterrupt(base, true);
EnableIRQ(s_sdifIRQ[SDIF_GetInstance(base)]);
}

b.
给g_sd这个结构体赋值具体的数据传输方式函数(DMA,polling,。。。),这个数据传输方式函数里会调用
SDIF_TransferNonBlocking或SDIF_TransferBlocking,
这两个函数会对s_sdifHandle这个结构体的几个成员有不同的处理。

/* Load SDIF and SD configuration */
void SetTestConfig(const test_config_t *config)
{
/* Save host information. */
card->host.base = BOARD_SDIF_BASEADDR;
card->host.sourceClock_Hz = CLOCK_GetFreq(BOARD_SDIF_CLKSRC);
if ((config->enableTransferIRQ) && (config->enableAutoCommand12))
{
card->host.transfer = SDIF_TransferInterruptAutoCommand12;
}
else if ((config->enableTransferIRQ) && !(config->enableAutoCommand12))
{
card->host.transfer = SDIF_TransferInterruptNoAutoCommand12;
}
}

/* User defined transfer function with auto command12 enabled. */
status_t SDIF_TransferInterruptAutoCommand12(SDIF_Type *base, sdif_transfer_t *content)
{
do
{
error = SDIF_TransferNonBlocking(base, &g_sdifHandle, &dmaConfig, content);
} while (error == kStatus_SDIF_SyncCmdTimeout);
}

status_t SDIF_TransferNonBlocking(SDIF_Type *base,
sdif_handle_t *handle,
sdif_dma_config_t *dmaConfig,
sdif_transfer_t *transfer)
{
assert(NULL != transfer);
sdif_data_t *data = transfer->data;
/* save the data and command before transfer */
handle->data = transfer->data;
handle->command = transfer->command;
handle->transferredWords = 0U;
handle->interruptFlags = 0U;
handle->dmaInterruptFlags = 0U;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值