Step to memory 007 DRAM的封装

原文在 https://www.bit-tech.net/reviews/tech/memory/the_secrets_of_pc_memory_part_2/4/

这篇介绍了 DRAM 的封装,对于BIOS工程师来说,稍微了解一下即可

当行业从 SDR 转向 DDR 后,内存芯片的封装设计发生了显著变化。一些常见的 DRAM 封装包括薄型小外形封装 (TSOP)、芯片级封装 (CSP)、薄型四方扁平封装 (LQFP) 和球栅阵列 (BGA)。DDR中最常用的封装包括 BGA 或 TSOP 的变体,其中 TSOP 在 DDR1 中更常用,而当前的 DDR2 和 DDR3 标准则采用 FBGA,不同 DRAM 制造商之间的封装差异很小。

不同尺寸的 FBGA 样品
来源: Spansion Memory

FBGA 的主要优势包括高密度、更好的散热性能以及更短的连接器,从而减少信号失真。需要注意,这里提到的 FBGA 与Fortified  BGA (强化BGA)不是同一种东西,后者是一种加强 BGA强度的技术。

LAB-Z 注释:先说一下FBGA。来自【参考1】

BGA(球栅阵列)是一种将球形焊料(焊球)以网格图案排列在封装底面上的封装。

间距有1.27mm、1.0mm、0.8mm、0.75mm、0.65mm、0.5mm、0.4mm等。

BGA前添加英文字母,会改变“封装安装高度”和“引脚间距”等。例如“ L ”表示封装安装高度L为“ 1.20 mm < 高度L ≦ 1.70 mm ”。因此,BGA前面带“L”的“LBGA”是封装安装高度为“1.20mm<高度L≦1.70mm”的SOP。

与QFP(四方扁平封装)相比,BGA具有以下优点和缺点。

优点

  • 由于不存在引线变形的风险,印刷电路板上不易发生安装缺陷,从而可以更高效地进行安装工作。
  • 由于封装周围没有引线,因此可以做得更小。也就是说,可以提高封装密度。
  • 可高密度排列端子。
  • 由于引线电感较小,适合于高速LSI封装。

缺点

  • 一旦焊接,由于无法看到内部状况,因此很难修复。
  • 无法从外部检查焊接状况。
  • 由于无法进行手工焊接,因此必须在回流炉中完成焊接。
  • 拆卸元件时需要重新加热电路板,并且根据BGA封装后处理中安装的元件的耐热性,可能无法修复。
  • 由于封装和电路板的热膨胀系数不同,对于在通电时会产生热量的BGA封装来说,反复的热膨胀和收缩会导致封装或电路板变形,从而导致焊点破裂并造成断线。

FBGA

BGA前面的“ F ”代表“细间距”

通过添加“ F ”,引脚间距缩短如下。

关于引脚间距

  • 如果基本封装是BGALGAFBGAFLGA),引脚间距为0.8mm或更小
  • 当基本封装为QFP ( FQFP)时,引脚间距为0.5mm或更小

因此,“FBGA(Fine-pitch BGA)”是指引脚间距为0.8mm或更小的BGA

总结:FBGA是 BGA 封装的一种,比普通的 BGA 底部引脚间距更小。

这里再介绍一下强化BGA(Fortified  BGA)

BGA-PCB焊点应力

如果芯片底部的连接器较短,且呈网格状排列,则在热胀冷缩循环过程中,会导致每个引脚或焊球之间的应力不均匀。当 DRAM 相对于所连接的印刷电路板 (PCB) 升温且膨胀速率不同时,就会发生这种情况。PCB和 DRAM 芯片之间的不同膨胀速率会对焊球施加应力,并可能导致连接断裂 – 这就是为什么用户不应将 DRAM 电压升至高于规格的原因之一,除非采取了额外的措施来保持内存冷却。更高的电压会产生更多的热量,并以更快的速度降低内部 DRAM 电路的性能。OCZ(FlexXLC、Reaper、ReaperX)和 Corsair(DHX、Dominator)的某些内存模块采用先进的散热技术,可减少热循环过程中 DRAM 和 PCB 之间的差异。

