DFRobot ESP32 P4 音频框架

ESP32 官方的 USB 框架是 TinyUSB, 这次带来的是使用 TinyUSB 在 IDF 下实现的虚拟USB麦克风。
代码内置了一个正弦波的采样数据,录音机打开之后会送出:

/*
 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

#include <stdio.h>
#include <math.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "usb_device_uac.h"
#include "sine.h"

static const char *TAG = "usb_uac_main";

int audiobuffer=0;

static esp_err_t uac_device_output_cb(uint8_t *buf, size_t len, void *arg)
{
    //size_t bytes_written = 0;
    //bsp_extra_i2s_write(buf, len, &bytes_written, 0);
	ESP_LOGE(TAG, "ocb");
    return ESP_OK;
}

static esp_err_t uac_device_input_cb(uint8_t *buf, size_t len, size_t *bytes_read, void *arg)
{
	
	for (int i=0;i<len;i++) {
		buf[i]=AudioData[(audiobuffer+i)%AUDIOLEN];
	}
	audiobuffer=(audiobuffer+len)%AUDIOLEN;
ESP_LOGE(TAG, "icb");
*bytes_read=len;
    return ESP_OK;
}

static void uac_device_set_mute_cb(uint32_t mute, void *arg)
{
    ESP_LOGI(TAG, "uac_device_set_mute_cb: %"PRIu32"", mute);
    //bsp_extra_codec_mute_set(mute);
}

static void uac_device_set_volume_cb(uint32_t volume, void *arg)
{
    ESP_LOGI(TAG, "uac_device_set_volume_cb: %"PRIu32"", volume);
    //bsp_extra_codec_volume_set(volume, NULL);
}

void app_main(void)
{
uart_config_t uart_config = {
	.baud_rate = 2000000,
	.data_bits = UART_DATA_8_BITS,
	.parity= UART_PARITY_DISABLE,
	.stop_bits=UART_STOP_BITS_1
};

uart_param_config(UART_NUM_0,&uart_config);

    uac_device_config_t config = {
        .output_cb = uac_device_output_cb,
        .input_cb = uac_device_input_cb,
        .set_mute_cb = uac_device_set_mute_cb,
        .set_volume_cb = uac_device_set_volume_cb,
        .cb_ctx = NULL,
    };

    uac_device_init(&config);
}

工作的视频

https://www.bilibili.com/video/BV1a7YizpEdr/?share_source=copy_web&vd_source=5ca375392c3dd819bfc37d4672cb6d54

完整的代码

Step to memory 013利用片上终端 (ODT) 抑制信号噪声

https://www.bit-tech.net/reviews/tech/memory/the_secrets_of_pc_memory_part_3/8

随着主板功能日益丰富,性能不断提升,保持信号完整性也变得越来越困难。当内存速度超过DDR1 之后,DDR1主板采用的电阻式终端方案无法克服信号反射问题。

内存总线频率的提升会降低信号的冗余度。压缩程度越高、电压越低的信号,其本质就越弱。虽然数据选通 (DQS)无法消除所有的抖动,但是这种设计能够减小波形边缘负面影响。

和DDR1相比,DDR2将终端电阻 (ODT)从主板上移入了内存芯片中。这样能够提高信号质量保证完整性。这不仅带来了其他好处,还降低了主板制造商的材料和测试成本。意外信号可能会从有源或无源元件反弹,但只有像 DRAM 这样的有源元件会受到不利影响。ODT 可以消除芯片级读写操作期间总线上信号回波的负面影响。

讽刺的是,如果端接过于有效,当内存时序不准确时,数据信号可能会被吸收——超频有时会导致这种数据截断内存错误。

某些主板的BIOS允许用户手动调整ODT的电阻特性,范围在50、75或150欧姆之间。根据JEDEC规范,在某些平台上,DDR2-667及更高版本的内存必须使用50欧姆。

要确定您的内存模块是否支持50欧姆,可以使用名为SPDTool的程序查看预定义的内存性能值和特性。主板设计人员需要根据各种ODT配置正确模拟和测试读写信号质量,以找到最佳数据眼孔径的要求。

模拟过程可能非常繁琐且耗时,因为它们需要根据主板阻抗和ODT设置的组合,针对不同插槽配置的众多内存模块收集数据眼孔径数据。这也是廉价主板只有两个插槽的部分原因。

片外驱动器 (OCD) 校准

DDR2 使用片外驱动器校准来提高数据和数据选通之间的跟踪精度。OCD 校准电路用于在内存初始化过程中设置 DDR2 驱动器的阻抗和电压电平。它的重要性体现在以下几个方面:

  • OCD 通过最小化数据选通 (DQS) 到数据 (DQ) 的偏差来提高信号质量。
  • 它通过最大限度地减少过冲和欠冲问题来提高信号质量。
  • 它通过 IO 驱动器电压校准吸收来自每个 DRAM 供应商的工艺变化。

OCD 的驱动器阻抗调整引擎使用一种状态机:对此最基本的解释是,状态机是一种在任何给定时间存储组件状态的设备。

为了检测最佳内存设置,系统会根据不同的但预先确定的配置值发送多个测试信号。测试完成后,将使用提供最佳信号质量的值。最佳DQS波形可提供最大的数据眼图区域,同时将抖动、过冲和下冲降至最低。如果经过适当的调整和激活,它可以扩展系统时序裕度,从而有助于改善整体信号特性。JEDEC

的DDR2规范文档指出,如果不使用OCD校准,则在上电和初始化过程中将采用默认参数。一些制造商并不认为这是DDR2的必要功能,并且通常将其保留为默认值以节省设计成本和时间。这可能是导致某些DDR2 800MHz(及更快)内存出现问题的一个因素。

驱动性能/驱动强度和过渡时间 Drive Performance/Drive Strength and Transition Time

驱动器性能与转换时间成正比。驱动器性能越高,内存低电压状态和高电压状态之间的转换时间就越短(或越快)。驱动器性能有时也称为“驱动强度”或“边沿速率”。

上图可以看到:驱动能力越强,信号的斜率越大,越快到达波峰/波谷

只有当电压上升或下降幅度设置在特定水平之间时,信号才能被正确读取。转换时间是指从低电压 (VIL) 变为高电压 (VIH) 状态或从高电压 (VIH) 变为低电压状态所需的时间。因此,转换时间越快,电压上升和下降的速度就越快。

更强的驱动性能会使波形上升部分的电压更快地上升。相反,它会迫使波形下降部分的电压更快地下降。需要注意的是,驱动性能功能应用于许多领域,通常来说,这个概念相当普遍,但不应将其混淆为特定设备或领域中单一因素的代表。

在某些主板中,内存子系统的许多方面都允许用户更改各种驱动强度值。将驱动性能设置过强可能会产生破坏性的过冲和下冲效应,从而与将其设置过低一样危及数据完整性。

想象一下一辆汽车上下坡:你把油门踏板踩得越深,汽车爬坡越快。同样,下坡时踩下踏板会使下坡更快。

这代表着汽车驱动性能的提升。那么,如果你过度增加驱动强度,到达山顶或山脚会发生什么?你会超过顶峰,四个轮子会离开地面,像好莱坞电影里那样飞过空中。这就是所谓的“超调”。

这同样适用于下坡,施加过多的驱动强度会导致惯性使你超调、失去控制并撞车。

数据选通 (DQS) 驱动性能

当数据选通信号DQS和/DQS具有不同的驱动性能时,它们将具有明显不平衡的转换时间。

DDR2 采用差分数据选通信号 (DQS) 设计,使用 DQS 和 /DQS 信号之间的交点作为数据传输的参考。任何偏差都会对时序精度产生不利影响,并可能造成人为的 DQS-DQ 偏差。内存控制器将通过与差分数据选通信号 (DQS) 同步来移动数据 (DQ) 信号,而差分数据选通信号又会跟踪系统时钟。DQ

信号使用与参考电压 (VREF) 的交点作为参考,与 DQS 同步。为了实现最佳数据传输,DQS-/DQS 和 DQ-VREF 之间的两个交点必须对齐。因此,调整 VREF 有时可以提高故障系统的稳定性。然而,对于家庭用户来说,他们无法观察并确切了解正在发生的事情。

DQ-DQS 偏移效应会缩短内存控制器发送和接收数据信号的时间,从而导致数据眼和有效数据窗口减小:成功的信号传输需要足够的建立时间和保持时间裕度。DQ-DQS 偏移通常会对运行频率为 800MHz 或更快的 DDR2 内存模块造成不利影响。

总而言之,驱动器阻抗调整引擎和 OCD 校准电路用于调整 DQ 和 DQS-/DQS 的上拉和下拉驱动强度,以使 DQ-DQS 偏差尽可能小,从而以更大的冗余度扩展数据眼。

关于 Intel USB4 测试工具错误的说明

前几天有朋友留言,希望我介绍一下 Intel USB4 这个工具的使用。主要是每一代产品都不相同,改动一直很大,所以我这边无法统一介绍。

今天正好有一个同事遇到了问题,找我帮忙看看。他遇到的问题是:根据手册,一直无法安装这个工具,从Log 上看是软件无法找到 Python 3.11 所以无法进行下去。

经过我的研究判断:这是一个软件问题。正常情况下安装 Python 后会在 HKEY_CURRENT_USER 下面生成 Python 路径。但是这个软件是去查找 HKEY_LOCAL_MACHINE 下面,因此无法找到对应的路径。

修改方法,手工在HKEY_LOCAL_MACHINE 下面创建一个名为 Python 的 Key,然后在它下面创建一个 PythonCore 的Key, 在下面继续创建 3.11 的Key, 然后是 InstallPath的Key, 最终给这个赋值你的 Python 3.11 安装目录。例如:

Intel GPIO Configuration tool 使用方法

这次介绍一下 Intel 的 GPIO 配置工具,通常的名称是 Intel GPIO Configuration tool ,使用这个工具可以检查和设置 Intel 平台的 GPIO, 一个工具可以支持全部平台,比如:KBL/RPL/ARL 。下载的时候会提供2个版本:EFI 和 Windows 版本。这里介绍 Windows 版本工具的使用。

安装界面如下:

1.初始界面

2.推荐使用默认目录进行安装

3.一路 Next 即可完成安装

4.运行时如果遇到如下错误,通常是因为没有使用管理员权限运行

5.在图标上使用“Run as administrator”运行

6.第一次启动会出现如下界面

7.使用 Open 菜单

8.这里会出现2个选项:Direct 的意思是读取当前平台的设置;File 的意思是读取保存成文件的GPIO设定信息

9.这里使用 Direct 即可读取当前平台的GPIO配置。可以根据你的需要修改 GPIO 的配置,修改后使用最右侧的“update”按钮即可设置进入。需要特别注意的是:

a.此次设置重启之后BIOS会重新配置 GPIO, 这次的设置就会失效

b.有可能出现修改无法生效的请款,有可能是因为启动过程中BIOS设置了 lock 功能,配置被锁定,这种情况可以请BIOS工程师来帮助修改,或者特别制作一个没有 lock 的BIOS方便测试

10.菜单中的 Export 可以帮助你导出当面读取的GPIO信息,输出是二进制格式,这种格式可以通过菜单中的 Open来读取打开

11.如果想导出为方便阅读的格式,需要使用 Report菜单

12. 例如,保存为 ddd.html 然后打开就是下面这样:

入手一款国产开源逻辑分析仪

最近入手了一款国产的开源逻辑分析仪:章鱼哥出品的 PX logic 逻辑分析仪。

这款逻辑分析仪主打高速采集,性能指标​如下:

•最大32通道逻辑分析仪​

•buff模式最大支持8ch@1G,总带宽8G,存储深度4Gbits​

•usb3.0下stream最大2ch@1G,总带宽2G,存储深度1024Gbits​

•采样usb3.0进行传输,兼容usb2.0​

•输入采样阈值0-6v可调​

•开源解码协议库200+,使用python进行开发,可自行开发编写

硬件核心部分采用国产器件:

  • USB3.0 Phy 采用南京沁恒微的WCH569W
  • FPGA采用国产FPGA 紫光同创PGL22G

其中的 Buffer 模式意思是:内部自带了缓冲,可以将采集的信号直接传输存储在内部,存储多少数据取决于当前采样数量居和板载内存的大小;Stream的意思是随时将当前采样到的数据发送到电脑上,理论上只要你的电脑性能足够,可以不停的进行采样。

我入手的是中间价位 16通道599的这款:

型号PX Logic 32PX Logic 16 ProPX Logic 16 PlusPX Logic 16 base
简介32通道1G采样4G存储16通道1G采样4G存储16通道500M采样2G存储16通道250M采样1G存储
裸机价格999599现阶段不出399
USB接口USB3.0Type-C 支持正反插入)支持USB35G gen1USB2.0480mbps
通道数量32161616
最高采样率Buffer1GHz8ch1GHz8ch500MHz16ch250MHz16ch
Stream1GHz2ch1GHz2ch500MHz4ch250MHz8ch
最大存储深度Buffer4Gbit4Gbit2Gbit1Gbit
Stream最大1024G(bit) 取决电脑内存
最小采集脉宽2ns2ns4ns8ns
数据缓存模式Buffer(采集率更高)/Stream(存储深度更长)/Roll滚动模式(实时监控)
采样精度一个采样周期
触发类型内部触发上升沿/高电平/下降沿/低电平/任意沿
最多32通道同时设置触发
外部触发上升沿/高电平/下降沿/低电平/任意沿
专用硬件io触发输入,供外部设备同步
触发输出触发信号输出到IO,供外部设备同步
协议支持200+协议(开放协议解码库,可自定义任何协议)
输入耐压-40V + 40V
输入阻抗200K/1pf
阈值范围0~6V0.1V步进)
波形输出1pwm
通道接口2.54mm 杜邦线接口 50Pin正凌精工 3U镀金牛角座)
供电电压5V/USB供电
供电电流300mA@5V
供电功率1.5W
尺寸大小长宽高:80*74*13.5mm
工作温度0~85摄氏度

刚好手上有一个兼容性问题,使用这个抓了一下 SPD 的波形:

官网www.marrychip.com

这款产品对于分析主板时序非常有用,此外后面还会深入研究,尝试自己编写解码功能支持更多的总线。

软件可以在这里下载:

http://a78231029.gs2.cosfiles.com/d/ty-2501/LABZ/PXView_1.4.8_window_Setup.exe

Step to memory 012 同步存储器中的时钟偏差

https://www.bit-tech.net/reviews/tech/memory/the_secrets_of_pc_memory_part_3/7

同步存储器中的时钟偏差

当越来越多的电路与一个时钟同步时,可能会出现时钟延迟现象。结果,所有数据都无法与正确的时钟关联并准时到达:这种现象通常称为“时钟偏差”

华硕 P5E3 Premium BIOS 中的“AI Clock Skew”选项

时钟偏差可能由多种因素造成,包括路径延长、温度波动、沿该线路添加多个逻辑电路、材料缺陷以及主板上的根本设计缺陷——换句话说,它可能发生在内存系统的许多不同部分。在不同位置消除偏差逻辑将尝试最大限度地减少负面影响,以保持数据和系统时钟之间的一致性关系。然而,随着内存性能的不断提高,并非所有问题都能轻松解决。

发烧友可能更熟悉主板 BIOS 中恰如其名的“Clock Skew”变量,它可以用于在超频计算机内存时获得更高的稳定性,从而解决 DIMM 之间的时钟偏差。不可避免的是,内存性能越高,出现时钟偏差的可能性就越大。

当主板上使用四条内存条而不是两条内存条时,时钟偏差会更加严重,偏差量取决于同时使用哪两条内存条,以及 PCB 的基本设计。

经过大量设计仿真和测试,质量极高的主板通常能够很好地控制时钟偏差问题。然而,由于市场竞争压力巨大,产品生命周期缩短,许多存在缺陷的主板在没有足够测试时间的情况下就过早上市并大肆宣传,之后又在 BIOS 更新中尽可能地进行修补。日益复杂的主板芯片组和更高的内存速度也增加了这方面出现故障的可能性。

单端差分选通到差分选通架构

虽然单端数据选通信号最初用于 DDR1,但 DDR2 是支持单端和差分选通信号的演进转折点。最基本的解释是,单端选通信号依赖于一个振荡波,而差分架构则使用两个相互交织、交叉的反向振荡波。

镁光科技的 Aaron Boehm 强调,“差分时钟和选通信号方案对串扰引起的变化不太敏感”,而对于高速 DDR2 和 DDR3 来说,使用差分设计至关重要,Boehm 解释说,“随着我们不断降低 DRAM 电压并不断提高速度,降低时钟和选通信号对此类噪声的敏感度至关重要。 ”

对于单端选通信号设计,任何少量的噪声和干扰都会导致选通信号沿水平电压阈值(有时也称为参考电压电平)向左或向右偏移。这种水平偏移是有害的,因为它代表了时间的变化,从而导致了时间的不准确性。

存储器依赖于“相交”参考点的稳定性才能可靠地进行读写操作。差分选通脉冲设计更加稳定,因为波形异常只会导致相交中心点上下移动,这代表参考电压 (Vdd/2) 的变化,而不是时序偏移(左移或右移)。波动的电压阈值不如时间偏移严重。

在同步存储器系统中,任何显著的时间偏移都是致命的,因为这意味着数据不再与时钟一致,因此,只有这样的差分信号架构才能保证高速存储器正常工作。

FireBeetle 2 ESP32 P4 USB 速度测试

ESP32 P4 终于开始了量产,可以轻松的在市面上购买到芯片和模块了。
相比之前的型号,这个型号最大的不同是:增加了USB High Speed的支持,这样在 Arduino 开发环境的支持下,

这个芯片可以快捷简单的和PC进行连接,制作出更多的好玩项目。

最近 DFRobot 也推出了对应的 ESP32 P4 开发板:FireBeetle 2 ESP32 P4。笔者有幸拿到一块,这次做一个简单的测试,测试ESP32 P4 的 USB 速度。

FireBeetle 2 ESP32 P4  USB 速度测试图1

可以看到,板子带有2个 TypeC 接口,其中一个是用于下载的接口(来自P4芯片内部),另外一个是可以编程的 TypeC 接口(同样来自P4内部)

FireBeetle 2 ESP32 P4  USB 速度测试图2

开发板上手很简单,使用 Arduino 环境即可。测试的代码是将自身模拟为一个 U盘,上面有一个文件可以用于测试。

代码如下:

#include "USB.h"
#include "USBMSC.h"
#include "256MBDisk.bin.h"

#if ARDUINO_USB_CDC_ON_BOOT
#define HWSerial Serial0
#define USBSerial Serial
#else
#define HWSerial Serial
USBCDC USBSerial;
#endif

USBMSC MSC;

uint32_t findLBA(uint32_t LBA) {
  for (uint16_t i=0; i<415;i++) {
      if (Index[i]==LBA) {
          return i;
        }
    }
  return 0xFFFFFF;  
}
static const uint32_t DISK_SECTOR_COUNT = 520192; 

static int32_t onRead(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){
  //HWSerial.printf("MSC READ: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);

  int32_t getLBA=0;
  uint8_t *p;
  p=(uint8_t *)buffer;
  //HWSerial.printf("Buffer1 %X\n", buffer);
  for (uint32_t i=0;i<bufsize/DISK_SECTOR_SIZE;i++) {
     //HWSerial.printf("Check %u\n", lba+i);
     getLBA=findLBA(lba+i);
     //HWSerial.printf("getLBA %u\n", getLBA);
     if (getLBA!=0xFFFFFF) { //如果找到了
        memcpy((void *)&p[i*DISK_SECTOR_SIZE], &msc_disk[getLBA][0], DISK_SECTOR_SIZE);
        //HWSerial.printf("Send %u\n", getLBA);
        //HWSerial.printf("Buffer2 %X\n", (void *)&p[i*DISK_SECTOR_SIZE]);
      } else {
        //HWSerial.printf("Send all zero to %u\n", getLBA);
        for (uint16_t j=0;j<DISK_SECTOR_SIZE;j++) {
              p[i*DISK_SECTOR_SIZE+j]=0;
          }
          
      }
    }
  return bufsize;
}

static bool onStartStop(uint8_t power_condition, bool start, bool load_eject){
  HWSerial.printf("MSC START/STOP: power: %u, start: %u, eject: %u\n", power_condition, start, load_eject);
  return true;
}

static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
  if(event_base == ARDUINO_USB_EVENTS){
    arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data;
    switch (event_id){
      case ARDUINO_USB_STARTED_EVENT:
        HWSerial.println("USB PLUGGED");
        break;
      case ARDUINO_USB_STOPPED_EVENT:
        HWSerial.println("USB UNPLUGGED");
        break;
      case ARDUINO_USB_SUSPEND_EVENT:
        HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en);
        break;
      case ARDUINO_USB_RESUME_EVENT:
        HWSerial.println("USB RESUMED");
        break;
      
      default:
        break;
    }
  }
}

static int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){
  HWSerial.printf("MSC WRITE: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);
  return bufsize;
}
void setup() {
  HWSerial.begin(115200);
  HWSerial.setDebugOutput(true);

  USB.onEvent(usbEventCallback);
  MSC.vendorID("ESP32");//max 8 chars
  MSC.productID("USB_MSC");//max 16 chars
  MSC.productRevision("1.0");//max 4 chars
  MSC.onStartStop(onStartStop);
  MSC.onRead(onRead);
  MSC.onWrite(onWrite);
  MSC.mediaPresent(true);
  MSC.begin(DISK_SECTOR_COUNT, DISK_SECTOR_SIZE);
  USBSerial.begin();
  USB.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
}

需要特别注意

1.选择 TinyUSB

FireBeetle 2 ESP32 P4  USB 速度测试图3

2.型号使用 P4

FireBeetle 2 ESP32 P4  USB 速度测试图4

连接板卡上方 TypeC 即可烧录, 然后连接右侧的TypeC,系统中会出现一个U盘

FireBeetle 2 ESP32 P4  USB 速度测试图5

测试显示速度可以稳定在 10MB/S 左右。

FireBeetle 2 ESP32 P4  USB 速度测试图6

之前的 ESP32 S2/S3 同样代码最高速度在 750KB/S 左右。相比之下速度提升了 13倍。

完整的代码在【参考1】可以看到

参考:
1.https://www.lab-z.com/fakeud/  ESP32 S2 上实现假U盘(ESP32 2.0.1 )
2.https://mc.dfrobot.com.cn/thread-309859-1-1.html  ESP32 S2 做一个假U盘

Step to memory 011 第二代DDR内存:DDR2

https://www.bit-tech.net/reviews/tech/memory/the_secrets_of_pc_memory_part_3/5

DDR2 台式机模块由 240 针连接接口组成。

JEDEC 定义的 DDR2 工作电压为 1.8V,然而,一些厂商生产的高性能模块可在高达 2.4V 的电压下运行,并且仍然提供保修。与之相反,一些廉价模块缺乏良好的散热,为了长期可靠的运行,需要主动降低电压。

我们最近就更高的 DRAM 电压及其对寿命的影响向镁光科技计算部门高级市场经理 Brett Williams 进行了咨询。例如,我们询问了一个典型的 2.0V 电压运行的内存模块;“ [它] 的寿命实际上会比 1.8V 模块短。现在,当我说‘寿命短’时……这可能会或可能不会成为您的顾虑。在 1.8V 电压下,该模块可能可以使用长达 200 年。在 2.0V 电压下,它可能可以使用长达 10 年。但您的系统很可能会在三到五年后就被丢弃:更换内存或升级。 ”

JEDEC 规定 DDR2的最高工作频率是 800MHz,因此超过 800MHz 的速度被认为超出了行业标准,需要主板特别支持。

需要注意的是,JEDEC 规范更关注“安全”冗余度。这是为了让所有的符合 JEDEC 标准的 RAM 能够适配最广泛的主板和芯片组,因此JEDEC DDR 标准更多地关注信号可靠性而非内存速度。

以瓦特/千兆字节/秒为单位的功率与吞吐量比的提高是一个积极的趋势,但许多 DDR2 台式机主板(BIOS)和内存(SPD)在出厂时就已预编程为在 1.85V 至 1.95V 的电压下运行,以应对更广泛的稳定性问题。

值得一提的是,镁光公司推出的一类特殊 1,066MHz DDR2 DRAM 原生电压为 1.8V,但仍符合 JEDEC 的要求。通常只有 800MHz 内存的额定电压为 1.8V,但这是 DDR2 市场上唯一一款原生 1,066MHz DRAM,因此特别适合以 1,066MHz 内存速度运行并可超频的 AMD 新款 Phenom CPU。Brett Williams 解释了美光公司如何通过“大幅提升利润率”实现这一目标。他告诉我们,美光公司的 D9 基本上采用了比许多竞争对手更先进的制造工艺:美光公司采用 78nm 工艺,而其他公司采用 95nm 工艺。“正是工艺和设计技术的结合,帮助美光公司实现了更高的内存频率,同时保持了最宽的信号传输裕度。 ”镁光科技的 Kirstin Bordner 为我们提供了需要注意的 D9 特定标识符,这些标识符指示 1.8V 1,066MHz DRAM。

  • D9HCD MT47H64M8B6-25:D
  • D9GKX MT47H64M8B6-25E:D
  • D9GMH MT47H64M8B6-3:D

对称 T 型分支拓扑

PC 内存的秘密:第 3 部分

https://www.bit-tech.net/reviews/tech/memory/the_secrets_of_pc_memory_part_3/6

DDR2 与 DDR1 共享类似的架构,称为 T-Branch 拓扑。然而,DDR2 与上一代产品的不同之处在于它采用了对称设计。因此,每个 DRAM 芯片的命令、地址和时钟总线完全均衡,从而提高了高频信号的质量,因为更好的对称性可以降低信号抖动。

这种设计在减少 SDR 和 DDR1 总线拓扑中常见的非单调性信号(non-monotonic signal behaviour)行为方面取得了重大改进。

LAB-Z注释:非单调性(non monotonic)问题指的是信号在上升过程中出现了部分下降的情况【参考1】

绝大多数非单调性都是由复杂的信号拓扑造成的。在一个CPU或DSP的本地总线上,非单调性问题最常见。非单调性按表现形式可以分为两种:回钩和台阶。

     对于一个沿有效的时钟来说,信号沿上的回钩和台阶是致命的。因为一个非单调性的时钟沿,可能被接收端认作多个有效沿,或在器件内部产生亚稳态,导致时序逻辑的功能错误。对于数据来说,非单调性的危害主要是造成时间裕量的减少,这也是复杂的总线系统往往需要进行时序仿真的原因之一。

参考:

  1. https://www.cnblogs.com/chenman/p/3649343.html

T-Branch 仍然会导致较长的命令-地址-时钟总线和较短的数据总线之间出现时序偏差。这是因为命令-地址-时钟 T-Branch 总线具有多个分支,而数据总线则是直接连接。这在 DDR2 下不是一个大问题,但在 DDR3 速度等级中已得到解决。

数据预取

DDR2 采用“4n 预取”设计,而非 DDR1 的“2n 预取”。在每个周期,它能够将来自内部存储库的 4 位数据排列到 IO 缓冲区中,然后再通过数据总线传输出去。

据 JEDEC DRAM 委员会成员、前 ATI Technologies(现 AMD)成员 Joe Macri 介绍,4n-Prefetch 架构的主要目的是降低 DRAM 核心频率以满足更高数据速率的需求。这样,DRAM 核心就能以数据总线频率的四分之一运行。

这种设计的直接优势在于能够维持相对成熟的制造工艺,而无需进行大规模的重新设计。它能够缓解 DDR2 芯片(尤其是具有更高数据速率和密度的芯片)的产能提升和良率压力。

Step to memory 010 数据预存取 Data Prefetch

https://www.bit-tech.net/reviews/tech/memory/the_secrets_of_pc_memory_part_3/4

DDR1 采用“2n 预取”设计,这意味着在每个周期,内存模块会在 1 个时钟周期内从内存条中准备 2 位数据,然后将它们在 IO 缓冲区中背靠背排列,最后通过数据线发送出去。这种设计相当简洁而优雅:对于每一对,在信号波的上升沿和下降沿各发送一位数据,从而有效地将数据吞吐量翻倍,而无需提高 DRAM 核心频率。

反射噪声管理

为了提高信号质量,主板的内存IO操作中内置了电阻终端,以消除信号反射引起的噪声。这种噪声是由信号从数据总线两端反射回来干扰新信号引起的。新信号与旧信号回声之间的冲突会引起抖动和相消干扰。信号可能会在阻抗不同的点发生反射,例如,内存插槽和内存条接触点。

需要注意的是,这种方法只能将噪声控制在DDR1设计性能参数范围内。超出该范围的噪声无法完全消除,甚至不足以造成稳定性问题。

如何理解信号的反射问题

信号反射噪声类似于声音沿着一条长管传播,随后从封闭的一端反射回来,在那里你会听到回声。现在想象一下,在这条长管的中途,有一个开口,你的朋友正在那里听。当你沿着管道和朋友说话时,声音传到他们中间,继续传播到管道的尽头,最终以回声的形式反弹回来。

当你的朋友开始回复时,回声会干扰他们的信息。因此,听清回复会有点困难。随着你们说话速度越来越快,越来越难以跟上对话;这类似于在处理信号反射的同时提高内存频率。

一种解决方案是消音管道末端以吸收噪声——板载电阻终端的作用就是在反射回来之前吸收掉不需要的信号。

ACPI:Object is created temporarily in another method and cannot be accessed

天杀最近在玩一台X86主机,他发现Dump出来的 DSDT Table 重新编译的时候会碰到标题的错误,更详细的错误信息如下:

SDT.dsl 2644: PARM |= (DerefOf (CDCT [^^MCHK.DCFE]) &lt;&lt; 0x15) /* _SB_.PCI0.GFX0.PARM */
Error 6163 - ^ Object is created temporarily in another method and cannot be accessed (^^MCHK.DCFE)

