RAMSPDToolkit Update + timings added (#1835)

* Workaround for page changing on DDR5 systems with SPD Write Protection active has been implemented in new version of RAMSPDToolkit.

Code for LHM has been adjusted accordingly.

Added more sensors (timings).

* Move abbreviation of timings to start of string.

* Simplify names for timings.

* Update version.

* Remove extra padding.
This commit is contained in:
Blacktempel
2025-09-08 13:14:32 +02:00
committed by GitHub
parent 16ad77afc6
commit 3f8294898d
8 changed files with 114 additions and 32 deletions
+3
View File
@@ -646,6 +646,9 @@ public class SensorGadget : Gadget
case SensorType.TimeSpan:
format = "{0:g}";
break;
case SensorType.Timing:
format = "{0:F3} ns";
break;
case SensorType.Energy:
format = "{0:F0} mWh";
break;
+3
View File
@@ -76,6 +76,9 @@ public class SensorNode : Node
case SensorType.TimeSpan:
Format = "{0:g}";
break;
case SensorType.Timing:
Format = "{0:F3} ns";
break;
case SensorType.Energy:
Format = "{0:F0} mWh";
break;
@@ -165,6 +165,8 @@ public class SensorNotifyIcon : IDisposable
return _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit ? $"{UnitManager.CelsiusToFahrenheit(Sensor.Value):F0}" : $"{Sensor.Value:F0}";
case SensorType.TimeSpan:
return $"{TimeSpan.FromSeconds(Sensor.Value.Value):g}";
case SensorType.Timing:
return $"{Sensor.Value.Value:F3}";
case SensorType.Clock:
case SensorType.Fan:
case SensorType.Flow:
@@ -289,6 +291,7 @@ public class SensorNotifyIcon : IDisposable
case SensorType.Noise: format = "\n{0}: {0:F0} dBA"; break;
case SensorType.Conductivity: format = "\n{0}: {0:F1} µS/cm"; break;
case SensorType.Humidity: format = "\n{0}: {0:F0} %"; break;
case SensorType.Timing: format = "\n{0}: {0:F3} ns"; break;
}
string formattedValue = string.Format(format, Sensor.Name, Sensor.Value);
+4
View File
@@ -91,6 +91,10 @@ public sealed class TypeNode : Node, IExpandPersistNode
Image = Utilities.EmbeddedResources.GetImage("time.png");
Text = "Times";
break;
case SensorType.Timing:
Image = Utilities.EmbeddedResources.GetImage("time.png");
Text = "Timings";
break;
case SensorType.Noise:
Image = Utilities.EmbeddedResources.GetImage("loudspeaker.png");
Text = "Noise Levels";
+2 -1
View File
@@ -29,7 +29,8 @@ public enum SensorType
Data, // GB = 2^30 Bytes
SmallData, // MB = 2^20 Bytes
Throughput, // B/s
TimeSpan, // Seconds
TimeSpan, // Seconds
Timing, // ns
Energy, // milliwatt-hour (mWh)
Noise, // dBA
Conductivity, // µS/cm
@@ -6,7 +6,6 @@
using LibreHardwareMonitor.Hardware.Memory.Sensors;
using RAMSPDToolkit.SPD;
using RAMSPDToolkit.SPD.Enums;
using RAMSPDToolkit.SPD.Interfaces;
using RAMSPDToolkit.SPD.Interop.Shared;
@@ -19,40 +18,36 @@ internal sealed class DimmMemory : Hardware
public DimmMemory(SPDAccessor accessor, string name, Identifier identifier, ISettings settings)
: base(name, identifier, settings)
{
//Check which kind of RAM we have
switch (accessor.MemoryType())
//Only add thermal sensor if present
if (accessor is IThermalSensor ts && ts.HasThermalSensor)
{
case SPDMemoryType.SPD_DDR4_SDRAM:
case SPDMemoryType.SPD_DDR4E_SDRAM:
case SPDMemoryType.SPD_LPDDR4_SDRAM:
case SPDMemoryType.SPD_LPDDR4X_SDRAM:
_thermalSensor = new SpdThermalSensor($"DIMM #{accessor.Index}",
accessor.Index,
SensorType.Temperature,
this,
settings,
accessor as IThermalSensor);
break;
case SPDMemoryType.SPD_DDR5_SDRAM:
case SPDMemoryType.SPD_LPDDR5_SDRAM:
//Check if we are on correct page or if write protection is not enabled
if (accessor.PageData.HasFlag(PageData.ThermalData) || !accessor.HasSPDWriteProtection)
{
//Check which kind of RAM we have
switch (accessor.MemoryType())
{
case SPDMemoryType.SPD_DDR4_SDRAM:
case SPDMemoryType.SPD_DDR4E_SDRAM:
case SPDMemoryType.SPD_LPDDR4_SDRAM:
case SPDMemoryType.SPD_LPDDR4X_SDRAM:
case SPDMemoryType.SPD_DDR5_SDRAM:
case SPDMemoryType.SPD_LPDDR5_SDRAM:
_thermalSensor = new SpdThermalSensor($"DIMM #{accessor.Index}",
accessor.Index,
SensorType.Temperature,
this,
settings,
accessor as IThermalSensor);
}
break;
break;
}
}
bool hasThermalSensor = _thermalSensor != null;
//Add thermal sensor
if (_thermalSensor != null)
if (hasThermalSensor)
ActivateSensor(_thermalSensor);
//Add other sensors
CreateSensors(accessor, hasThermalSensor);
}
public override HardwareType HardwareType => HardwareType.Memory;
@@ -61,4 +56,80 @@ internal sealed class DimmMemory : Hardware
{
_thermalSensor?.UpdateSensor();
}
private void CreateSensors(SPDAccessor accessor, bool hasThermalSensor)
{
if (accessor is DDR4Accessor ddr4)
{
CreateSensorsDDR4(ddr4, hasThermalSensor);
}
else if (accessor is DDR5Accessor ddr5)
{
CreateSensorsDDR5(ddr5, hasThermalSensor);
}
}
private void CreateSensorsDDR4(DDR4Accessor accessor, bool hasThermalSensor)
{
if (hasThermalSensor)
{
//Temperature Resolution (fixed value)
AddSensor("Temperature Sensor Resolution", 0, false, SensorType.Temperature, accessor.TemperatureResolution);
}
//Timings
AddSensor("tCKAVGmin (Minimum Cycle Time)", 1, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumCycleTime);
AddSensor("tCKAVGmax (Maximum Cycle Time)", 2, false, SensorType.Timing, (float)accessor.SDRAMTimings.MaximumCycleTime);
AddSensor("tAA (CAS Latency Time)", 3, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumCASLatencyTime);
AddSensor("tRCD (RAS to CAS Delay Time)", 4, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumRASToCASDelayTime);
AddSensor("tRP (Row Precharge Delay Time)", 5, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumRowPrechargeDelayTime);
AddSensor("tRAS (Active to Precharge Delay Time)", 6, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumActiveToPrechargeDelayTime);
AddSensor("tRC (Active to Active/Refresh Delay Time)", 7, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumActiveToActiveRefreshDelayTime);
AddSensor("tRFC1 (Refresh Recovery Delay Time)", 8, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumRefreshRecoveryDelayTime1);
AddSensor("tRFC2 (Refresh Recovery Delay Time)", 9, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumRefreshRecoveryDelayTime2);
AddSensor("tRFC4 (Refresh Recovery Delay Time)", 10, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumRefreshRecoveryDelayTime4);
AddSensor("tFAW (Four Activate Window Time)", 11, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumFourActivateWindowTime);
AddSensor("tRRD_S (Activate to Activate Delay Time)", 12, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumActivateToActivateDelay_DiffGroup);
AddSensor("tRRD_L (Activate to Activate Delay Time)", 13, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumActivateToActivateDelay_SameGroup);
AddSensor("tCCD_L (CAS to CAS Delay Time)", 14, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumCASToCASDelay_SameGroup);
AddSensor("tWR (Write Recovery Time)", 15, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumWriteRecoveryTime);
AddSensor("tWTR_S (Write to Read Time)", 16, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumWriteToReadTime_DiffGroup);
AddSensor("tWTR_L (Write to Read Time)", 17, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumWriteToReadTime_SameGroup);
}
private void CreateSensorsDDR5(DDR5Accessor accessor, bool hasThermalSensor)
{
if (hasThermalSensor)
{
//Temperature Resolution (fixed value)
AddSensor("Temperature Sensor Resolution", 0, false, SensorType.Temperature, accessor.TemperatureResolution);
}
//Timings
AddSensor("tCKAVGmin (Minimum Cycle Time)", 1, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumCycleTime);
AddSensor("tCKAVGmax (Maximum Cycle Time)", 2, false, SensorType.Timing, (float)accessor.SDRAMTimings.MaximumCycleTime);
AddSensor("tAA (CAS Latency Time)", 3, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumCASLatencyTime);
AddSensor("tRCD (RAS to CAS Delay Time)", 4, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumRASToCASDelayTime);
AddSensor("tRP (Row Precharge Delay Time)", 5, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumRowPrechargeDelayTime);
AddSensor("tRAS (Active to Precharge Delay Time)", 6, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumActiveToPrechargeDelayTime);
AddSensor("tRC (Active to Active/Refresh Delay Time)", 7, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumActiveToActiveRefreshDelayTime);
AddSensor("tWR (Write Recovery Time)", 8, false, SensorType.Timing, (float)accessor.SDRAMTimings.MinimumWriteRecoveryTime);
AddSensor("tRFC1 (Normal Refresh Recovery Time)", 9, false, SensorType.Timing, (float)accessor.SDRAMTimings.NormalRefreshRecoveryTime);
AddSensor("tRFC2 (Fine Granularity Refresh Recovery Time)", 10, false, SensorType.Timing, (float)accessor.SDRAMTimings.FineGranularityRefreshRecoveryTime);
AddSensor("tRFCsb (Same Bank Refresh Recovery Time)", 11, false, SensorType.Timing, (float)accessor.SDRAMTimings.SameBankRefreshRecoveryTime);
AddSensor("tRFC1_dlr (Normal Refresh Recovery Time 3DS)", 12, false, SensorType.Timing, (float)accessor.SDRAMTimings.NormalRefreshRecoveryTime_3DSDifferentLogicalRank);
AddSensor("tRFC2_dlr (Fine Granularity Refresh Recovery Time 3DS)", 13, false, SensorType.Timing, (float)accessor.SDRAMTimings.FineGranularityRefreshRecoveryTime_3DSDifferentLogicalRank);
AddSensor("tRFCsb_dlr (Same Bank Refresh Recovery Time 3DS)", 14, false, SensorType.Timing, (float)accessor.SDRAMTimings.SameBankRefreshRecoveryTime_3DSDifferentLogicalRank);
}
private void AddSensor(string name, int index, bool defaultHidden, SensorType sensorType, float value)
{
var sensor = new Sensor(name, index, defaultHidden, sensorType, this, null, _settings)
{
Value = value,
};
ActivateSensor(sensor);
}
}
@@ -7,14 +7,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using RAMSPDToolkit.I2CSMBus;
using RAMSPDToolkit.SPD;
using RAMSPDToolkit.SPD.Enums;
using RAMSPDToolkit.SPD.Interfaces;
using RAMSPDToolkit.SPD.Interop.Shared;
using RAMSPDToolkit.Windows.Driver;
@@ -162,9 +160,8 @@ internal class MemoryGroup : IGroup, IHardwareChanged
//RAM available and detected
if (detector.Accessor != null)
{
//We are only interested in modules with thermal sensor
if (detector.Accessor is IThermalSensor { HasThermalSensor: true })
accessors.Add(detector.Accessor);
//Add all detected modules
accessors.Add(detector.Accessor);
ramDetected = true;
}
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;netstandard2.0;net6.0;net8.0</TargetFrameworks>
<AssemblyName>LibreHardwareMonitorLib</AssemblyName>
@@ -41,7 +41,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="HidSharp" Version="2.1.0" />
<PackageReference Include="RAMSPDToolkit-NDD" Version="1.1.4" />
<PackageReference Include="RAMSPDToolkit-NDD" Version="1.2.2" />
<PackageReference Include="System.Management" Version="9.0.8" />
</ItemGroup>
<ItemGroup>