SDIO初始化流程

对STM32的SDIO——SD卡输入/输出模块摸索了一下,今天只看了POWER UP这个函数的实现。对SDIO编写驱动,需要参考SD卡的协议,我手上的SD卡协议是ver2.00的物理层简化协议。协议主要规定了主机(这里就是STM32)向SD卡写入的各种控制指令,以及SD卡的初始化过程状态转移图。了解SD卡从初始化状态转移图开始。

 这个图看起来有点复杂,感觉无从下手,其实仔细瞧瞧就跟我们数电学的状态转移图差不多,框框里面是各种操作,箭头指向下一步操作,直线引出去的部分就是状态发生跳转的条件。首先上电(power-on),然后发出CMD0,再接着发送CMD8,有应答(response)判断为Ver2.00或更新的SDMC,无应答(no response)判断为ver2.00或者更新版SDMC(电压不匹配(voltage mismatch) )或ver1.X SDMC或不是SDMC。若判断为前一种情况,则问询是否为有效应答(valid response),如果不是,判断为无效卡,否则判断为有效卡且开始循环发送ACMD41指令直至SD卡发出power up应答。然后判断CCS(card capacity status——卡容量状态)位,为1则判断为ver2.00或者更新的大容量卡(high capacity SD memory card),否则判断为ver2.00或者更新的标准卡(sandard capacity SD memory card)。至此,power on工作结束。

上文只是对状态图进行了一个解读,真正要控制还是需要知道各个CMD如何发送。SD卡协议提供了几个CMD的格式以及其响应值的格式(如果有相应的话)。下面就对函数的具体编写进行下总结。

(1)初始化SDIO

利用SDIO_Init中的结构体初始化SDIO接口。该结构体有以下几个成员函数:SDIO_ClockDiv、SDIO_ClockEdge、SDIO_ClockBypass、SDIO_ClockPowerSave、SDIO_BusWide、SDIO_HardwareFlowControl。其中比较重要的是SDIO_ClockDiv成员,它确定了SDIO的分频系数,在不使用旁路时钟(ByPass)的时候SDIO_CLK=HCLK/(SDIO_ClockDiv+2),我们在这里将SDIO_CLK设置为400kHZ,就是通过设置分频系数实现的。初始化完成后,就进行第一步,也就是power on,调用SDIO_SetPowerState函数即可。最后别忘记使能SDIO的时钟。

(2)发送CMD0

由STM32向SD卡发送指令可以直接调用SDIO_SendCommand函数,该函数包含一个结构体,该结构体有以下几个成员:SDIO_Argument、SDIO_CmdIndex、SDIO_Response、SDIO_Wait、SDIO_CPSM。跟我们编程密切相关的一个是SDIO_Argument——参数,许多带有响应的命令都需要通过设置参数来实现,由于CMD0没有响应,所以此处设为0x00即可。SDIO_CmdIndex成员是该结构体核心——指令指数。也就是说,如果我要发送CMD0,SDIO_CmdIndex=0,如果发送ACMD41,SDIO_CmdIndex=41,但是注意此处SDIO_CmdIndex的值是等于指令,而且是指令的十进制形式,但是我们在给SDIO_CmdIndex赋值时必须转换成十六进制。SDIO_Wait设置等待中断。填写好结构体后检测是否正确受到CMD0,然后才能进行下一步。为了保证程序正确,这样的检测在每一个指令发送周期都是必须的。

(3)发送CMD8

用同样类似的方式发送CMD8。注意此时CMD8是带有响应的指令,接收到指令后sd返回该SDIO_Argument的值,所以对SDIO_Argument要进行特殊设置,设置后SDIO->ARG寄存器便有了该值。SDIO_Response——把应答模式设置成短应答,这是根据参考指南设置的。同样地,在填写完结构体后检查是否接收到命令。根据SD协议初始化流程图,此时如果有响应则SD遵循2.00协议,否则说明是1.x 或者mmc。无论是哪一种情况,都发送CMD55来检测。

(4)发送CMD55

CMD55是一个特殊的指令,该指令告诉主机下一个command将会是一个应用指令(application command),比如要发送ACMD41之前必须先发送CMD55。此处发送CMD55是为了检测卡的类型。不过暂时没没看懂为什么是发送CMD55,因为关于CMD55的解释中并没有提到它能够检测卡类型,只说了它的应答类型是R1。判断是SD卡或者是不支持的卡。

(5)进入循环,再次发送CMD55

这次发送CMD55就是为发送ACMD41做准备了。为什么要在循环里发送呢?因为SD协议初始化状态图中发送ACMD的过程是一个反复地,指导检测出power up为1为止,所以该处的循环条件设置成!validvoltage,validvoltage为OCR的power up位。需要注意的是例程中的循环条件是(!validvoltage) && (count < SD_MAX_VOLT_TRIAL),也就是说它设置了一个最大检测次数,当超过该检测次数仍然没有power up时就可以跳出,反馈检测失败的信息,这样程序不会死在此处。

(6)发送ACMD41

发送了CMD55后检测到收到指令,紧接着发送ACMD41指令。ACMD41响应类型是R3,该响应返回OCR寄存器的值,稍后我们需要这个寄存器来判断卡容量以及power up状态。注意此处参数格式规定的是HCS和Voltage Window共同确定的。填写完结构体后检查是否正确接收指令,然后检测power up位是不是1,不是的话再次循环,是则根据条件跳出循环。如果达到最大循环次数power up仍然没置位,则返回卡不可用的信息。

(7)检测卡的最终类型

正常上电好后,检测OCR的CCS为,一次来判断卡是SDHC还是SDSC。至此,power on函数功能到此结束。

猜你喜欢

转载自blog.csdn.net/T19900/article/details/129547817