分析代码可以看到

  1. 出现问题的代码是尝试访问MCHK.DCFE
 If ((GESF == 0x07))
    {
   PARM = GIVD /* \_SB_.PCI0.GFX0.GIVD */
   PARM ^= One
   PARM |= (GMFN &lt;&lt; One)
   PARM |= 0x1800
   PARM |= (IDMS &lt;&lt; 0x11)
   PARM |= (DerefOf (CDCT [^^MCHK.DCFE]) &lt;&lt; 0x15) /* \_SB_.PCI0.GFX0.PARM */
       GESF = One
        Return (SUCC) /* \_SB_.PCI0.GFX0.SUCC */
 }

2.DCFE定义在MCHK 中

                Method (MCHK, 0, Serialized)
                {
                    If ((MADR != 0xFFFFFFFF))
                    {
                        OperationRegion (IGMM, SystemMemory, MADR, 0x3000)
                        Field (IGMM, AnyAcc, NoLock, Preserve)
                        {
                            Offset (0x20C8), 
                                ,   4, 
                            DCFE,   4
                        }
                    }
                }

看起来错误的原因是:如果MADR为0xFFFFFFFF,那么DCFE 就不存在,访问不到。

解决方法,修改代码如下:

PARM |= 0x1800
PARM |= (IDMS &lt;&lt; 0x11)
                                          
//LABZDebug_Start
If ((MADR != 0xFFFFFFFF))
      {
         OperationRegion (IGMM, SystemMemory, MADR, 0x3000)
         Field (IGMM, AnyAcc, NoLock, Preserve)
             {
                Offset (0x20C8),
                 ,   4,
                  DCFE,   4
              }
          PARM |= (DerefOf (CDCT [DCFE]) &lt;&lt; 0x15) /* \_SB_.PCI0.GFX0.PARM */
       }
//LABZDebug_End
                           
 GESF = One
 Return (SUCC) /* \_SB_.PCI0.GFX0.SUCC */

再次编译就通过了。

此外,还有一种更简单的方法:使用编译 AML 相同的版本重新编译,这个很容易理解:能够编译生成 AML 就说明至少有一个版本的编译器认可这种编译方法,找到这个版本即可重新编译。

具体的信息可以在 dsdt 的头部看到,比如,另外一个项目上如下位置可以看到编译器版本:

找到这个版本重新编译一个Error甚至Warning 都没有。

当然,这个问题还是给了我们一个提醒:ASL 编译器不同版本之间存在差异。