Here are some notes about the PWM software.
The PWM is full range.
The output voltage is between 0 volt and the 7 volt reference voltage.
#1
The unit for the width is one clock cycle (1/16MHz).
If the count is zero, all pulses have width 0.
If the count is increased then pulses with width 1 appear.
This continues until there are 300 pulses with width 1.
If the count is increased beyond 300 then pulses with width 2 appear.
This continues until all 300 pulses have width 2.
There are 3 operating regions:
1. In the first region pulses with width 1 appear.
The width of these pulses is NOT exactly 1 clock cycle.
The level shifter between 5 volt and the reference voltage is not ideal.
The rise and fall time can differ.
What matters is the actual width.
The region is very small: 12V / 53333 = 225 uV.
2. In the second region the width of pulses is increased by 1.
The increment of the width is exactly 1 clock cycle.
The pulses are longer, with a constant width error.
3. In the third region, at the top of the range, pulses disappear.
It is the inverse of the first region.
Each of the 3 regions has a different slope.
The error can be corrected with one parameter.
The processor frequency is 16 MHz, the period is 62.5 ns.
The PWM frequency is 300 Hz, the PWM period is 3.3 ms.
A change in the width by 3.3 ns gives 1e-6 error.
#2
The pulse width can be set from 1 to the period count.
Zero width is not included.
Zero width can be implemented by setting the output to 0.
But then PWM interpolation between 0 and 1 is not possible.
The solution is to invert both the count and the polarity of the output.
#3
The polarity of the output voltage is reversed using two relays.
There are two signed zeros depending on the state of the relays.
The voltage difference between the two zeros is twice the output offset of the buffer.
It is an error of the voltage source.
The correction should be with done by a shift over the x-axis.
It is easier to do on the y-axis without any loss of accuracy.
The error is removed by shifting the positive and negative readings over the y-axis towards each other.
The relays are Coto 3402.
The datasheet has a picture of the offset over time after the relay is energized.
The drift in offset was 10 uV. The measured shift of relays used is less than 1 uV.
#4
With both relays energized the output is shorted.
The buffer's output is also shorted. Therefore the PWM voltage is set to zero volts.
In addition there is a 1 k ohm resistor in series with the buffer output.
#5
The calculation is done with integers.
The numerical accuracy is improved with guard digits.