一. 简介
本篇文章,将介绍如何编写命令的发送,与响应的接收,这部分代码,这部分代码。
对应所以模式而言,发送与接收的时序都是一样的,所以这部分代码对应所以的eMMC而言,都是通用的。
先来看一下整体的框图,命令模块下包括发送与接收,还是比较容易的。
关注微信公众号 FPGA之旅 回复 eMMC代码V1 获取完整工程,目前支持高速和HS200.HS400有点问题,可能是我PCB的问题。
FPGA驱动eMMC系列(二)-------上电初始化
FPGA驱动eMMC系列(一)-------简介
二. 命令发送
在命令发送模块里面,我们就不关心,命令长什么样,每一位代表什么意思,只需要知道每一条命令的长度,以及如何将其发送出去即可。
模块的接口信号如下,非常简单。当req请求来的时候,模块就会将eMMC_Command发送出去,然后返回一个ack信号,模块接口和UART的比较类似。所有的命令数据,都是在高电平的时候进行采样。
eMMC_CMD_TX( input eMMC_CLK, input rst_n, input eMMC_tx_req, //eMMC 发送请求 output eMMC_tx_ack, //eMMC 发送完成响应 input[47:0] eMMC_Command, //eMMC 发送命令 output eMMC_CMD //eMMC 命令数据 );
三. 响应接收
命令的接收,和串口的接收类型,空闲的时候,eMMC_CMD为高电平,起始信号为一个周期的低电平,同样也是检测到低电平,也就是下降沿,标志响应的起始位。
其中由于响应的大小有两种,48bit和136bit。通过外部eMMC_Response_Size参数控制即可,也是在时钟的上升沿进行采样。
最后将接收到的eMMC_Response,输出出去。内部的写法和串口类型,想要了解的可以看完整代码。
eMMC_CMD_RX( input eMMC_CLK, input rst_n, input eMMC_rx_req, //eMMC 发送请求 output eMMC_rx_ack, //eMMC 发送完成响应 input eMMC_Response_Size, //eMMC 响应大小 0 : 48bit , 1 :136bit output[135:0] eMMC_Response, //eMMC 接收到的响应 先接收高位 input eMMC_CMD //eMMC 命令数据 );
四. 命令整体模块
发送一个命令后,基本上都会有一个响应,有的命令没有响应(广播命令),例如CMD0。所以命令发送接收的过程为 先发送命令,然后再接收响应,为一个完整的过程。
这部分的状态机如下,如果命令的类型为`CMD_Type_BC,说明没有响应,则直接进入END。有些命令发送后,eMMC设备会产生busy信号,将DAT[0]拉低,这个时候需要等待,直到DAT[0]为高,结束本次的发送。
always@(*) begin case (state) S_IDLE: if(eMMC_Cmd_Req == 1'b1) next_state <= S_SEND; else next_state <= S_IDLE; S_SEND: if(eMMC_tx_ack == 1'b1 && eMMC_Cmd_Typei == `CMD_Type_BC) next_state <= S_DONE; else if(eMMC_tx_ack == 1'b1) next_state <= S_RECV; else next_state <= S_SEND; S_RECV: if(eMMC_rx_ack == 1'b1 || eMMC_Response_Timeout == 1'b1) next_state <= S_DONE; else next_state <= S_RECV; S_DONE: if( eMMC_data0 == 1'b1) next_state <= S_IDLE; else next_state <= S_DONE; default: next_state <= S_IDLE; endcase end
五. 完
这部分就到这里,还是比较轻松的,对完整代码有疑问的,或者对eMMC不清楚的,可以通过微信公众号私聊我。
公众号:FPGA之旅