OCZ 和 Corsair 验证其 PCB 散热技术有效性的方法是,让模块长时间承受极端温度循环,然后用 X 射线检查 DRAM 球连接处是否有断裂。这是一个极其耗时的过程,也是超频玩家需要牢记的要点之一。

OCZ 和 Corsair 为 FBGA DRAM 提供专用 PCB 冷却 资料
来源: OCZ Technology 和 Corsair Memory

如前所述,BGA技术的另一种变体被称为强化BGA。顾名思义,它通过强化连接点来提高DRAM在热循环(从热到冷,反之亦然)中的可靠性。DRAM芯片底部的焊球直径与焊点在温度循环过程中的可靠性成正比。直径越大,可靠性越高——这也是某些内存模块能够耐受更高温度的原因之一。

内存模块制造商经常使用 X 射线技术检查从生产批次中抽取的样品,以查找异常焊点。BGA连接不易从各个角度接触,因此需要使用 X 射线、在线测试和专用显微镜等先进的成像技术。X射线图像可以从各个角度拍摄,以验证 DRAM 芯片与底层 PCB 之间的连接是否正确。成像解决方案的最新进展可以与符合 RoHS(《限制在电气和电子设备中使用某些有害物质指令》)规定的无铅焊膏配合使用,同时提供计算机生成3D细节。

BGA X射线检测
来源: STL Electronics

常见的BGA缺陷包括焊点桥接、焊点缺失、错位和焊点开路。质量控制流程通常通过光学识别软件实现自动化。机器会尝试检测诸如焊点桥接、过多空隙、焊点直径不规则或球形焊点等缺陷。所有制造商都使用上述X射线技术的变体。

BGA焊球 – 边缘颜色较深的圆环表示润湿性良好,亮点表示空洞。
数据来源: Phoenix/X-ray GmbH

焊点中的空隙或气泡被认为是有害的,但在制造过程中极难避免,通常将其控制在总连接量的一定百分比以下。空隙过大会导致焊点缺焊,并损害连接几何形状。BGA 焊点中过多的空隙会在热循环过程中削弱接触力,从而缩短内存模块的使用寿命。

其他手动检查流程包括使用功能验证、内部电路测试仪 (ICT) 和专用探针。有时,会使用“最高放大倍数斜视图”(OVHM) X 射线技术代替典型的倾斜法,从一定角度检查焊球,而不会降低放大倍数。

LAB-Z注释: SMT 厂商是否能够对产品进行X光检测可以作为考察SMT能力的标准。我接触过的一搏科技和一些厂商都有这样的能力。SMT 完成之后,直接用X光检查,能够确保SOC焊接的可靠性。

参考:

1. https://detail-infomation.com/package-types-bga/

关于 PCB/应力/芯片不良的问题,感受最深的恐怕就是微软了。

微软公司在2005年11月推出游戏主机Xbox360后,众多用户曾向微软方面投诉游戏主机经常出现不同程度的故障,而且几率偏高。有调查显示,早期版本Xbox360返修率高达68%,而2007年7月的报告指出故障几率还是有33%。

三个红色灯光形成一个环形,绰号为“三红”(Red Ring of Death)。

微软随后将游戏主机三红故障部分保修期由一年延长至三年,但其他故障问题仍维持在一年保修。微软声称将于新推出的版本主机改进制造工艺。【参考2】

在花费了十几亿美元之后,微软终于搞清楚产生的原因是GPU 芯片本身。简单的说是基片、封胶几个部件的膨胀系数都不一样,封胶在高温下还有软化的趋向。这样导致出厂之后不同材料之间存在着应力,相互拉扯。用户在使用过程中热胀冷缩加剧了这种现象,最终导致内部封装的焊料失效。更详细的解释可以在【参考3】看到。

