esp_hal/soc/
efuse_field.rs
1use bytemuck::AnyBitPattern;
2
3use crate::soc::efuse::{Efuse, EfuseBlock};
4
5#[derive(Clone, Copy)]
7pub struct EfuseField {
8 blk: EfuseBlock,
9 bit_off: u16,
10 bit_len: u16,
11}
12
13impl EfuseField {
14 pub(crate) const fn new(blk: EfuseBlock, bit_off: u16, bit_len: u16) -> Self {
15 Self {
16 blk,
17 bit_off,
18 bit_len,
19 }
20 }
21}
22
23impl Efuse {
24 #[inline(always)]
26 pub fn read_field_le<T: AnyBitPattern>(field: EfuseField) -> T {
27 let mut output = core::mem::MaybeUninit::<T>::uninit();
28 let mut bytes = unsafe {
30 core::slice::from_raw_parts_mut(
31 output.as_mut_ptr() as *mut u8,
32 core::mem::size_of::<T>(),
33 )
34 };
35 let block_address = field.blk.address();
37
38 let bit_off = field.bit_off as usize;
39 let bit_end = (field.bit_len as usize).min(bytes.len() * 8) + bit_off;
40
41 let mut last_word_off = bit_off / 32;
42 let mut last_word = unsafe { block_address.add(last_word_off).read_volatile() };
43 let word_bit_off = bit_off % 32;
44 let word_bit_ext = 32 - word_bit_off;
45 let mut word_off = last_word_off;
46
47 for bit_off in (bit_off..bit_end).step_by(32) {
48 let word_bit_len = 32.min(bit_end - bit_off);
49
50 if word_off != last_word_off {
51 last_word_off = word_off;
53 last_word = unsafe { block_address.add(last_word_off).read_volatile() };
54 }
55
56 let mut word = last_word >> word_bit_off;
57
58 word_off += 1;
59
60 if word_bit_len > word_bit_ext {
61 last_word_off = word_off;
63 last_word = unsafe { block_address.add(last_word_off).read_volatile() };
64 word |= last_word.wrapping_shl((32 - word_bit_off) as u32);
66 };
67
68 if word_bit_len < 32 {
69 word &= u32::MAX >> (32 - word_bit_len);
71 }
72
73 let byte_len = word_bit_len.div_ceil(8);
75 let word_bytes =
77 unsafe { core::slice::from_raw_parts(&word as *const u32 as *const u8, byte_len) };
78
79 bytes[..byte_len].copy_from_slice(word_bytes);
81
82 bytes = &mut bytes[byte_len..];
84 }
85
86 bytes.fill(0);
88
89 unsafe { output.assume_init() }
90 }
91
92 #[inline(always)]
94 pub fn read_field_be<T: AnyBitPattern>(field: EfuseField) -> T {
95 let mut output = Self::read_field_le::<T>(field);
97 let bytes = unsafe {
99 core::slice::from_raw_parts_mut(
100 &mut output as *mut T as *mut u8,
101 core::mem::size_of::<T>(),
102 )
103 };
104 bytes.reverse();
106 output
107 }
108
109 #[inline(always)]
113 #[cfg_attr(not(feature = "unstable"), allow(unused))]
114 pub fn read_bit(field: EfuseField) -> bool {
115 assert_eq!(field.bit_len, 1);
116 Self::read_field_le::<u8>(field) != 0
117 }
118}