Lots of doc updates

main
alexis 2023-01-02 22:56:15 -07:00
parent e38da22af5
commit c4755a233a
4 changed files with 189 additions and 13 deletions

View File

@ -1128,9 +1128,6 @@
(junction (at 71.12 91.44) (diameter 0) (color 0 0 0 0)
(uuid a46fcb78-250d-4921-8a87-b2519402d8d7)
)
(junction (at 129.54 149.86) (diameter 0) (color 0 0 0 0)
(uuid a89299d5-5402-4f09-9626-aed55f7bcb19)
)
(junction (at 71.12 81.28) (diameter 0) (color 0 0 0 0)
(uuid aabfff1a-dfb8-4c4c-9f00-4d2023e80623)
)
@ -1424,6 +1421,10 @@
(stroke (width 0) (type dash_dot) (color 72 72 72 1))
(uuid 526975f9-28b2-44bb-9fe9-c9267356a875)
)
(polyline (pts (xy 19.05 135.89) (xy 19.05 156.21))
(stroke (width 0) (type dash))
(uuid 53e88d33-3f12-441c-9809-ed9a17708df3)
)
(bus (pts (xy 260.35 82.55) (xy 260.35 86.36))
(stroke (width 0) (type default))
@ -1778,10 +1779,6 @@
(uuid d12306e0-a553-4ecb-88eb-4915b66e3cd9)
)
(wire (pts (xy 129.54 157.48) (xy 129.54 149.86))
(stroke (width 0) (type default))
(uuid d451bbb0-9df7-4113-b76f-c2fba12c0a33)
)
(wire (pts (xy 71.12 81.28) (xy 71.12 76.2))
(stroke (width 0) (type default))
(uuid d451c38e-19df-4720-a790-d167fcb3dff6)
@ -1893,6 +1890,10 @@
(stroke (width 0) (type default))
(uuid fa50c382-0229-4bdc-9705-9e1c11adbc78)
)
(polyline (pts (xy 19.05 135.89) (xy 58.42 135.89))
(stroke (width 0) (type dash))
(uuid fb5bc4bc-6f46-407a-830b-17683886ee71)
)
(polyline (pts (xy 242.57 97.79) (xy 242.57 95.25))
(stroke (width 0) (type dash))
(uuid fbe88ee7-e830-43ee-a0c5-fef329707871)
@ -1956,6 +1957,10 @@
(effects (font (size 1.27 1.27)) (justify left bottom))
(uuid 413f4c64-5596-4695-820b-f338519a1161)
)
(text "IMPLEMENATION NOTE" (at 20.32 139.7 0)
(effects (font (size 1.27 1.27) (thickness 0.254) bold) (justify left bottom))
(uuid 4969b734-3d23-44ee-b68c-2af7bedb09e7)
)
(text "U5" (at 19.05 195.58 0)
(effects (font (size 1.27 1.27)) (justify left bottom))
(uuid 49c37a0c-6206-4162-90bc-c6c4ef1879f5)
@ -2067,6 +2072,11 @@
(effects (font (size 1.27 1.27)) (justify left bottom))
(uuid d3e36383-c510-4f37-a6d8-5cc3d140c7af)
)
(text "Implementers may tie R16 to the\nmicrocontroller supply rail instead\nof +5V and then omit R17, substantially\nreducing standby power consumption."
(at 20.32 154.94 0)
(effects (font (size 1.27 1.27)) (justify left bottom))
(uuid d6f7b278-7bd6-4471-9c6f-a381c7c98913)
)
(text "Low charge injection variant of 74HCT4051. Critical for performance"
(at 57.15 190.5 0)
(effects (font (size 1.27 1.27)) (justify left bottom))

Binary file not shown.

View File

@ -19,28 +19,194 @@ and layout quality.
## Hardware
TODO: reference design here
TODO: reference design here, need a nice crisp PNG
### Reference chopper
Analog switch `U1B` implements a constant-impedance reference chopper. By
sending the voltage reference either into the 0V virtual ground of the
integrator or directly into ground, it ensures that the load on the voltage
reference is stable — the AC peak-to-peak component is equal to the integrator
offset voltage divided by the slope resistor, or about 12 nA on 30 µA. This
stability ensures that the voltage reference output impedance and load
regulation error do not come into play, which provides a few LSBs improvement
to INL with typical voltage references.
### Integrator and ramp inverter
Op amp `U2A` is connected as an inverting integrator, so when a positive-going
pulse is applied to it, a negative-going ramp is produced. Because the reference
chopper fully disconnects the reference during the space period rather than
applying 0V, `U2A`'s input offset voltage is not integrated into an error term;
only the leakage current is integrated. This will eventually add up to an
error, so the discharge switch is held engaged whenever possible, and because
`U2` is a low-leakage JFET op amp, the resulting error is negligible.
Analog switch `U1C` discharges the integrating capacitor through `R4` when
switched on; `R4` is also shared with the sample-and-hold circuit as the
charging resistor for negative ramps.
Because there are few options for noninverting integrators that provide the
speed and precision needed, a second op amp `U2B` inverts the inverted ramp,
producing a positive-going ramp. The resistor ratio on this inverter will
induce a gain error; the tuning comparator senses the _positive_ ramp in order
to prioritize this most likely polarity (TODO, #3).
### Tuning comparator
Comparator `U5` detects whether the positive-going ramp has crossed the
reference voltage. `R15` adds hysteresis, and `D1` blocks the hysteresis on
the leading edge so the switching threshold is as accurate as possible
(TODO rev 1.1 uses an RC circuit instead).
The pulldown resistor R17 reduces the output voltage from 5V to 3.3V. As per
the note in the schematic, it can be removed if R16 pulls up to the system
IO voltage.
### Polarity switch and output multiplexer
Analog switch `U1A` selects between the positive and negative ramps; it may
be omitted for non-bipolar designs. The selected ramp is steered to the
output capacitors through multiplexer `U3`, which is inhibited until the ramp
has stabilized.
### Sample-and-hold amplifiers
The output capacitor bank holds the output voltages in between pulse transfers.
To stabilize the output voltage, they are buffered by high-impedance op amps
`U4A` etc. Charging current is limited by resistor `R4` (for negative ramps)
or `R5` (for positive ramps); these are placed on the pre-multiplexer side to
reduce part count.
## Firmware
### Layer 1: low-level DAC driver
TODO: state diagram here
The low-level driver steps the external hardware through its various states.
It is responsible for discharging the integrator, generating a pulse to be
integrated into a ramp, waiting for the integrator to stabilize, and finally,
either transferring the final ramp value to the output or using it for tuning.
```
┌────┐
│IDLE│ ◄───────────────────────────────┐
└┬───┘ │
│ │
│emit or tune │
▼ │
┌─────────┐ │
│DISCHARGE│ │
└┬────────┘ │
│ │
│ │
┌┴────┐ │
│PULSE│ │
└┬────┘ │
│ │
▼ │
┌─────────┐tune ┌────────────────┐ │
│STABILIZE├─────►│Evaluate tuning ├────┘
└┬────────┘ └────────────────┘ ▲
│emit │
▼ │
┌────────┐ │
│TRANSFER├─────────────────────────────┘
└────────┘
```
### Layer 2: tuning driver
TODO: state diagram here
The tuning driver, which is also part of `timdac_ll.c`, exists as an
intermediate layer between the low-level and high-level driver. It is triggered
by the high-level driver, and itself triggers the emission of one pulse from
the low-level driver. The pulse it emits, and the comparator output at the
end of that pulse, is used as the comparison in a binary-search successive
approximation. Each time it runs, the range is narrowed by half, until it has
been narrowed down to a single value. Once this happens, the resulting
measurement is pushed into a low-pass filter, which smooths the tuning over
time to reduce noise, and the output of this filter provides the tuning
scale factor.
### Layer 3: scan driver
```
┌────┐
│Idle│ ◄──────────────────────────────────────────┐
└┬───┘ │
│timdac_ll_tune() │
▼ │
┌──────────────┐ no ┌──────────────────┐ │
│top/bot valid?├────────┤Reinit to 65535, 0├──────┘
└┬─────────────┘ └──────────────────┘ ▲
│yes │
▼ │
┌────────────────┐ no ┌──────────────────────┐ │
│top/bot unequal?├─────►│Tuning is complete ├──┘
└┬───────────────┘ │Push top/bot into the │ ▲
│yes │tuning low-pass filter│ │
│ └──────────────────────┘ │
▼ │
┌──────────────────────────────────────┐ │
│Start a pulse with width = (top+bot)/2│ │
└┬─────────────────────────────────────┘ │
│ │
▼ │
┌─────────────────────────────────┐ │
│Read the tuning comparator output│ │
└┬───────────────┬────────────────┘ │
│ramp<vref ramp>vref │
│ │ │
▼ ▼ │
┌─────────┐ ┌─────────┐ │
│bot = mid│ │top = mid│ │
└┬────────┘ └┬────────┘ │
│ │ │
└─────────────► └────────────────────────────────┘
```
TODO: state diagram here
### Layer 3: scan (high-level) driver
The high-level driver sequences all of the above continuously through its
various states. It is triggered by the timer stop interrupt, and always starts
the timer, so it will continue forever (TODO, #1).
If the first tuning cycle has not yet completed, it will always initiate the
next phase, so that outputs are never scanned prior to a tuning. It will also
initiate a scan periodically, as defined by `TIMDAC_TUNE_INTERVAL`. If there
is no tuning needed, it will next check to see if a channel is in the
queue-jump pending slot, and if there is, this channel is emitted next. When
this happens, the queue-jump slot is "blanked" for one cycle so that rarely
updated channels always get scanned. If none of these less common scenarios
occur, the next channel in a simple round-robin scan sequence is emitted.
```
┌─────────────────────┐ ┌──────────────────────┐
│Step low-level driver│◄───────────────────┤Wait for timer to stop│
└┬────────────────────┘ └──────────────────────┘
│ ▲
▼ │
┌──────────────────────┐ no ┌─────────────┐ │
│First tuning complete?├─────►│Initiate tune├───────────────────┘
└┬─────────────────────┘ └─────────────┘ ▲
│yes ▲ │
▼ │ │
┌────────────────────────┐ yes │ │
│Reached tuning interval?├───────────┘ │
└┬───────────────────────┘ │
│no │
▼ │
yes ┌────────────────────────┐ │
┌───┤Queue-jump slot blanked?│ │
│ └┬───────────────────────┘ │
│ │no │
│ ▼ │
│ ┌───────────────────────────┐ yes ┌─────────────────┐ │
│ │Channel in queue-jump slot?├─────►│Emit queue jumper│ │
│ └┬──────────────────────────┘ └┬────────────────┘ │
│ │no │ │
│ │ ▼ │
│ │ ┌─────────────────────┐ │
│ │ │Blank queue-jump slot├──────┘
│ ▼ └─────────────────────┘ ▲
│ ┌─────────────────┐ │
└──►│Emit next channel├─────────────────────────────────────────────┘
└─────────────────┘
```

View File

@ -65,7 +65,7 @@ void timdac_ll_init(void)
bool timdac_ll_tune(void)
{
if (_tune_sar_top == 0 || _tune_sar_bot == UINT16_MAX)
if (_tune_sar_top < _tune_sar_bot)
{
// Start fresh.
_tune_sar_top = UINT16_MAX;