2.https://zh.wikipedia.org/wiki/Xbox_360%E6%95%85%E9%9A%9C%E5%95%8F%E9%A1%8C

3.https://www.zhihu.com/question/340045804/answer/2638540514

CH55xduino CH554 DataFlash 使用的例子

CH554内置了128字节的 DataFlash ,掉电不会丢失,方便写入

这里展示了如何在 Ch55xDuino 环境下使用 DataFlash。

#ifndef USER_USB_RAM
#error "This example needs to be compiled with a USER USB setting"
#endif

#include "src/CdcHidCombo/USBCDC.h" 
#include "DataFlash.H"

uint8_t lastValue;
      
void setup() {
  USBInit();
  // 读取
  Flash_Op_Check_Byte1 = 0x00;
  Flash_Op_Check_Byte2 = 0x00;
  ReadDataFlash(0,1,&lastValue);
  lastValue++;
  
  // 写入
  Flash_Op_Check_Byte1 = DEF_FLASH_OP_CHECK1;
  Flash_Op_Check_Byte2 = DEF_FLASH_OP_CHECK2;
  WriteDataFlash(0,&lastValue,1);

}

void loop() {
  USBSerial_println(lastValue-1);
  delay(3000);
}

实现的效果是:插入Ch554 ,打开 USB串口可以看到输出的数字。拔掉之后再次插入,输出的是前一次加一的数字。

FANGXIANG SSD 太垃圾

做测试借了一个崭新的,没开封PCIE5 2T 的NVME, 品牌是 Fanxiang。发现无法在 PCIE 5 上写入数据(读取可以)。但是在 PCIE 4 Port上面可以读写。猜测这是一个“假的PCIE 5 NVME”。

很多年前还被 Foresee 这个牌子的 M.2 SSD 坑过,它不支持 DEVSLP ,然后我用它测试 ModernStandby 一直搞不定。

Web Serial 的例子

一个简单的 Web Serial 的例子,页面上有两个按钮,一个是选择串口号,另外一个是连接串口之后按下会发送”Hello World!” 到这个串口。

<!DOCTYPE html>
<html>
<body>
    <button id="connectBtn">连接串口</button>
    <button id="sendBtn" disabled>发送 hello world</button>
</body>
<script>
    let port;  // 存储串口实例

    // 连接串口按钮事件
    document.getElementById('connectBtn').addEventListener('click', async () => {
        try {
            port = await navigator.serial.requestPort();
            await port.open({ baudRate: 9600 });  // 设置波特率
            document.getElementById('sendBtn').disabled = false;
        } catch (error) {
            console.error("端口打开失败:", error);
        }
    });

    // 发送按钮事件
    document.getElementById('sendBtn').addEventListener('click', async () => {
        if (!port?.writable) return;
        
        const writer = port.writable.getWriter();
        const encoder = new TextEncoder();
        
        try {
            await writer.write(encoder.encode('hello world!\r\n'));  // 发送数据
        } finally {
            writer.releaseLock();  // 释放写入器
        }
    });
</script>
</html>

ASCII 数字的例子

之前的文章【参考1】,介绍了 ASCII 的字体,这次用这个实现在 Console 下显示数值。使用 VS2019 VC 编译通过。

运行结果如下:

测试代码如下:

// AsciiFontTest.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <windows.h>  // 必须包含头文件
#include <iostream>

// 字体宽度
#define DOHWIDTH  20
#define DOHHEIGHT 16

