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
//! TLV — the factory device-descriptor table, and the ADC/REF calibration
//! constants stored in it.
//!
//! Every FR59xx die is measured on the production tester and the results are
//! burned into a reserved 256-byte FRAM window at **0x1A00–0x1AFF** as a
//! **T**ag-**L**ength-**V**alue table (SLAU367 §1.13): after an 8-byte info
//! block (CRC, device ID, revisions), entries of `[tag: u8, length: u8,
//! data: length bytes]` follow from **0x1A08**, terminated by tag `0xFF` or
//! the end of the window. Walking by tag — rather than hardcoding addresses —
//! is the documented procedure, and degrades to `None` instead of garbage if
//! a future die revision shuffles the layout.
//!
//! Two entries matter to the ADC path:
//!
//! - **Tag `0x11`, ADC12 calibration** (8 words): the gain factor and offset
//! of this specific converter, then the **measured temperature-sensor
//! readings at 30 °C and 85 °C** for each reference voltage (1.2/2.0/2.5 V
//! pairs, in that order). Two known (temperature → counts) points define the
//! sensor's line; interpolation between them is the entire thermometer.
//! - **Tag `0x12`, REF calibration** (3 words): the measured-vs-nominal ratio
//! of each REF_A output as a **1.15 fixed-point** factor (`2^15` = exactly
//! nominal). A "1.2 V" reference that actually produces 1.194 V stores
//! ≈ `32604`; multiplying a result by `factor / 2^15` cancels the deviation.
//!
//! Because the constants were measured *through this chip's own ADC*, the
//! temperature pairs already embed its gain/offset error — the temperature
//! interpolation therefore uses **raw** readings, while absolute-voltage
//! corrections chain gain → offset → REF factor explicitly (the methods here
//! delegate to the pure math in `adc_cal.rs`, host-tested in `unit_tests/`).
//!
//! Reads are plain loads: the table is ordinary (write-protected) FRAM. The
//! info-block CRC is not verified here.
//!
//! # Example
//!
//! ```ignore
//! let cal = tlv::adc_cal().unwrap(); // factory table — present on real silicon
//! let raw = adc.read_temperature(&vref);
//! let deci_c = cal.temp_deci_celsius(vref.voltage(), raw).unwrap(); // 273 = 27.3 °C
//! ```
use crateReferenceVoltage;
/// First tag byte (0x1A00–0x1A07 is the info block: CRC, device ID, revisions).
const TLV_START: u16 = 0x1A08;
/// Last byte of the descriptor window.
const TLV_END: u16 = 0x1AFF;
/// End-of-table marker tag.
const TAG_END: u8 = 0xFF;
/// ADC12_B calibration entry.
const TAG_ADC12_CAL: u8 = 0x11;
/// REF_A calibration entry.
const TAG_REF_CAL: u8 = 0x12;
/// Factory ADC12_B calibration: gain/offset of this die's converter and the
/// temperature-sensor characterization points, from TLV tag `0x11`.
/// Factory REF_A calibration: the measured-vs-nominal factor of each
/// reference output, from TLV tag `0x12`.
/// This die's ADC12_B calibration, or `None` if the table has no `0x11` entry
/// of the expected size (real silicon always has one; `None` means a blank or
/// corrupted descriptor table).
/// This die's REF_A calibration, or `None` if the table has no `0x12` entry
/// of the expected size.
/// Walk the table for `tag` and return its data address, requiring at least
/// `min_len` bytes so the field reads that follow stay inside the entry.
/// One byte of the descriptor table.
/// One little-endian word, assembled from bytes so an odd `addr` (possible
/// only with a corrupt length chain) cannot fault on alignment.