The MCP4728 is a quad-channel, 12-bit, buffered voltage-output DAC from Microchip with an I²C interface and onboard nonvolatile EEPROM. It's a resistor-string architecture intended for applications that need a precise, low-power DAC with moderate bandwidth — set-point and offset trimming, sensor calibration, portable battery-powered instrumentation, and motor speed control. Its differentiator is persistence: DAC codes, the I²C address bits, reference selection, gain, and power-down bits all live in EEPROM, so outputs return to their last stored values on power-up with no host re-programming. Supply range is 2.7–5.5 V, the output buffer is rail-to-rail with roughly 6 µs settling, and all four channels together draw 800 µA typ at VDD = 5.5 V with all channels in Normal mode — dropping to 40 nA standby when fully powered down with the external (VDD) reference.
What is the MCP4728 actually for? (What is this part and what's it for?)
The datasheet positions it as a general-purpose resistor-string DAC "intended to be used in applications where a precise and low power DAC, with moderate bandwidth, is required." The manufacturer's applications list includes set point or offset adjustment, sensor calibration, closed-loop servo control, low-power portable instrumentation, programmable voltage and current sources, industrial process control, and bias voltage adjustment for power amplifiers. The applications section narrows this to set-point/offset trimming, sensor calibration, battery-powered portable instrumentation, and motor speed control.
The worked example in the datasheet is a DC set-point application: four channels generating four different trip voltages for calibrating a sensor offset or bias point, programmed via Sequential and Fast Write commands.
Equally important is what it's not for. The datasheet never frames it for high-speed or waveform-generation work — it's explicitly low-power, moderate-bandwidth, DC-set-point oriented, which is consistent with its settling and stability profile. If you need fast arbitrary waveform output, this isn't your part.
How do I wire it up? (Integration and surrounding components)
Power and decoupling. Run VDD in the 2.7–5.5 V operating range and never exceed 6.5 V absolute max — size your input rail so supply transients stay well below that. Bypass VDD with a 0.1 µF ceramic and a 10 µF tantalum in parallel, placed within 4 mm of the pin. This matters more than usual: when VREF = VDD, the supply is the DAC reference, so supply noise degrades DAC performance directly. If you have separate digital and analog planes, keep the MCP4728's VDD/VSS on the analog plane.
I²C bus. SCL and SDA are open-drain N-channel drivers, so pull-ups to VDD are mandatory. Size them for 5–10 kΩ at 100–400 kHz, roughly 700 Ω for 3.4 MHz High-Speed mode, and go smaller if bus capacitance is high. The part's own input capacitance is ≤3 pF with ±1 µA leakage, so the pull-up is driven mainly by total bus capacitance and bus speed — Fast mode (400 kHz) allows an SCL rise time up to 300 ns. The part is slave-only; SCL accepts external clocks only. Digital inputs are Schmitt-triggered with VIL = 0.3·VDD and VIH = 0.7·VDD, so your pull-up rail or level translation must actually reach ≥0.7·VDD for a clean high.
LDAC. Two valid choices: tie it permanently low so every channel's input register transfers to the output at the last acknowledge pulse (a zero-external-component option), or drive it from an MCU GPIO to update all four outputs simultaneously on the high→low edge. It's a high-impedance digital input — drive it actively rather than leaving it floating. One more reason to give LDAC its own GPIO per device: if you ever put multiple MCP4728s on one bus, LDAC is the only mechanism for isolating a factory-default part during address programming (more below).
RDY/BSY. This is a real open-drain pin, not just a register flag. Give it a ~100 kΩ pull-up from VDD, or leave it floating if you don't use it.
Protection. All pins carry ≥4 kV HBM / ≥400 V MM ESD protection built in. For pins exposed at board edges, remember the absolute-max pin range is −0.3 V to VDD+0.3 V with input current limited to ±2 mA — a series resistor on the I²C lines provides over-voltage/current limiting.
What are the traps specific to this part? (What should I watch out for?)
The address is in EEPROM, not on pins. The A2/A1/A0 device address bits live in EEPROM with factory default "000" — there are no address straps. You reprogram them over the bus with the Write I²C Address Bits command (C2=0, C1=1, C0=1, max 400 kHz). The command requires the current address, and LDAC must be pulled High→Low at the low time of the 8th clock of the second byte and held low through the end of the third byte; the update occurs after the Stop bit. If multiple factory-default (000) parts share a bus, all of them respond simultaneously — the only per-device selector is LDAC, so each device needs its own LDAC line. Program one device at a time: hold all other LDAC lines high, run the command, wait out the EEPROM write, power-cycle (or send General Call Reset 0x06), then move to the next device.
The gain bit only works with the internal reference. Per-channel gain of ×1 or ×2 is applicable only when the internal VREF is selected. If VREF = VDD, the device uses gain 1 regardless of the gain bit — setting gain 2 on a VDD-referenced channel silently does nothing.
Factory defaults use the internal reference. All four channels power up with VREF bit = 1 (internal 2.048 V bandgap). Design your scale factor around that on first boot. With the internal reference and gain ×1, LSB = 0.5 mV and full-scale is 2.048 V; gain ×2 gives 1 mV LSB and 4.096 V full scale. If you feed 3.3 V expecting a 0–3.3 V swing, you won't get it. Conversely, the internal reference self-disables when all channels select VREF = VDD, so going all-external draws no bandgap current.
EEPROM writes block the device. EEPROM write time is 25 ms typ / 50 ms max, and any command received during an EEPROM write is silently ignored. RDY/BSY goes low only while programming is in progress. Poll RDY/BSY (at the pin or via the read-command flag) or time out before sending the next command after any EEPROM-writing transaction.
Pick the right write command. Whether a write touches EEPROM depends entirely on the command code: Fast Write (C2=0, C0=X) updates input registers A–D only; Multi-Write updates one input register at a time, no EEPROM; the Write DAC Register and EEPROM commands (Sequential/Single Write) are the slow path that triggers RDY/BSY and the command-ignore window. Use Fast/Multi-Write for live updates; reserve EEPROM writes for persistence events. Note the datasheet publishes data retention (200 years typ @ +25 °C) but no write-cycle endurance rating — so don't treat EEPROM writes as free.
Power-down states and sleep math. Each channel's PD1/PD0 bits choose Normal, or VOUT terminated to ground through 1 kΩ, 100 kΩ, or 500 kΩ — pick per your leakage-vs-impedance trade. Full power-down with external reference draws 40 nA typ; with the internal reference kept on it's 45 µA typ / 60 µA max — a 1000× difference if you forget to switch to VDD reference before sleeping.
Reference switching has its own settle delay. 26 µs typ external→internal, 44 µs internal→external. If firmware toggles the VREF bit at runtime, wait these out before trusting the output.
Known limitation: the datasheet publishes no numeric POR/startup-ready time (time from VDD crossing the ~2.0–2.2 V POR threshold to ACKing on I²C) and no EEPROM write-cycle endurance rating. Poll the POR status bit via the I²C read command after power-up rather than relying on a fixed delay, and treat endurance as an unknown.
How do I test it? (Verification procedure)
With the internal reference at gain 1, 1 LSB = 0.5 mV, so the ½-LSB settling target is 0.25 mV — you need a DMM with sub-millivolt resolution and noise floor to verify settling and the 20 mV offset bound. A concise bench run-list:
| Step | What to do | Pass criteria (datasheet) |
|---|---|---|
| 1 | Ramp VDD slowly, probe for POR | ramp ≥1 V/s; operable above ~2.2 V |
| 2 | I²C ACK + read-back at target speed | ACK at ≤400 kHz (2.7–5.5 V) |
| 3 | Output @ code 000h | ≤20 mV offset |
| 4 | Output @ code FFFh | within ±1.25% FSR gain error |
| 5 | Linearity sweep 100–4000 | INL ≤±13 LSB, DNL within ±0.75 LSB |
| 6 | Step ¼→¾ FS, scope settling | settles to ½ LSB within 6 µs typ |
| 7 | Write to EEPROM, power-cycle | value persists; wait ≥50 ms / poll RDY/BSY |
| 8 | Measure standby | ~40 nA (ext ref) vs 45 µA (int ref) |
The pass criteria come straight from the datasheet's electrical-characteristics and timing tables; the DMM-resolution guidance is engineering practice.
Use the read command to verify configuration, not just DAC values. Each channel returns a 24-bit frame: bit 23 is the RDY/BSY flag (1 = no EEPROM write in progress), bits 22–20 echo A2/A1/A0, bit 19 is VREF, bits 17–16 the channel ID (DAC1/DAC0), bits 15–14 PD1/PD0, bit 13 Gx, and bits 11–0 the DAC code. A solid firmware pattern after any write: read, confirm RDY/BSY = 1, confirm the channel ID matches, then compare VREF/Gx/PD bits and the code against what you wrote. For an authoritative address read, use the General Call Read Address Bits command (address 0x00, second byte 0x0C) instead of the per-channel echo.
Why isn't it behaving? (Troubleshooting)
Output stuck low or "missing." First check the power-up ramp — it needs ≥1 V/s for POR/EEPROM readiness, with the POR threshold around 2.2 V typ. Then check your full-scale math: FSR is VDD (VREF=VDD), VREF (internal, gain 1), or 2×VREF (internal, gain 2). An output that only swings 0–2.048 V isn't a fault — it's the internal reference at gain 1, which is the factory default.
Wrong output level / scale error. The internal reference is 2.048 V typ but ranges 2.007–2.089 V, so a unit measuring slightly off nominal is within tolerance. And remember gain ×2 is ignored when VREF = VDD.
Output slow after a code change. Settling is 6 µs typ (¼→¾ FS step), but add 26 µs (ext→int) or 44 µs (int→ext) if you switched the reference at runtime, and 4.5 µs typ to wake from power-down.
Output oscillates. Capacitive load must stay ≤1000 pF at RL = 5 kΩ for stability — an oversized bypass on VOUT is the usual culprit. Keep RL > 5 kΩ for best accuracy.
Commands appear ignored. If the previous command wrote EEPROM, the device ignores everything for 25–50 ms — poll RDY/BSY. If you're using an LDAC pulse to latch, it must be low ≥210 ns; shorter pulses don't update.
No I²C response. Check bus speed vs. voltage: 400 kHz Fast mode needs ≥2.7 V with ≤400 pF bus cap; 3.4 MHz High-Speed requires ≥4.5 V and only ≤100 pF. Scope SDA/SCL — the rise time must be ≤300 ns in Fast mode, and weak/too-large pull-ups stretching it cause missed ACKs. Verify levels actually cross VIH ≥ 0.7·VDD / VIL ≤ 0.3·VDD.
Bus won't idle high. SDA and RDY/BSY are open-drain and must pull to ≤0.4 V at 3 mA sink. A line sitting half-pulled usually means a missing or open pull-up.
Standby current is microamps, not nanoamps. The internal reference is still enabled — switch channels to VREF = VDD before powering down to hit the 40 nA figure.
Small glitch on mid-scale transition. Major-carry glitch is 45 nV·s typ (7FFh→800h) with crosstalk <10 nV·s — that's normal, not a fault.
Part page: MCP4728.