// 定义二维数组,每行预留足够空间
char DOH[10][DOHHEIGHT*10][DOHWIDTH+1] = {
// char "0"
{
"     000000000      ",
"   00:::::::::00    ",
" 00:::::::::::::00  ",
"0:::::::000:::::::0 ",
"0::::::0   0::::::0 ",
"0:::::0     0:::::0 ",
"0:::::0     0:::::0 ",
"0:::::0 000 0:::::0 ",
"0:::::0 000 0:::::0 ",
"0:::::0     0:::::0 ",
"0:::::0     0:::::0 ",
"0::::::0   0::::::0 ",
"0:::::::000:::::::0 ",
" 00:::::::::::::00  ",
"   00:::::::::00    ",
"     000000000      "
},
// char "1"
{
"       1111111      ",
"      1::::::1      ",
"     1:::::::1      ",
"     111:::::1      ",
"        1::::1      ",
"        1::::1      ",
"        1::::1      ",
"        1::::l      ",
"        1::::l      ",
"        1::::l      ",
"        1::::l      ",
"        1::::l      ",
"     111::::::111   ",
"     1::::::::::1   ",
"     1::::::::::1   ",
"     111111111111   "
},
// char "2"
{
" 222222222222222    ",
"2:::::::::::::::22  ",
"2::::::222222:::::2 ",
"2222222     2:::::2 ",
"            2:::::2 ",
"            2:::::2 ",
"         2222::::2  ",
"    22222::::::22   ",
"  22::::::::222     ",
" 2:::::22222        ",
"2:::::2             ",
"2:::::2             ",
"2:::::2       222222",
"2::::::2222222:::::2",
"2::::::::::::::::::2",
"22222222222222222222",
},
// char "3"
{
" 333333333333333    ",
"3:::::::::::::::33  ",
"3::::::33333::::::3 ",
"3333333     3:::::3 ",
"            3:::::3 ",
"            3:::::3 ",
"    33333333:::::3  ",
"    3:::::::::::3   ",
"    33333333:::::3  ",
"            3:::::3 ",
"            3:::::3 ",
"            3:::::3 ",
"3333333     3:::::3 ",
"3::::::33333::::::3 ",
"3:::::::::::::::33  ",
" 333333333333333    ",
},
// char "4"
{
"        444444444   ",
"       4::::::::4   ",
"      4:::::::::4   ",
"     4::::44::::4   ",
"    4::::4 4::::4   ",
"   4::::4  4::::4   ",
"  4::::4   4::::4   ",
" 4::::444444::::444 ",
" 4::::::::::::::::4 ",
" 4444444444:::::444 ",
"           4::::4   ",
"           4::::4   ",
"           4::::4   ",
"         44::::::44 ",
"         4::::::::4 ",
"         4444444444 ",
},
// char "5"
{
" 555555555555555555 ",
" 5::::::::::::::::5 ",
" 5::::::::::::::::5 ",
" 5:::::555555555555 ",
" 5:::::5            ",
" 5:::::5            ",
" 5:::::5555555555   ",
" 5:::::::::::::::5  ",
" 555555555555:::::5 ",
"             5:::::5",
"             5:::::5",
" 5555555     5:::::5",
" 5::::::55555::::::5",
"  55:::::::::::::55 ",
"    55:::::::::55   ",
"      555555555     ",
},
// char "6"
{
"         66666666   ",
"        6::::::6    ",
"       6::::::6     ",
"      6::::::6      ",
"     6::::::6       ",
"    6::::::6        ",
"   6::::::6         ",
"  6::::::::66666    ",
" 6::::::::::::::66  ",
" 6::::::66666:::::6 ",
" 6:::::6     6:::::6",
" 6:::::6     6:::::6",
" 6::::::66666::::::6",
"  66:::::::::::::66 ",
"    66:::::::::66   ",
"      666666666     ",
},
// char "7"
{
"77777777777777777777",
"7::::::::::::::::::7",
"7::::::::::::::::::7",
"777777777777:::::::7",
"           7::::::7 ",
"          7::::::7  ",
"         7::::::7   ",
"        7::::::7    ",
"       7::::::7     ",
"      7::::::7      ",
"     7::::::7       ",
"    7::::::7        ",
"   7::::::7         ",
"  7::::::7          ",
" 7::::::7           ",
"77777777            ",
},
// char "8"
{
"      888888888     ",
"    88:::::::::88   ",
"  88:::::::::::::88 ",
" 8::::::88888::::::8",
" 8:::::8     8:::::8",
" 8:::::8     8:::::8",
"  8:::::88888:::::8 ",
"   8:::::::::::::8  ",
"  8:::::88888:::::8 ",
" 8:::::8     8:::::8",
" 8:::::8     8:::::8",
" 8:::::8     8:::::8",
" 8::::::88888::::::8",
"  88:::::::::::::88 ",
"    88:::::::::88   ",
"      888888888     "
},
// char "9"
{
"      999999999     ",
"    99:::::::::99   ",
"  99:::::::::::::99 ",
" 9::::::99999::::::9",
" 9:::::9     9:::::9",
" 9:::::9     9:::::9",
"  9:::::99999::::::9",
"   99::::::::::::::9",
"     99999::::::::9 ",
"          9::::::9  ",
"         9::::::9   ",
"        9::::::9    ",
"       9::::::9     ",
"      9::::::9      ",
"     9::::::9       ",
"    99999999        "
}
};

