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
//! Read fuse values.
//!
//! This example uses `defmt` to convey the fuse value over RTT.
//! Although the example may build on your board, it may not work
//! properly.
//!
//! If you set `FUSE_VALUE_CAUTION_PERMANENT` to a non-zero value,
//! that value will be written to the given `FUSE_ADDRESS`. This
//! is permament, so be careful where you're writing!
#![no_main]
#![no_std]
use hal::ocotp::FuseAddress;
use imxrt_hal as hal;
const FUSE_ADDRESS: FuseAddress = FuseAddress::new(0x1300).unwrap();
/// If set to a non-zero value, the example attempts to write this
/// value to the fuse address above!
///
/// (It's possible to write zero to a ECC-redundant fuse and lock it.
/// We assume you don't want to do that!)
const FUSE_VALUE_CAUTION_PERMANENT: u32 = 0;
const DELAY_MS: u32 = board::PIT_FREQUENCY / 1_000 * 250;
#[imxrt_rt::entry]
fn main() -> ! {
let (
board::Common {
mut pit, mut ocotp, ..
},
board::Specifics { led, .. },
) = board::new();
pit.0.set_load_timer_value(DELAY_MS);
pit.0.enable();
let mut write_delays = 50;
let mut fuse_written = false;
loop {
while !pit.0.is_elapsed() {}
pit.0.clear_elapsed();
led.toggle();
defmt::println!("Reading fuse...");
match ocotp.blocking_fuse_read(FUSE_ADDRESS) {
Ok(fuse_value) => {
defmt::println!("Fuse value: {=u32:#010X}", fuse_value);
}
Err(_) => {
defmt::error!("Failed to read fuse!");
}
}
if FUSE_VALUE_CAUTION_PERMANENT != 0 && !fuse_written {
if write_delays == 0 {
defmt::println!("=== WRITING FUSE ===");
fuse_written = true;
match ocotp.blocking_fuse_write(FUSE_ADDRESS, FUSE_VALUE_CAUTION_PERMANENT) {
Ok(()) => {
defmt::println!("Fuse write finished!");
}
Err(_) => {
defmt::error!("Failed to write fuse!");
}
}
} else {
defmt::println!("!! Writing fuse when {=u32} reaches zero", write_delays);
write_delays -= 1;
}
}
}
}