时序参数全解:洞悉SDIO的tSU、tH、tODLY、tCLK
做SDIO调优,绕不开这几个参数。你去看规范文档,满篇都是tSU、tH、tODLY、tCLK,但到底它们什么意思?取值多少?怎么影响你的板子?今天咱们把这个啃透。
我个人习惯先把协议侧和芯片侧的概念分开。卡有卡的要求,主控有主控的输出。搞混了,调试时就会抓瞎。
1. tSU(Setup Time)——数据必须在时钟前站好
tSU是卡对主控的要求:在时钟采样沿到来之前,CMD/DAT线上的数据必须稳定下来。说白了,数据得提前“就位”。
取值范围呢?我翻了下SDIO 2.0和3.0规范,给你个直觉:
| 模式 | 典型tSU(最小值) | 备注 |
|---|---|---|
| Default Speed (0–25 MHz) | 5 ns | SDIO 2.0 基本要求 |
| High Speed (25–50 MHz) | 3 ns | 上升沿采样,更紧 |
| UHS‑I SDR12/SDR25 | 1.6 ns | 1.8V 信号,时序更严 |
| UHS‑I SDR50/DDR50 | 0.8 ns | 极限情况,几乎没冗余 |
2. tH(Hold Time)——时钟沿之后别急着变
tH 和 tSU 是孪生兄弟。它要求数据在时钟采样沿之后还要维持一段时间。为什么会这样?因为卡内部触发器需要一点点时间来锁存数据,数据变太快,锁不住。
曾经有个项目,高速读写时随机丢包。我用示波器抓,setup 裕量很大,hold 时间却贴着底线。原来是走线等长没做好,某根数据线比时钟短了太多,导致 hold 违例。嗯,调了走线后问题解决。
典型 tH 取值范围(最小值):
- Default Speed:2.5 ns
- High Speed:1.5 ns
- UHS‑I SDR12/SDR25:0.8 ns
- UHS‑I SDR50/DDR50:0.4 ns
3. tODLY(Output Delay)——卡吐出数据要多久
tODLY 是卡侧的参数:从时钟的有效沿到卡内数据出现在引脚上的时间。主控靠这个来推算采样窗口。
这个参数对主控的 RX 时序设计至关重要。比如卡说 tODLY(max) 是 14 ns,时钟周期 20 ns(50 MHz),那么主控必须在时钟沿之后至少等 14 ns 才能采样,否则可能采到旧数据。
不同速率下的典型 tODLY:
- Default Speed:tODLY(max) ≈ 14 ns
- High Speed:tODLY(max) ≈ 7 ns
- UHS‑I SDR50:tODLY(max) ≈ 1.8 ns
- UHS‑I DDR50:tODLY(max) ≈ 1.4 ns
数值越来越小,说明卡内部响应更快。但也意味着主控的采样窗口更窄,调起来更费劲。
4. tCLK(时钟周期与频率)——节奏决定一切
tCLK 就是时钟周期,或者倒过来叫时钟频率。SDIO 规范里对 tCLK 有限制:最小周期对应最大频率。但别忘了还有占空比要求,一般45%–55%之间。
取值速查:
| 模式 | 最大频率 | 最小周期 | 占空比要求 |
|---|---|---|---|
| Default Speed | 25 MHz | 40 ns | 40%–60% |
| High Speed | 50 MHz | 20 ns | 45%–55% |
| UHS‑I SDR50 | 100 MHz | 10 ns | 45%–55% |
| UHS‑I DDR50 | 50 MHz (DDR) | 20 ns (等效) | 45%–55% |
我碰过最奇葩的案子:芯片手册写支持50 MHz,但实际波形占空比只有38%。一测,卡直接不响应。调了时钟源的 duty 后恢复正常。所以说,别只盯着频率,占空比也要看。
5. 时序关系一张图
下面这张 SVG 把四个参数的关系画出来了。CLK 作为基准,数据信号上标出 tSU、tH、tODLY 的位置。你琢磨一下:主控发数据要看 tSU、tH(满足卡要求);卡发数据回来,主控要看 tODLY 和 tCLK。
6. 实际调优中的经验法则
光知道参数值不够,还得会用。我总结几条实战心得:
- Always 留余量:tSU/tH 至少多 50%,tODLY 按 max 算。
- 温度是敌人:高温下 I/O 驱动变弱,setup 会变差。 我在高低温箱里吃过亏——常温跑得好好的,85°C 就随机挂。
- 走线等长:时钟和数据的走线长度差尽量控制在 5mm 以内,否则 skew 吃掉 tSU 或 tH。
- 用 delay chain 微调:FPGA 里调用 IDELAY/ODELAY,Software 里调整采样相位,效果立竿见影。
# 计算 setup 裕量(示例)
freq_mhz = 50 # 时钟频率
tclk = 1000 / freq_mhz # ns
tsu_req = 3.0 # 卡要求 3 ns
tsu_actual = 5.2 # 实际测量或仿真值
setup_margin = tsu_actual - tsu_req
print(f"Setup margin: {setup_margin:.2f} ns")
if setup_margin < 1.5:
print("⚠️ 裕量偏小,建议优化")
好了,参数全解就聊到这儿。记住:tSU、tH、tODLY、tCLK 这四个数字,是你和 SDIO 卡沟通的密码。下回调时序时,心里先过一遍这张图,多半能少跳几个坑。