// 计算 n 的位数
// 比如: 123 返回2, 1 返回0
int count_digits(int n) {
    // 处理特殊情况:0的位数为1
    if (n == 0) return 0;  // [^1]

    int count = 0;
    n = abs(n);  // 处理负数

    while (n != 0) {
        n /= 10;  // 每次循环移除最后一位
        count++;
    }
    return count-1;
}

/**
 * @brief 获取整数指定位的数字
 * @param v 目标整数(支持负数)
 * @param index 位索引(0表示个位,1表示十位,依此类推)
 * @return int 对应位的数字(0-9)
 *
 * @example
 * GetValueOf(1234, 0) -> 4
 * GetValueOf(-987, 2) -> 9
 */
int GetValueOf(int v, int index) {
    if (index < 0) return 0;  // 非法索引处理
    v = abs(v);               // 处理负数情况[^1]

    long long divisor = 1;    // 使用long long防止溢出
    for (int i = 0; i < index; ++i) {
        divisor *= 10;
        if (divisor > INT_MAX) return 0; // 大索引保护机制[^2]
    }

    return (v / divisor) % 10;
}

char* Int2Ascii(int value) {
    // 计算最终的宽度
    int StrWitdh = (count_digits(value)+1) * DOHWIDTH + 1; // 最后加入回车换行字符

    char *str =(char*) malloc(StrWitdh * DOHHEIGHT + 1); //末尾使用 \0 作为标记
    if (str == NULL) {
        return NULL;
    } else  memset(str, '*', StrWitdh * DOHHEIGHT + 1);
    str[StrWitdh * DOHHEIGHT + 1 - 1] = NULL;

    // 赋值换行
    for (int i = 1; i < DOHHEIGHT+1; i++) {
        str[i * StrWitdh - 1] = '\n';
    }

    // 从 Value 的最高位开始搬移
    for (int i = 0; i<count_digits(value)+1; i++)
    {
        printf("GetValueOf[%d,%d]=%d\n", value, count_digits(value) - i, GetValueOf(value,count_digits(value)-i));
        for (int j = 0; j < DOHHEIGHT; j++) {
            memcpy(&str[j* StrWitdh+ DOHWIDTH*i], &DOH[GetValueOf(value, count_digits(value)-i)][j][0], DOHWIDTH);
            //printf("copy DOH[%d][%d][0] > str[%d]\n", GetValueOf(value, count_digits(value) - i), j, j * StrWitdh + DOHWIDTH * i);
           
        }
    }


    
    return str;
}
int main()
{
    for (int i = 0; i < 100; i++) {
        char* p = Int2Ascii(i);
        printf("%s\r\n", p);
        free(p);
        Sleep(500);
    }        
    
}

参考:

1.https://www.lab-z.com/asciiart/

Step to memory 006 DDR外形和自刷新

继续之前的话题,这里来到了《内存的秘密 第二部分》

