1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
//! REF_A — the shared voltage-reference module.
//!
//! Every measurement the [`crate::adc`] makes is a *ratio*: the SAR reports
//! what fraction of VR+ the input sits at. With the reset-default `VRSEL = 0`
//! that VR+ is AVCC itself, so results are ratiometric — fine for a
//! potentiometer, useless for an absolute voltage, because the "ruler" is
//! whatever the supply happens to be. REF_A is the on-chip precision ruler: a
//! **bandgap** (a circuit whose output is flat over temperature and supply,
//! ~1.2 V by physics) plus a programmable buffer that scales it to **1.2 V,
//! 2.0 V, or 2.5 V**. Point the ADC at it (`VRSEL = 1`) and a count is worth a
//! fixed number of microvolts regardless of the battery sagging.
//!
//! # One register, and a handshake instead of a delay
//!
//! The whole module is a single register, `REFCTL0`:
//!
//! - **`REFVSEL`** picks 1.2/2.0/2.5 V; **`REFON`** turns the generator on.
//! - **`REFGENBUSY`** is a *write gate*: while the generator is actively
//! servicing a conversion, *all writes to `REFCTL0` are silently ignored* —
//! the hardware protects an in-flight conversion from its reference being
//! yanked. So the driver must check it **before** writing, not after.
//! - **`REFGENRDY`** is the *settled* flag. The bandgap and buffer need tens
//! of microseconds to charge their internals after `REFON`; converting
//! before that samples a still-rising reference. Polling `REFGENRDY`
//! replaces the open-loop `__delay_cycles(75)` seen in TI examples with the
//! hardware's own word that the output is stable. Both waits are internal
//! (no pin, no external clock), so neither poll can hang the way an I2C
//! bus wait can.
//! - **`REFTCOFF`** — the **temperature sensor lives in this module**, not in
//! the ADC: it is a diode stack biased by the reference generator, and it is
//! simply unpowered until `REFON` is set (with `REFTCOFF = 0`, the reset
//! default, which this driver keeps). This is why
//! [`crate::adc::Adc::read_temperature_raw`] reads a flat ~0 without REF_A —
//! verified on hardware 2026-06-27 — and why the [`Ref`]-taking read methods
//! exist.
//!
//! On this FR59xx generation REF_A is the *sole* owner of the reference —
//! older F5xx parts had duplicate legacy control bits inside the ADC plus a
//! `REFMSTR` arbitration bit; here there is nothing to arbitrate, the ADC just
//! consumes whatever REF_A produces.
//!
//! # `REFOUT` — the reference on a pin
//!
//! [`Ref::enable_output`] buffers VREF onto the **P1.1** pad (the package's
//! VREF+ function) for external circuitry — or, hands-free, for *other on-die
//! consumers that can only see pads*: [`crate::comp_e`]'s input channels tap
//! pads, so REFOUT on P1.1 = C1 is the one way to present a known mid-rail
//! analog voltage to the comparator with no wiring at all (the comp
//! integration fixture sweeps the comparator's VCC ladder against it). Takes
//! the P1.1 `Analog` typestate pin as proof the digital path is disconnected.
//! LaunchPad caveat: P1.1 is also button S2 — a held button shorts REFOUT to
//! ground.
//!
//! # Choosing the voltage
//!
//! Full scale is VR+, so pick the smallest reference that still covers the
//! signal — smaller reference, smaller µV/count, finer resolution:
//!
//! - **1.2 V**: the temperature sensor (~0.7 V) at best resolution.
//! - **2.0 V**: the sweet spot when one reference must serve both the
//! temperature sensor and the supply monitor — AVCC/2 at a 3.3 V supply is
//! 1.65 V, which *clips at 1.2 V* but fits under 2.0 V (covers AVCC to 4 V).
//! - **2.5 V**: headroom for external signals up to 2.5 V.
//!
//! The factory TLV calibration ([`crate::tlv`]) stores constants for each of
//! the three settings, so any choice can be fully corrected.
//!
//! # Example
//!
//! ```ignore
//! let vref = Ref::new(p.shared_reference, ReferenceVoltage::V2_0); // settled on return
//! let mut adc = Adc::new(p.adc12, Config::default().sample_time(SampleTime::Cycles256));
//! let t_raw = adc.read_temperature(&vref); // sensor powered, VREF-referenced
//! let avcc = adc.read_supply_millivolts(&vref); // an actual voltage, not a ratio
//! ```
use cratepac;
/// The three output voltages the reference buffer can produce (`REFVSEL`).
/// The REF_A reference generator, on and settled.
///
/// Constructing a `Ref` performs the full bring-up handshake, so *holding one
/// is proof the reference (and the temperature sensor it biases) is powered
/// and stable* — which is why the VREF-referenced [`crate::adc::Adc`] read
/// methods take `&Ref`: a conversion against an unpowered reference is
/// unrepresentable, and the borrow keeps the reference alive (un-`free`-able)
/// for the duration of the read.