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
//! CRC16 hardware module (CRC-CCITT, polynomial 0x1021).
//!
//! The MSP430FR5969 carries a 16-bit CRC accelerator: a hardware LFSR for the
//! CRC-CCITT polynomial x^16 + x^12 + x^5 + 1 (0x1021). Feeding it costs one
//! register write per byte (or word) with **no cycles spent on the bit math**
//! — the LFSR settles combinationally before the next write can retire, so
//! there is no busy flag and nothing to poll. That makes it worthwhile even
//! for short frames, and it is the natural integrity check for the FRAM
//! persistence this project already does (e.g. guarding an Info-FRAM config
//! block against a torn update).
//!
//! # One polynomial, two bit orders, four registers
//!
//! The module computes only the 0x1021 polynomial, but exposes **both bit
//! conventions** in which that polynomial is used in the wild (SLAU367P ch.
//! 16). The four data/result registers pair up:
//!
//! - [`write_msb_first`](Crc::write_msb_first) (`CRCDIRB`) +
//! [`result`](Crc::result) (`CRCINIRES`) — the *non-reflected* ("MSB-first")
//! family: CRC-16/CCITT-FALSE, CRC-16/XMODEM.
//! - [`write_lsb_first`](Crc::write_lsb_first) (`CRCDI`) +
//! [`result_bit_reversed`](Crc::result_bit_reversed) (`CRCRESR`) — the
//! *reflected* ("LSB-first") family: CRC-16/KERMIT, CRC-16/X-25.
//!
//! The hardware holds a single shift register; `CRCDIRB` bit-reverses data on
//! the way in and `CRCRESR` bit-reverses the register on the way out, which
//! is exactly the textbook relationship between the two conventions. The four
//! catalog variants ship as one-shot convenience methods
//! ([`ccitt_false`](Crc::ccitt_false), [`xmodem`](Crc::xmodem),
//! [`kermit`](Crc::kermit), [`x25`](Crc::x25)); their published check values
//! over `"123456789"` (0x29B1 / 0x31C3 / 0x2189 / 0x906E) are pinned by the
//! host unit tests against the software model in `crc_soft.rs` and by the
//! `accel_test_runner` fixture against the silicon.
//!
//! # Byte writes through raw pointers
//!
//! Byte-granular input requires **byte-wide** stores to the data registers'
//! low byte (`CRCDI_L`/`CRCDIRB_L`): an 8-bit store clocks 8 bits into the
//! LFSR, a 16-bit store clocks 16. The PAC's register API only emits 16-bit
//! accesses, so [`write_msb_first`]/[`write_lsb_first`] go through raw
//! volatile byte pointers derived from the owned peripheral's base address —
//! same approach as the MSP430X byte primitives in [`fram`](crate::fram).
//! Word-at-a-time input is available too ([`write_words_msb_first`]): within
//! a 16-bit write to `CRCDIRB` the hardware processes the **lower byte
//! first** (HW-verified 2026-07-05), so the word path equals the byte path
//! over the words' little-endian serialization — i.e. checksumming a
//! `&[u16]` gives the same result as checksumming the same bytes in memory
//! order on this little-endian CPU.
//!
//! [`write_msb_first`]: Crc::write_msb_first
//! [`write_lsb_first`]: Crc::write_lsb_first
//! [`write_words_msb_first`]: Crc::write_words_msb_first
//!
//! # Example: guard a config block
//!
//! ```ignore
//! let mut crc = hal::crc::Crc::new(p.crc16);
//! let stored = crc.ccitt_false(&config_bytes);
//! // ... persist config_bytes + stored in Info FRAM; on boot, recompute and compare.
//! ```
pub use crate;
/// Byte offsets of the CRC16 registers from the module base (0x0150).
const CRCDI_OFFSET: usize = 0; // CRC data in
const CRCDIRB_OFFSET: usize = 2; // CRC data in, bit order reversed
/// Owned driver for the CRC16 module.
///
/// Owning the PAC peripheral makes concurrent feeders a compile error — the
/// module is a single shared LFSR, so an interleaved writer would silently
/// corrupt both checksums.
use cratepac;
/// Byte-wide pointer to the low byte of a CRC data register.
///
/// Borrowing `&pac::Crc16` (rather than using `Crc16::ptr()` freestanding)
/// ties the raw access to the owned peripheral for the reader, even though
/// the address is the same either way.