https://www.bit-tech.net/reviews/tech/memory/the_secrets_of_pc_memory_part_2/1

第一章 紧凑型 DDR

SO-DIMM(小外形双列直插式内存模块,small outline dual in-line memory module)是最常见的移动内存类型:其尺寸几乎是标准 DIMM 的一半,并且不同代之间的连接引脚数量也有所不同。它最常用于笔记本电脑、嵌入式系统、打印机和高端网络设备。除此之外紧凑型和移动型 DDR 还有其他外形尺寸,包括 Mini DIMM 和 Micro DIMM,其区别如下表所示。

引脚数量

尺寸

移动 DDR(例如采用 SO-DIMM 外形尺寸的 DDR)具有一些动态功率调节功能,可以降低自身功耗降尽可能的延长待机时间。这些功能包括部分阵列自刷新 (Partial Array Self-Refresh ,PASR)、温度补偿自刷新 (Temperature Compensated Self-Refresh,TCSR) 和深度省电 (Deep Power Down,DPD)。移动内存设计人员需要努力平衡功耗与性能关系。

个别 DRAM 制造商可能也拥有专有的节能技术,例如,Elpida Memory 就拥有一项名为超级自刷新 (Super Self-Refresh,SSR) 的技术,可将 DDR1 自刷新电流降低 95%。【注释:SSR 是一种新型电路技术,它与嵌入式纠错电路 (ECC) 协同工作,显著延长了内部刷新间隔。ECC 会在退出自刷新周期时检查并纠正数据。SSR 功能取代了传统 SDRAM 中常见的自刷新功能。SSR 利用片上温度传感器(通常称为自动温度补偿自刷新 (ATCSR)),自动调整自刷新时间,以补偿内部温度变化。这是 2005年的技术。】
为了理解移动内存功耗的本质,我们只需使用如下基本公式:

总功率=核心功率+IO功率

DDR GDDR和 移动DDR 内存功耗比较

需要注意的是:DIMM和SO-DIMM使用的DDR芯片通常都是相同的。此外,还有一种 LPDDR (Low Power Double Data Rate SDRAM)的内存芯片,这种和 DDR 芯片差异较大需要特别注意。

DRAM自刷新技术

即使在没有读取数据时,内存(RAM) 也需要持续进行刷新以保持电容器中的电荷。因为DRAM使用电容器来记录数据,其中的电荷会随着时间的推移逐渐泄漏。为了确保数据的可靠必须进行刷新操作,这个操作简单的说就是对于电容再次充电。

这是 RAM (易失性存储器)与非易失性存储器(例如,只读存储器 ROM 或闪存NAND 或 NOR)的主要区别。在笔记本电脑和手持设备等移动设备中,这种自刷新特性不断改进,努力降低功耗,从而延长设备的待机时间。

以下章节介绍了移动 DDR 使用的四种不同的节能方法。

  1. 温度补偿自刷新
  2. 部分阵列自刷新
  3. 深度断电
  4. 时钟停止模式

当计算机处于休眠或睡眠模式时,在关闭自刷新功能之前,内存内容会被复制到硬盘驱动器,这样内存不消耗电力同时数据也得到了保存。

温度补偿自刷新 (TCSR)

温度补偿自刷新技术在各种内存上都有使用。当DRAM 进行刷新操作时,功耗会增加。此外执行刷新操作时无法进行读写操作。因此,从技术角度厂商都在想办法降低内存刷新的频率。

DDR1 和 DDR2只有一种自刷新模式,而 DDR3 则增强了这项技术,新增了两种温度敏感型自刷新模式。当 DDR3 温度低于 85˚C (185˚F) 时,刷新间隔设置为 7.8µs。如果工作温度介于 85˚C (185˚F) 和 95˚C (203˚F) 之间,则刷新间隔需要降至 3.9µs(速度提高一倍)。

