ESH10000536 - M.2 Active Load 2ch Module
Overview
The ESH10000536 is a compact 2-channel active load module in M.2 form factor for power supply testing, battery characterization, and electronic load applications with integrated temperature monitoring, fan control, and energy measurement.
Description
The M.2 Active Load 2ch module provides programmable electronic load capabilities for testing power supplies, batteries, and power circuits. Each channel features independent current control, voltage/current/power measurement, energy consumption tracking, and automatic thermal protection with integrated fan cooling.
Key Features:
2 Independent Active Load Channels: Programmable electronic load with comprehensive measurement
- Current setpoint control (ISET1, ISET2)
- Voltage measurement per channel (VMEAS1, VMEAS2)
- Current measurement per channel (IMEAS1, IMEAS2)
- Remote voltage sensing (VREM1, VREM2)
- Real-time power calculation (POWER1, POWER2)
- Energy consumption tracking (JOULES1, JOULES2)
Thermal Management: Integrated temperature monitoring and fan control
- TMP116 temperature sensor
- MAX6650 PWM fan controller
- Automatic temperature-based regulation
- Thermal protection limits (50°C warning, 65°C error)
Safety Features: Automatic protection mechanisms
- Energy dissipation limit (250 joules maximum)
- Automatic load shutdown on over-energy condition
- Temperature-based fan speed control
- LED status indication per channel
LED Status Indication: Visual feedback system
- 4× RGB LEDs (LP5012 driver)
- Channel 1 LEDs: D4 (middle), D5 (connector)
- Channel 2 LEDs: D2 (connector), D3 (middle)
- Color coding: Yellow=off/idle, Green=active load
Calibration Support: Per-channel gain and offset calibration
- Persistent calibration storage by module identity
- Automatic calibration application
- User-accessible calibration channel
Hardware Details
Analog-to-Digital/Digital-to-Analog Converter:
- Chip: Analog Devices AD5593R
- I²C Address: 0x10
- Channels: 8 (2 ISET outputs + 6 measurement inputs)
- Resolution: 12-bit ADC/DAC
- Communication: I²C bus
- Voltage Range: 0-5V (double ADC range mode enabled)
- Features:
- DoubleAdcRange: true (extends ADC to 2× VREF)
- DoubleDacRange: false (DAC uses single range)
- ReadTemperature: false (internal temp sensor disabled)
Temperature Sensor:
- Chip: TI TMP116 high-precision temperature sensor
- I²C Address: 0x49
- Accuracy: ±0.2°C (typ)
- Resolution: 0.0078°C (16-bit)
- Communication: I²C bus
- Purpose: Module thermal monitoring
Fan Controller:
- Chip: Maxim MAX6650 PWM fan controller
- I²C Address: 0x48
- Control: PWM-based speed control
- Maximum RPM: 30,000 (configurable)
- Default RPM: 0 (off when load disabled)
- Communication: I²C bus
- Features: Tachometer feedback, temperature-based regulation
LED Driver:
- Chip: TI LP5012 RGB LED driver
- I²C Address: 0x14
- Channels: 12 (4 LEDs × 3 RGB)
- LEDs: D2, D3, D4, D5
- Control: PWM-based intensity (0-255 per color)
- Default Luminance: 0.2 (20% brightness)
- Communication: I²C bus
Channel Naming Convention
All channels follow the naming pattern: {ModuleIndex}.ESH10000536.{ChannelName}
Where:
{ModuleIndex}is the position of the module in the system (e.g., 0, 1, 2...)ESH10000536is the module type identifier{ChannelName}is the specific channel name from the table below
Example: Module at position 0, current setpoint for channel 1 would be: 0.ESH10000536.ISET1
User-Accessible Channels
| Channel Name | Type | Direction | Usage | Description |
|---|---|---|---|---|
| Channel 1 Load Control & Measurement | ||||
| ISET1 | Analog | OUT | UserAllocatable | Current setpoint for channel 1 load (A, DAC output) |
| VMEAS1 | Analog | IN | UserAllocatable | Voltage measurement channel 1 (V, gain=10) |
| IMEAS1 | Analog | IN | UserAllocatable | Current measurement channel 1 (A, gain=0.5) |
| VREM1 | Analog | IN | UserAllocatable | Remote voltage sense channel 1 (V, gain=10) |
| POWER1 | Analog | IN | UserAllocatable | Power consumption channel 1 (W, calculated: V×I) |
| JOULES1 | Analog | IN | UserAllocatable | Energy consumed channel 1 (Ws, integrated power) |
| Channel 2 Load Control & Measurement | ||||
| ISET2 | Analog | OUT | UserAllocatable | Current setpoint for channel 2 load (A, DAC output) |
| VMEAS2 | Analog | IN | UserAllocatable | Voltage measurement channel 2 (V, gain=10) |
| IMEAS2 | Analog | IN | UserAllocatable | Current measurement channel 2 (A, gain=0.5) |
| VREM2 | Analog | IN | UserAllocatable | Remote voltage sense channel 2 (V, gain=10) |
| POWER2 | Analog | IN | UserAllocatable | Power consumption channel 2 (W, calculated: V×I) |
| JOULES2 | Analog | IN | UserAllocatable | Energy consumed channel 2 (Ws, integrated power) |
| Thermal Monitoring | ||||
| TEMP | Temperature | IN | UserAllocatable | Module temperature (°C, TMP116 sensor) |
| Calibration | ||||
| CALIBRATION | Calibration | N/A | UserAllocatable | Module calibration table (gain/offset for all ADC channels) |
Total User Channels: 14 (6 per load channel + 1 temperature + 1 calibration)
Internal Channels (Not User-Accessible)
The following channels are used for internal system control and are hidden from users:
- LED RGB Channels (all
HiddenSystemControl):- D2_R, D2_G, D2_B (Channel 2 connector LED)
- D3_R, D3_G, D3_B (Channel 2 middle LED)
- D4_R, D4_G, D4_B (Channel 1 middle LED)
- D5_R, D5_G, D5_B (Channel 1 connector LED)
Channel Configuration
Current Setpoint Control
Set the current draw for each channel:
// Set channel 1 to draw 1.5A
ConfigureChannels(new[] {
new AnalogChannel {
NetName = "0.ESH10000536.ISET1",
Enabled = true,
Direction = DirectionTypes.OUT,
Value = 1.5, // 1.5 amperes
Gain = 1.0,
Offset = 0.0
}
});
Note: Setting ISET to 0 disables the load for that channel and turns the LED yellow. Non-zero values enable the load, turn the LED green, and activate the fan.
Voltage and Current Measurement
Read actual voltage and current:
string[] measurements = GetValues(new[] {
"0.ESH10000536.VMEAS1",
"0.ESH10000536.IMEAS1"
});
double voltage = double.Parse(measurements[0]); // Volts
double current = double.Parse(measurements[1]); // Amperes
Console.WriteLine($"CH1: {voltage:F3}V @ {current:F3}A");
Power and Energy Measurement
Monitor power consumption and total energy:
string[] powerEnergy = GetValues(new[] {
"0.ESH10000536.POWER1",
"0.ESH10000536.JOULES1"
});
double powerW = double.Parse(powerEnergy[0]); // Watts
double energyWs = double.Parse(powerEnergy[1]); // Watt-seconds (Joules)
Console.WriteLine($"Power: {powerW:F2}W, Energy: {energyWs:F1}J");
Programming Interface
Set Load Current:
// Enable 2A load on channel 1
SetValues(
new[] { "0.ESH10000536.ISET1" },
new[] { "2.0" } // 2.0 amperes
);
// Result: LED D5 turns green, fan starts, energy tracking begins
Read All Channel 1 Parameters:
string[] ch1Data = GetValues(new[] {
"0.ESH10000536.VMEAS1",
"0.ESH10000536.IMEAS1",
"0.ESH10000536.POWER1",
"0.ESH10000536.JOULES1"
});
Console.WriteLine($"Voltage: {ch1Data[0]}V");
Console.WriteLine($"Current: {ch1Data[1]}A");
Console.WriteLine($"Power: {ch1Data[2]}W");
Console.WriteLine($"Energy: {ch1Data[3]}Ws");
Disable Load:
// Turn off both channels
SetValues(
new[] { "0.ESH10000536.ISET1", "0.ESH10000536.ISET2" },
new[] { "0", "0" }
);
// Result: LEDs turn yellow, fan stops, energy counters reset
Monitor Temperature:
string[] temp = GetValues(new[] { "0.ESH10000536.TEMP" });
double temperatureC = double.Parse(temp[0]);
Console.WriteLine($"Module temperature: {temperatureC:F1}°C");
if (temperatureC > 50)
Console.WriteLine("WARNING: Temperature above 50°C");
if (temperatureC > 65)
Console.WriteLine("ERROR: Temperature above 65°C - thermal protection active");
Calibration Access:
// Read current calibration
string[] calData = GetValues(new[] { "0.ESH10000536.CALIBRATION" });
CalibrationTable cal = SerializableHelpers.CreateFromBase64<CalibrationTable>(calData[0]);
// Modify calibration for specific channel
foreach (var row in cal.CalData)
{
if (row.Key.Contains("IMEAS1"))
{
row.Gain = 0.505; // Adjust current measurement gain
row.Offset = -0.01; // Apply -10mA offset
}
}
// Write updated calibration
string updatedCal = SerializableHelpers.AsBase64(cal);
SetValues(
new[] { "0.ESH10000536.CALIBRATION" },
new[] { updatedCal }
);
Automatic Features
Power Calculation
Power is automatically calculated every invalidation cycle:
POWER1 = VMEAS1 × IMEAS1 // Real-time power in watts
POWER2 = VMEAS2 × IMEAS2
Special Behavior:
- If load is disabled (ISET=0), current measurement is forced to 0
- Power calculation uses the actual voltage and forced/measured current
Energy Integration
Energy (joules) is automatically integrated over time:
JOULES1 += POWER1 × ElapsedSeconds // Cumulative energy in watt-seconds
JOULES2 += POWER2 × ElapsedSeconds
Reset Conditions:
- Energy counter resets to 0 when load is re-enabled after being disabled
- Energy counters reset when total energy (CH1+CH2) exceeds 250J safety limit
Energy Safety Limit
The module enforces a 250 joule maximum energy dissipation limit:
if (JOULES1 + JOULES2 > 250)
{
// Automatic protection:
SetValues(ISET1, "0"); // Disable channel 1 load
SetValues(ISET2, "0"); // Disable channel 2 load
LogWarning("Excessive power dissipation: 250 joules, disabling load");
}
Purpose: Protects the module from thermal damage due to excessive sustained power dissipation.
Thermal Regulation
The fan controller automatically regulates speed based on temperature:
// When load is enabled (ISET > 0):
fan.DesiredRpm = 30000; // Maximum RPM (full cooling)
// When load is disabled (ISET = 0):
fan.DesiredRpm = 0; // Fan off
// Temperature-based warnings:
// 50°C: Warning logged
// 65°C: Error logged, system notification
Measurement Update Rate
The module uses rate-limited automatic invalidation:
- Default Interval: 10,000ms (10 seconds)
- Trigger: Automatic on GetValues() calls
- Behavior: Non-blocking (returns immediately if interval hasn't elapsed)
Implications:
- Measurements update at most every 10 seconds
- Calling GetValues() more frequently than 10s returns cached values
- Energy integration accuracy depends on update interval
LED Status Indication
The module provides visual feedback through 4 RGB LEDs:
| LED | Location | Channel | Behavior |
|---|---|---|---|
| D5 | Under CH1 connector | Channel 1 | Yellow=off, Green=active (ISET1>0) |
| D4 | CH1 middle | Channel 1 | Yellow initially, user-configurable |
| D3 | CH2 middle | Channel 2 | Black initially (off) |
| D2 | Under CH2 connector | Channel 2 | Yellow=off, Green=active (ISET2>0) |
Automatic Color Changes:
- Yellow: Load disabled (ISET=0), fan off, energy counter reset
- Green: Load active (ISET>0), fan running, energy accumulating
Initial Colors (on Reset):
- D2: Yellow (CH2 connector)
- D3: Black (CH2 middle)
- D4: Black (CH1 middle)
- D5: Yellow (CH1 connector)
Error Handling
The module validates operations and provides error messages:
- Invalid NetName: Throws exception if channel does not exist
- Calibration Errors: Validates calibration table structure and keys
- Excessive Energy: Automatic load shutdown with warning log at 250J limit
- Temperature Warnings: Logs warnings at 50°C, errors at 65°C
- Fan Communication Errors: Logged but does not prevent operation (degraded mode)
- Invalid Current Values: Logged as warnings, value ignored
Best Practices
- Monitor energy accumulation: Check JOULES1 and JOULES2 to avoid hitting 250J limit
- Use remote sensing: Connect VREM1/VREM2 for accurate voltage measurement at load
- Allow thermal stabilization: Wait for temperature to stabilize before high-power tests
- Reset energy counters: Disable and re-enable load to reset joules count for new test
- Monitor temperature: Check TEMP channel periodically during sustained loads
- Gradual current ramping: Ramp ISET slowly to avoid inrush current issues
- Calibration verification: Verify calibration with known loads/voltages
- Fan operation: Ensure fan is functional before applying sustained loads
- Update interval consideration: Understand 10s measurement interval for test timing
- LED monitoring: Observe LED status for quick operational verification
Module Initialization Sequence
On Reset(), the module performs:
- Clear existing channel list
- Setup fan controller:
- Create MAX6650 at I²C address 0x48
- Maximum RPM: 30,000
- Initial desired RPM: 0 (off)
- Reset, update, and invalidate (read current RPM)
- Setup temperature sensor:
- Create TMP116 at I²C address 0x49
- Create temperature channel (TEMP)
- Reset and invalidate (read initial temperature)
- Add temperature channel to module
- Setup ADC/DAC:
- Create AD5593R at I²C address 0x10
- Configure 8 analog channels:
- ISET1, ISET2 (OUT, DAC)
- IMEAS1 (IN, gain=0.5), IMEAS2 (IN, gain=0.5)
- VMEAS1 (IN, gain=10), VMEAS2 (IN, gain=10)
- VREM1 (IN, gain=10), VREM2 (IN, gain=10)
- Enable double ADC range mode
- Disable double DAC range mode
- Reset and update ADC
- Add all ADC channels to module
- Setup LED driver:
- Create LP5012 at I²C address 0x14
- Initialize 4 RGB LEDs (D2, D3, D4, D5)
- Create 12 hidden ratiometric channels (4 LEDs × 3 RGB)
- Default luminance: 0.2 (20%)
- Reset LED controller
- Add power channels:
- POWER1 (IN, calculated: V×I for channel 1)
- POWER2 (IN, calculated: V×I for channel 2)
- Add energy channels:
- JOULES1 (IN, integrated power for channel 1)
- JOULES2 (IN, integrated power for channel 2)
- Setup calibration:
- Initialize calibration helper
- Load calibration table from persistent storage (or create defaults)
- Add CALIBRATION channel for user access
- Set initial LED colors:
- D2: Yellow (CH2 off)
- D3: Black (off)
- D4: Black (off)
- D5: Yellow (CH1 off)
Typical Use Cases
1. Battery Discharge Test:
// Set constant current load
SetValues(
new[] { "0.ESH10000536.ISET1" },
new[] { "0.5" } // 0.5A discharge current
);
// Monitor battery voltage and energy
while (true)
{
string[] data = GetValues(new[] {
"0.ESH10000536.VMEAS1",
"0.ESH10000536.IMEAS1",
"0.ESH10000536.JOULES1"
});
double voltage = double.Parse(data[0]);
double current = double.Parse(data[1]);
double energyWh = double.Parse(data[2]) / 3600.0; // Convert Ws to Wh
Console.WriteLine($"V:{voltage:F3}V, I:{current:F3}A, Energy:{energyWh:F2}Wh");
// Stop at cutoff voltage
if (voltage < 2.7)
{
SetValues(new[] { "0.ESH10000536.ISET1" }, new[] { "0" });
Console.WriteLine($"Discharge complete. Capacity: {energyWh:F2}Wh");
break;
}
Thread.Sleep(10000); // Match invalidation interval
}
2. Power Supply Load Regulation Test:
// Test power supply regulation under varying loads
var loadSteps = new[] { 0.1, 0.5, 1.0, 2.0, 3.0, 2.0, 1.0, 0.5, 0.1 };
foreach (var loadA in loadSteps)
{
// Set load current
SetValues(new[] { "0.ESH10000536.ISET1" }, new[] { loadA.ToString() });
Thread.Sleep(5000); // Allow stabilization
// Measure voltage regulation
string[] measurements = GetValues(new[] {
"0.ESH10000536.VMEAS1",
"0.ESH10000536.IMEAS1",
"0.ESH10000536.POWER1"
});
Console.WriteLine($"Load:{loadA:F1}A, Voltage:{measurements[0]}V, " +
$"Current:{measurements[1]}A, Power:{measurements[2]}W");
}
// Disable load
SetValues(new[] { "0.ESH10000536.ISET1" }, new[] { "0" });
3. Dual-Channel Synchronized Load:
// Apply load to both channels simultaneously
SetValues(
new[] {
"0.ESH10000536.ISET1",
"0.ESH10000536.ISET2"
},
new[] {
"1.5", // Channel 1: 1.5A
"1.0" // Channel 2: 1.0A
}
);
// Monitor combined power dissipation
Thread.Sleep(10000);
string[] combined = GetValues(new[] {
"0.ESH10000536.POWER1",
"0.ESH10000536.POWER2",
"0.ESH10000536.JOULES1",
"0.ESH10000536.JOULES2",
"0.ESH10000536.TEMP"
});
double totalPower = double.Parse(combined[0]) + double.Parse(combined[1]);
double totalEnergy = double.Parse(combined[2]) + double.Parse(combined[3]);
double temperature = double.Parse(combined[4]);
Console.WriteLine($"Total Power: {totalPower:F2}W");
Console.WriteLine($"Total Energy: {totalEnergy:F1}J");
Console.WriteLine($"Module Temp: {temperature:F1}°C");
if (totalEnergy > 200)
Console.WriteLine("WARNING: Approaching 250J safety limit!");
4. Thermal Characterization:
// Apply sustained load and monitor thermal response
SetValues(new[] { "0.ESH10000536.ISET1" }, new[] { "2.0" });
var startTime = DateTime.Now;
while (true)
{
string[] thermal = GetValues(new[] {
"0.ESH10000536.TEMP",
"0.ESH10000536.POWER1",
"0.ESH10000536.JOULES1"
});
double temp = double.Parse(thermal[0]);
double power = double.Parse(thermal[1]);
double energy = double.Parse(thermal[2]);
var elapsed = (DateTime.Now - startTime).TotalMinutes;
Console.WriteLine($"T+{elapsed:F1}min: Temp={temp:F1}°C, " +
$"Power={power:F1}W, Energy={energy:F0}J");
// Stop if thermal limit approached or energy limit
if (temp > 60 || energy > 240)
{
SetValues(new[] { "0.ESH10000536.ISET1" }, new[] { "0" });
Console.WriteLine("Thermal test complete - limit reached");
break;
}
Thread.Sleep(10000);
}
5. Energy Measurement with Reset:
// Measure energy for a specific test duration
SetValues(new[] { "0.ESH10000536.ISET1" }, new[] { "1.0" });
Thread.Sleep(60000); // Run for 60 seconds
string[] finalEnergy = GetValues(new[] { "0.ESH10000536.JOULES1" });
double energyJ = double.Parse(finalEnergy[0]);
double energyWh = energyJ / 3600.0;
Console.WriteLine($"Energy consumed: {energyJ:F1}J ({energyWh:F4}Wh)");
// Reset energy counter by disabling and re-enabling
SetValues(new[] { "0.ESH10000536.ISET1" }, new[] { "0" });
Thread.Sleep(1000);
SetValues(new[] { "0.ESH10000536.ISET1" }, new[] { "1.0" });
// JOULES1 now reset to 0 and begins accumulating again
Debugging and Troubleshooting
Problem: Current measurement reads 0 even when load is active
- Check: ISET value is actually > 0
- Check: Verify load is enabled (m_Channel1LoadEnabled flag)
- Action: GetValues() triggers invalidation which updates measurements
- Note: If load is disabled internally, current is forced to 0 even if ADC reads non-zero
Problem: Energy counter not incrementing
- Check: POWER channel is > 0 (requires both voltage and current)
- Check: Measurement interval (10s) has elapsed
- Check: Load is enabled (ISET > 0)
- Action: Call GetValues() to trigger invalidation cycle
Problem: Load shuts down unexpectedly
- Check: Total energy (JOULES1 + JOULES2) may have exceeded 250J limit
- Check: Temperature may be above error threshold (65°C)
- Action: Review logs for "Excessive power dissipation" warning
- Solution: Reduce load current or duration to stay under energy limit
Problem: Fan not running
- Check: At least one load channel is enabled (ISET1>0 or ISET2>0)
- Check: I²C communication with MAX6650 at 0x48
- Check: Fan is physically connected and functional
- Action: Run I2C scan to verify device presence
Problem: Temperature readings seem incorrect
- Check: TMP116 I²C communication at address 0x49
- Check: Values outside -100°C to +200°C are ignored as invalid
- Try: Reset module to reinitialize sensor
- Verify: Sensor is properly mounted with thermal contact
Problem: LED colors not updating
- Check: LP5012 I²C communication at address 0x14
- Check: Luminance ratio is set (default 0.2)
- Action: LED color updates are automatic on ISET changes
- Verify: UpdateLEDColor() is being called on SetValues()
Problem: Power calculation seems wrong
- Check: Voltage and current measurements are correct
- Check: Gain factors for VMEAS (10) and IMEAS (0.5) are applied
- Verify: Calculation: POWER = VMEAS × IMEAS
- Note: Power is only calculated during invalidation cycles (10s interval)
Problem: Calibration changes not taking effect
- Check: Calibration table was written to CALIBRATION channel
- Check: Gain and offset values are reasonable (not NaN or infinity)
- Action: Re-apply calibration by writing to CALIBRATION channel
- Verify: ConfigureChannels() is called to apply new calibration to ADC
Hardware Considerations
Current Measurement Accuracy:
- Gain factor of 0.5 suggests 2× voltage divider or shunt amplifier
- Verify shunt resistor value for expected current range
- Calibration critical for accurate current measurement
Voltage Measurement Accuracy:
- Gain factor of 10 suggests 10:1 voltage divider
- Supports voltage measurements up to ~50V (10 × 5V ADC range)
- Use VREM channels for Kelvin (4-wire) sensing for accurate measurement
Power Dissipation Limits:
- 250J energy limit is safety protection, not continuous rating
- Module likely rated for lower continuous power dissipation
- Monitor TEMP channel to ensure safe operating temperature
- Fan provides active cooling but has limits
Thermal Management:
- TMP116 measures module temperature, not load temperature
- Fan speed is binary: full speed when load active, off when disabled
- Temperature regulation affects warnings/errors but not fan speed
- Ensure adequate airflow and heat sinking for sustained loads
Comparison with Standard Electronic Loads
| Feature | ESH10000536 (M.2 Active Load) | Benchtop Electronic Load |
|---|---|---|
| Form Factor | M.2 compact module | Benchtop instrument |
| Channels | 2 independent | 1-4 typical |
| Current Control | DAC setpoint (I²C) | Front panel/remote |
| Measurement | Voltage, Current, Power, Energy | Similar + more modes |
| Energy Limit | 250J automatic shutdown | Continuous rating typical |
| Thermal Protection | Automatic (temp + energy) | Automatic (varies) |
| Fan Control | Automatic binary (on/off) | Variable speed typical |
| Remote Sensing | Yes (VREM channels) | Yes (Kelvin sensing) |
| Calibration | Per-channel user-accessible | Factory calibration typical |
| Integration | I²C, embedded systems | SCPI, test automation |
Revision History
- ESH10000536: Current production version
- 2 independent active load channels
- AD5593R ADC/DAC (8 channels, 12-bit, I²C 0x10)
- TMP116 temperature sensor (I²C 0x49)
- MAX6650 fan controller (I²C 0x48, 30k RPM max)
- LP5012 LED driver (4 RGB LEDs, I²C 0x14)
- Current control (ISET1, ISET2)
- Voltage measurement (VMEAS1, VMEAS2, VREM1, VREM2)
- Current measurement (IMEAS1, IMEAS2)
- Power calculation (real-time V×I)
- Energy integration (joules accumulation)
- Automatic safety shutdown at 250J
- Temperature-based warnings and errors
- Calibration support (persistent storage)