SD_clk
- 测试模式下,选择hclk,将扫描链中的时钟保持一致
- clk_en表示可以通过软硬件关闭时钟
sd_if模块
- 模块中设置一些寄存器,我们可以对寄存器进行读写或者对于寄存器中的某些域段进行读写操作
- 对于AHB总线的协议进行解析,将address phase和data phase进行对齐
- ahb总线信号和sd总线信号进行交互,所以会有跨时钟域设计
sd_clk
- in_clk_divider - 配置信号(几分频)
- in_sd_clk_enbale - 软件使能
- hw_stop_clk - 硬件使能
- out_sd_clk_dft - dft mode下使能
- sd host是用于控制sd card,sd io是更加通用的协议,可以和wifi设备进行交互
- sd host和sd io都需要fifo和dma进行数据缓存和数据搬移,所以fifo和dma可以进行共用,所以fifo时钟会和sd io的时钟进行mux,选择sd clk
- 分频系数为0,表示不分频,选择hclk时钟本身
- 软件停止时钟和硬件停止时钟,只要有一个有效,时钟就不反转,输出0
sd_clk = in_sd_clk || hw_stop_clk ? 1'b0 : sd_clk;
- 测试模式下都时钟外部时钟
sd_cmd_fsm
- 命令发送模块
- 发送命令的时候,时序:首先要发送cmd然后接收response,在发送cmd的时候,sd card有时候会处于busy的状态,sd card在进行写操作和擦除操作的时候,会将data[0]进行拉低,此时card会进入到busy状态,此时不能再发送命令给到card
- 在设计sd_data_fsm的时候,需要判断card是不是处于busy状态,判断data[0]是不是为低的,如果为低就不能发送命令,通过硬件进行识别
- 可以将命令中的start bit/content/crc/end bit设置为一个状态,也可以将命令作为一个整体作为一个状态,具体发送到命令的哪一个部分,通过发送逻辑内部进行解析
sd_cmd_fsm设计思路
- 初始时时IDLE状态,当接收到cpu要发送命令的信号之后,就会进入等待状态,此时判断data[0]是不是为低(判断sd card是不是处于busy状态),data[0] 1的时候,fsm进入到发送状态,当发送完成之后,进入到等待response状态,当cmd总线接收到start bit之后,表示response开始返回数据了,当cmd0的时候(start bit == 0)的时候,开始进入接收response的状态,接收完response之后,进入到IDLE状态
- in_sd_clk - 时钟
- hrst_n - 复位信号,硬复位,直接接到寄存器的异步复位端
- in_soft_reset - 软复位,相当于软件配置的复位端,高电平有效
- 在发送命令之后,有三种情况,一种是没有response,一种是48bit reponse,一种是136bit reponse,不同长度的response的时钟周期是不同的
- in_longresponse - 表示长短response
- in_response - 表示当前命令是否有response
- in_command_ready - 表示cpu让状态机开始进行发送命令了,软件置位,硬件清0,硬件不清0,那么就会再次进行cmd发送,当状态机运转的任何时间点,在回到idle之前对其进行清0
- in_sd_dat - 需要判断data[0]是不是为低,需要data总线输入
- in_sd_cmd - 需要判断response是不是返回,需要cmd总线输入
- has_send_bit - 为了区分当前正在发送start bit/content/crc,所以设置一个表示当前已发送多少bit数据的信号,发送的cmd是48bit,所以使用6bit信号
- has_receive_bit - 为了表示当前正在接收content/crc等,设置接收信号,接收response最多有136bit,所以需要8bit信号
- end_command - 当前cmd发送完成,需要产生中断信号给cpu,表示当前的命令已经发送完成,这个阶段在命令发送阶段就可以产生
- end_command_and_response - 当前cmd发送完成,并且接收到response之后,产生这个信号,这个信号在receive response阶段产生
- response timeout - 超时信号
根据状态机,书写模块的信号,先写状态机,然后再找trigger状态转移的信号,然后在写输入输出信号
sd_cmd_fsm状态转移图
sd_cmd_send_shift_register模块
- 发送数据,按序的将并行的数据转变为串行的数据,最主要的是crc的产生逻辑
- in_current_state - 当前只有在cmd 发送状态,才能使能发送的逻辑
- in_command_index - 6bit表示cmd的index,这个是cmd中所含有的部分,1bit(start bit)+1bit+6bit(index)+32bit(argument)+7bit(crc)+1bit(end bit)
- in_command_argument - 32bit
- in_has_send_bit - 表示当前发送多少位
- out_sd_cmd - sd cmd输出
- out_cmd_dir - 输出方向,三态总线需要两个信号控制,一个控制方向,一个控制当前的发送数据,如果当前正在进行cmd命令的发送,out_cmd_dir应该拉高,在其他状态下为0
- 每次输出一位之后,都将数据左移一位,次高位移动到最高位进行输出
功能描述
- 产生cmd总线的方向控制:只有在命令发送状态,的时候输出
- 产生crc校验码,并附带在命令之后,发送出去
sd_cmd_receive_shift_register
- in_current_state - 表示当前状态,根据当前的状态判断是否需要进行接收数据
- in_serial_cmd - response也是在cmd线上进行接收的,需要cmd总线的输入,此时host只进行采样
- in_has_receive_bit - 表示当前接收了多少bit
- in_longresponse - 表示前接收48bit还是136bit response
- out_cmd_receive_crc_error - 接受命令出错
- reponse0,1,2,3
- 边接收数据,边产生crc,然后进行crc的比较,软件可查
- 串行数据转变为并行数据
sd_data_fsm模块
- data传输表示读和写
\
sd_data_fsm状态机设计
读状态机设计
-
开始的时候sd host处于idle状态,等待start bit是不是到来,表示开始读数据,在等待start bit之前可以设置一个状态判断是不是已经接收结束了,如果结束了,可以直接回到idle状态,如果没有结束就可以直接进入到等待接收状态,接收start bit,接收data,接收crc,接收end bit,然后返回idle状态
-
是否能将content和crc合并在一起?
-
receive data,data的数据长度是不同的,根据block length进行接收的,block length是可配置的,receive data的时间取决于block length和data bus宽度决定的
-
cmd总线只有1bit,data bus可以是1bit的,也可以用4bit
-
content和crc如果合并在一起,状态机的转移计算比较玛法
-
receive crc - crc总是16bit,可以单独计算crc的时间
写状态机设计
-
总线控制权交换需要缓冲,所以需要两个周期的缓冲,所以出现两个z
-
可以根据host返回的状态进行设计
-
z - 表示不对总线进行驱动
-
p - 表示对总线上拉,发送1
-
s - 表示发送start bit 发送0
-
对于写操作,首先发送z,然后发送p,然后发送s(start bit),发送data(content),发送crc,然后发送end bit(这里end bit中包含两个z,总线控制权交换的时间),然后可以接收crc,等待busy结束,可以增加一个状态表示当前是不是已经结束了(send end,对于sd host是send),单个block 写,就回到idle状态,如果多个block写,会进行下一次传输
-
读的时候,data线之后进行接收
-
写操作的时候,开始的时候sd host会通过data线发送数据,当数据发送完成之后,会通过data线接收crc的status,返回的crc status表示sd card是否准确无误的接收到sd host发送的数据
-
读写可以设计成两个状态机,也可以合并成一个状态机
-
什么时候进行读操作和什么时候进行写操作是cpu配置好的
-
还可以再增加一个状态,表示进行任务的分发,再idle状态收到一条命令的时候,进入到issue的状态,然后再判断进行读操作和写操作
sd_data_fsm信号
- 时钟复位以及软复位信号
- data_ready - 表示idle状态向issue状态跳转的条件,cpu让状态机启动
- in_sd_data - 写状态机中有wait busy状态,需要判断data[0],所以需要输入data总线,对于读操作,等待接收状态到接收状态跳转需要判断start bit,所以也需要输入data总线
- in_data_direction - 控制读写,可以从issue状态进入到读的状态机或者是写的状态机
- need_to_receive_byte - 设置读的block length
- need_to_send_byte - 设置写的block length
- need_to_recieve_block - 设置需要读取多少个block,用于receive end的判断
- need_to_send_block - 设置需要写多少个block,用于send end的判断
- in_data_width - 数据位宽,receive data和send data两个状态都需要data位宽和block length
- 在wait receive状态的时候,如果时间过长,等待start bit时间过长,就会上报中断或者是错误给到cpu,cpu通常会将硬件复位带idle,然后在重新尝试发送
- in_read_to - host读操作的timeout时间
- current_data - 状态机需要输出当前处于哪个状态,给到data_send和data_receive,这两个模块接收到状态之后,才能进行接收数据或者是发送数据
- send_crc_counter - crc发送了多少bit
- has_send_bit - 表示当前发送了多少bit数据
- out_transfer_compelete - 既可以表示读结束也可以表示写结束
- interval_counter - send end状态的时候,单块block写结束的时候,会发送end bit并且会发送两个z状态,可以使用interval counter表示哪个bit是end bit
- out_read_to_error - 读的时候发生timeout会上报一个错误的标识
- one_bk_re_end - 一个block数据读操作结束状态位,用于硬件停时钟,假设fifo只能存储1block的数据,如果要读取多个block的数据,开始的时候fifo为空,通过一些配置命令之后,会开启多块的读取,对于第一个block的数据读取是没有问题的,第一个block读取的时候会将fifo填满,fifo填满之后,不能进行第二个block的读取,需要dma,将fifo中的数据搬移之后,才能进行下一个block的读取