该技术基于以下原理:DRAM 保留数据的时间与工作温度直接相关。较高的温度会导致 DRAM 因电荷泄漏而更快地丢失数据。因此,温度升高后需要增加刷新频率才能保证数据不丢失。

当温度较低时,自刷新周期可以更长,根据这个特性,当 DDR3 在 85˚C (185˚F) 以下运行时,降低刷新频率可以在功耗方面节省近 50%。对于台式机内存模块,因为通常有足够的的空间进行散热, DIMM 的温度很少会超过 60˚C (140˚F)。不同DRAM 制造商的刷新间隔可能略有不同 , 这取决于各个公司使用的电路和芯片制造技术,但这种差异也可能导致移动内存和设备 BIOS 之间的一些兼容性问题。一些制造商也可能根据他们放置或使用温度传感器的位置而略微不同地实现此功能;有些温度传感器位于片上或 DIMM 上,前者专门检测内存核心温度,而位于DIMM 上的传感器更多用于检测环境温度。

部分阵列自刷新 (Partial Array Self-Refresh ,PASR)

DRAM 芯片内部包含由列和行构成的内存条,类似于 Microsoft Excel 等电子表格程序中的工作表。PASR 技术预先编程了 DRAM 的某些自刷新行为,用于寻址这些列和行,以降低功耗。

例如:

  • 完整阵列:组 0、1​​、2 和 3
  • 半阵列:组 0 和 1
  • 1/4 阵列:Bank 0
  • 1/8 阵列:Bank 0,行地址 MSB = 0
  • 1/16 阵列:Bank 0,行地址 MSB 和 MSB-1 均等于零

为了降低自刷新期间的功耗,移动 DDR 可以选择性刷新某些bank中的数据而不刷新其他bank。

部分阵列自刷新示意图 来源:Elpida Memory

不同 的PASR 配置对应的不同电流消耗 来源:Micron Technology

当需要刷新的阵列数量较少时,自刷新电流会下降;但当温度升高时,电流消耗会自动增加,因为阵列需要更频繁地刷新。为此,PASR功能通常使用芯片内部嵌入的热传感器来确定其精确温度。

深度断电 (Deep Power Down , DPD)

在深度掉电模式下,内部电源关闭,所有刷新操作暂停。因此,进入深度掉电模式后数据将无法保留。
在正常运行情况下,单个活动存储体的功耗通常低于 80mA。进行刷新操作时,功耗约为正常运行时的三倍,但在深度掉电模式下,电流消耗降至约 10µA。

自刷新和深度断电模式概述 来源: Elpida Memory

时钟停止模式 (Clock Stop Mode)

此功能通过减少时钟路径上的转换来降低功耗。镁光科技称,主要有两种方法可以实现此目的:

  • 当数据传输需要不同的速度时,改变时钟频率
  • 在整个时钟停止模式期间,保持 CKE 为高电平,CK 为低电平,CK 为高电平

所采用的方法取决于具体产品的要求。移动 DDR 内存可以在运行过程中更改时钟频率,但只有在满足所有时序和内存刷新要求的情况下才可以这样做。
根据 JEDEC 的规定,在以下条件下甚至可以完全停止时钟:

  • 最后一个命令(ACTIVE、READ、WRITE、PRECHARGE、AUTO REFRESH 或 MODE REGISTER SET)已执行完成,包括读取突发期间的任何数据输出;每个访问命令的时钟脉冲数取决于设备的 AC 时序参数和时钟频率。
  • 相关时序条件(tRCD、tWR、tRP、tRFC、tMRD)已满足。
  • CKE 处于高位。

时钟停止模式的进入和退出 来源: JEDEC

XML 本地格式化工具

最近在研究 KML文件(也是一种XML格式),忽然发现很多工具都是在线的,使用起来并不顺手,因此编写一个本地的 XML 格式化工具。能够帮助将KML变成容易阅读的格式。

使用方法:

XMLLocalFormatter 输入文件名

