Using a hardware PWM system based on a comparison-voltage source, a triangle-wave generator, and a comparator, you can set as many different output levels as your comparison-voltage source can generate. A charge-transfer system like that diagrammed below can be used to develop almost arbitrarily many different levels.
In operation, the voltage on C1 supplies one input to a comparator, via a unity-gain buffer. A triangle wave oscillator supplies the other input, generating a PWM signal.
The voltage on C1 is set by turning on, turning off, or setting to high-impedance one or more of digital inputs D1...D3, then turning on D4 for a controlled interval, to slightly raise or lower the voltage on C1. For example, suppose C1 = 0.1 μF and VC1 = 2 V. Turning on D4 for 1 ms with D1 on will raise VC1 by .21 V; turning on D4 for 4 μs with D3 on will raise VC1 by 8 μV.
If you want to control to about 1 part in 4 million using this method in simplest form, then R3 may need to be larger. But of course slightly more involved alternative schemes can get by with smaller resistors. For example, if R2 is 10 MΩ and R3 is 10.01 MΩ, you could raise VC1 by a few nV by turning on D2 high for a fraction of a microsecond, then returning it to high impedance and turning on D3 low for the same length of time, or could lower VC1 by doing vice versa; or could turn on both briefly high, then one briefly low, etc. Another approach is to have D4 trigger a one-shot that closes S1 for a few nanoseconds, rather than depending on use of a fast microcontroller clock.
If you actually use a system like this, write a program that computes voltage rates of change for all combinations of your digital inputs, at various voltages on C1. Also analyze the system for stability.
Note, D4 is controlling a JFET switch S1 to isolate C1 from leakage that could occur through D1-D3 if S1 were left out. For example, the Atmega328 data sheet shows a max leakage of 1 μA on typical inputs in high impedance state, which is about a million times the leakage of a good JFET. However, typical leakages of Atmega inputs – rather than max leakages – might be much less. One could run experiments to see if S1 is indeed necessary.