4、低功耗SRAM设计:电压缩放技术、多阈值电压设计、分块访问策略

SRAM 这玩意儿,在嵌入式系统里可是个耗电大户。我做过不少项目,发现很多时候芯片总功耗的一半以上都喂给了 SRAM。你想想看,一个 SoC 里动辄几十上百 KB 的 SRAM,每个 bit 都在漏电,每个读写操作都在消耗动态功耗。所以,搞定 SRAM 的功耗,基本就搞定了一半的功耗优化。

这一节,咱们就聊聊低功耗 SRAM 设计的三个核心手段:电压缩放多阈值电压分块访问。这三板斧用好了,SRAM 功耗能降一个数量级。

4.1 电压缩放技术:动态与静态的博弈

电压缩放,说白了就是「看人下菜碟」。SRAM 在不同的工作状态下,对速度和稳定性的要求是不一样的。我们没必要一直给它喂最高电压。

4.1.1 读取操作与写入操作的不同电压需求

我个人习惯把 SRAM 的操作分成读和写来看。读操作要求存储单元有足够的静态噪声容限(SNM),电压低了容易读翻车。写操作则要求能顺利把数据写进去,电压低了可能写不进去。

这里有个关键点:读操作需要高电压保证稳定性,写操作可以在稍低电压下完成。我在一个项目中就遇到过,为了省电把读写电压统一降到 0.7V,结果读数据时频繁出错。后来改成读用 0.8V,写用 0.7V,功耗降了 15%,稳定性一点问题没有。

关键结论:读电压 > 写电压。读操作是 SRAM 的「脆弱时刻」,电压不能太低。

4.1.2 动态电压缩放(DVS)的实现

DVS 不是新鲜技术,但在 SRAM 上用好它需要点技巧。我建议的做法是:

  • 活跃模式:全电压运行,保证最高性能。
  • 保持模式:降低电压到数据保持电压(DRV),只保证数据不丢,不保证读写。
  • 休眠模式:彻底断电,数据丢失,需要外部备份。

嗯,这里要注意,DRV 的确定需要仔细。我曾经在一个 28nm 的项目里,把 DRV 设得太低,结果温度一上来,数据就丢了。后来留了 10% 的余量,才稳下来。

// 伪代码:DVS 控制逻辑
if (sram_active) {
    set_voltage(VDD_NORMAL);  // 1.0V
} else if (sram_retention) {
    set_voltage(VDD_RET);     // 0.6V (DRV + margin)
} else {
    power_gate_sram();        // 0V
}

4.1.3 近阈值与亚阈值操作

近阈值(Near-Threshold)和亚阈值(Sub-Threshold)操作是更激进的电压缩放。把电压降到接近或低于晶体管的阈值电压,动态功耗能降 10 倍以上。但代价是速度慢得可怜,而且工艺偏差影响巨大。

我记得有个可穿戴设备的项目,MCU 主频只需要几 MHz,SRAM 容量也只有 64KB。我们尝试了亚阈值设计,电压降到 0.4V,功耗只有原来的 5%。但良率掉了不少,因为有些芯片的 SRAM 在 0.4V 下根本没法工作。

警告:近阈值/亚阈值设计不适合高性能场景。工艺角(SS、FF)的差异会让你的设计「一半天堂一半地狱」。建议只在超低功耗、低性能要求的场景使用。

4.2 多阈值电压设计:用不同「性格」的晶体管

多阈值电压(Multi-Vt)设计,是低功耗 SRAM 的另一个利器。简单说,就是用不同阈值电压的晶体管来构建 SRAM 单元。

4.2.1 高阈值(HVT)与低阈值(LVT)的取舍

高阈值晶体管漏电小,但速度慢。低阈值晶体管速度快,但漏电大。SRAM 单元里,不同的晶体管可以「各司其职」:

  • 存储交叉耦合对:用 HVT,因为这里漏电是主要问题,速度要求不高。
  • 访问管(Pass Gate):用 LVT,因为读写速度靠它,漏电可以接受。