之后会生成一个“输入文件名_for.XML”的新文件。

代码如下:

#include <iostream>
#include <fstream>
#include <string>
#include "tinyxml2.h"

using namespace std;
using namespace tinyxml2;

int main(int argc, char* argv[]) {
    if (argc != 2) {
        cerr << "Usage: xml_formatter input_file" << endl;
        return EXIT_FAILURE;
    }

    string inputFile = argv[1];

    // Load the XML file using TinyXML2.
    XMLDocument doc;
    XMLError error = doc.LoadFile(inputFile.c_str());
    if (error != XML_SUCCESS) {
        cerr << "Error loading file: " << inputFile << ". Error code: " << error << "." << endl;
        return EXIT_FAILURE;
    }

    // 查找最后一个 '.' 的位置以分离扩展名
    size_t dotPosition = inputFile.find_last_of('.');
    if (dotPosition == std::string::npos || dotPosition == 0) {
        std::cerr << "Invalid file name format.\n";
        return 1;
    }

    // 构造新的文件名
    std::string baseName = inputFile.substr(0, dotPosition);
    std::string extension = inputFile.substr(dotPosition);

    std::string newFileName = baseName + "_for" + extension;
    const char* output = newFileName.c_str();

    // Use PrettyPrint option for formatting.
    doc.SaveFile(output,false);

    cout << "Formatted XML saved successfully to: " << newFileName << endl;

    return EXIT_SUCCESS;
}

运行:

左边是格式化之前的,右边是格式化之后的

有需要的朋友可以试试。

可执行程序(建议自行编译):

源代码工程:

Intel xHCI

xHCI 是 eXtensible Host Controller Interface Controller的缩写。简单的理解这个是一个 USB Host控制器,能连接外部的诸如USB键盘鼠标U盘等等USB Device ,进行数据的交互传输等等。

例如,在【参考1】描述如下:

The eXtensible Host Controller Interface (xHCI) allows data transfer speed up to 10 Gb/s for USB 3.2 Gen 2×1 ports, and 5 Gb/s for USB 3.2 Gen 1×1 ports. The xHCI supports SuperSpeed USB 10 Gbps, SuperSpeed USB 5 Gbps, High-Speed (HS), Full-Speed (FS) and Low-Speed (LS) traffic on the bus. The xHCI supports USB Debug port on all the USB ports. The xHCI also supports USB Attached SCIS Protocol (UASP).

其中提到了USB Attached SCIS Protocol (UASP),我查了一下资料【参考2】:

UAS(USB Attached SCSI)是一种位于SCSI协议框架下传输层的一种协议,其作用是通过基于USB的应用层协议约定,将SCSI的协议数据(Protocol Data Unit)用USB进行封装,从而实现使用USB物理连接进行SCSI协议通信的方式。

UAS实际上定义了两个规范,第一个是规定UAS本身使用方式的USB Attached SCSI,另一个是定义了UAS设备类型的Universal Serial Bus Mass Storage Class - USB Attached SCSI Protocol (UASP)。

大约的意思是:这个接口可以驱动符合 USB 协议个U盘这种,走 USB mass Storage 协议。此外,还可以直接走 SCSI 协议。后者传输速度更快效率更高(我个人理解)。这种有点像 ThunderBolt 的 TypeC 接口,可以输出视频信号,但是实现方法有两种:1.USB协议 2.DP 协议。Type-C 内部有一个Mux(切换)芯片,如果发现对方设备握手是一个显示器,那么就直接将DP的视频信号输出,实际上工作的是 Intel 显卡。

上述都是个人理解,如有不妥,欢迎指出。


参考:

1.https://edc.intel.com/content/www/us/en/design/ipla/software-development-platforms/client/platforms/tiger-lake-mobile-y/intel-500-series-chipset-family-on-package-platform-controller-hub-datasheet-v/003/extensible-host-controller-interface-xhci-controller/

2.https://blog.csdn.net/polley88/article/details/130845520