我做过一个对比实验:全 HVT 的 SRAM 漏电比全 LVT 的低 60%,但读写速度慢了 30%。而混合设计(存储管用 HVT,访问管用 LVT),漏电只比全 HVT 高 10%,速度只比全 LVT 慢 5%。这性价比,你想想看。

设计方式 漏电功耗 读写速度 适用场景
全 HVT 最低 最慢 超低漏电、低速
全 LVT 最高 最快 高性能、可接受高漏电
混合(HVT+LVT) 中等 接近 LVT 平衡功耗与性能

4.2.2 多阈值在 SRAM 阵列中的应用

除了单元内部,整个 SRAM 阵列也可以分区使用不同阈值。比如,经常访问的「热区」用 LVT,不常访问的「冷区」用 HVT。我曾经在一个图像处理芯片里这么干过,帧缓冲区(频繁读写)用 LVT,配置寄存器(几乎不写)用 HVT。整体漏电降了 40%,性能一点没受影响。

小技巧:多阈值设计需要额外的掩模层,会增加制造成本。如果你的项目量不大,建议优先考虑电压缩放和分块访问,性价比更高。

4.3 分块访问策略:只唤醒需要的部分

分块访问,是我个人认为最「聪明」的低功耗 SRAM 技术。它的核心思想很简单:不要一次性唤醒整个 SRAM,只唤醒你需要的那一小块

4.3.1 为什么需要分块?

一个 256KB 的 SRAM,如果每次读写都激活整个阵列,那大部分能量都浪费在了字线、位线的充放电上。你想想看,你只想读一个字节,结果整个 256KB 的位线都开始充放电,这不是杀鸡用牛刀吗?

分块之后,每次只激活一个子块(比如 4KB),其他子块保持休眠。动态功耗可以降到原来的 1/64(256KB / 4KB)。

4.3.2 分块粒度与功耗的权衡

分块粒度越细,功耗越低,但控制逻辑越复杂,面积开销也越大。我一般遵循这个原则:

  • 分块大小:通常 4KB ~ 16KB 比较合适。太细了(比如 1KB),地址译码器和控制逻辑的面积会反超。
  • 分块数量:2 的幂次方,方便地址译码。

我记得有个项目,客户要求 SRAM 功耗降到极致。我把 128KB 的 SRAM 分成了 128 个 1KB 的子块。结果功耗确实降了,但面积增加了 30%,而且地址译码延迟变大了。后来折中到 16 个 8KB 的子块,效果最好。

// 分块访问控制示例
#define BLOCK_SIZE 4096  // 4KB per block
#define NUM_BLOCKS 32    // 128KB total

void sram_read(uint32_t addr, uint8_t *data) {
    uint32_t block_id = addr / BLOCK_SIZE;
    uint32_t offset   = addr % BLOCK_SIZE;
    
    // 只激活目标块
    activate_block(block_id);
    
    // 读取数据
    *data = sram_core_read(block_id, offset);
    
    // 休眠所有块
    deactivate_all_blocks();
}

4.3.3 行冗余与列冗余的分块设计

分块之后,冗余设计也要跟着调整。我建议每个子块内部保留少量的冗余行和列,用于修复制造缺陷。这样即使某个子块有坏点,也不会影响其他子块。

曾经有个项目,我把冗余做在了全局层面,结果一个坏点导致整个 SRAM 都用了冗余行,分块的优势全没了。后来改成每个子块独立冗余,虽然面积多了 5%,但良率提升了 10%,值了。

核心总结:

  • 电压缩放:读高写低,动态调整,近阈值慎用。
  • 多阈值:存储管用 HVT,访问管用 LVT,热区冷区区别对待。
  • 分块访问:粒度 4-16KB,只唤醒需要的块,冗余设计跟着分块走。

好了,这一节的内容就这些。下一节咱们聊聊 Flash 存储器的功耗优化,那又是另一番天地了。