esp_hal/soc/
efuse_field.rs1use core::{cmp, mem, slice};
2
3use bytemuck::AnyBitPattern;
4
5use crate::soc::efuse::{Efuse, EfuseBlock};
6
7#[allow(unused)]
9#[derive(Debug, Clone, Copy)]
10pub struct EfuseField {
11 pub(crate) block: EfuseBlock,
13 pub(crate) word: u32,
15 pub(crate) bit_start: u32,
17 pub(crate) bit_count: u32,
19}
20
21impl EfuseField {
22 pub(crate) const fn new(block: u32, word: u32, bit_start: u32, bit_count: u32) -> Self {
23 Self {
24 block: EfuseBlock::from_repr(block).unwrap(),
25 word,
26 bit_start,
27 bit_count,
28 }
29 }
30}
31
32impl Efuse {
33 pub fn read_base_mac_address() -> [u8; 6] {
35 let mut mac_addr = [0u8; 6];
36
37 let mac0 = Self::read_field_le::<[u8; 4]>(crate::soc::efuse::MAC0);
38 let mac1 = Self::read_field_le::<[u8; 2]>(crate::soc::efuse::MAC1);
39
40 mac_addr[0] = mac1[1];
42 mac_addr[1] = mac1[0];
43 mac_addr[2] = mac0[3];
44 mac_addr[3] = mac0[2];
45 mac_addr[4] = mac0[1];
46 mac_addr[5] = mac0[0];
47
48 mac_addr
49 }
50
51 #[inline(always)]
53 pub fn read_field_le<T: AnyBitPattern>(field: EfuseField) -> T {
54 let EfuseField {
55 block,
56 bit_start,
57 bit_count,
58 ..
59 } = field;
60
61 let mut output = mem::MaybeUninit::<T>::uninit();
63 let mut bytes = unsafe {
64 slice::from_raw_parts_mut(output.as_mut_ptr() as *mut u8, mem::size_of::<T>())
65 };
66
67 let bit_off = bit_start as usize;
68 let bit_end = cmp::min(bit_count as usize, bytes.len() * 8) + bit_off;
69
70 let mut last_word_off = bit_off / 32;
71 let mut last_word = unsafe { block.address().add(last_word_off).read_volatile() };
72
73 let word_bit_off = bit_off % 32;
74 let word_bit_ext = 32 - word_bit_off;
75
76 let mut word_off = last_word_off;
77 for bit_off in (bit_off..bit_end).step_by(32) {
78 if word_off != last_word_off {
79 last_word_off = word_off;
81 last_word = unsafe { block.address().add(last_word_off).read_volatile() };
82 }
83
84 let mut word = last_word >> word_bit_off;
85 word_off += 1;
86
87 let word_bit_len = cmp::min(bit_end - bit_off, 32);
88 if word_bit_len > word_bit_ext {
89 last_word_off = word_off;
91 last_word = unsafe { block.address().add(last_word_off).read_volatile() };
92 word |= last_word.wrapping_shl((32 - word_bit_off) as u32);
94 };
95
96 if word_bit_len < 32 {
97 word &= u32::MAX >> (32 - word_bit_len);
99 }
100
101 let byte_len = word_bit_len.div_ceil(8);
103 let word_bytes =
104 unsafe { slice::from_raw_parts(&word as *const u32 as *const u8, byte_len) };
105
106 bytes[..byte_len].copy_from_slice(word_bytes);
108
109 bytes = &mut bytes[byte_len..];
111 }
112
113 bytes.fill(0);
115
116 unsafe { output.assume_init() }
117 }
118
119 #[inline(always)]
123 #[cfg_attr(not(feature = "unstable"), allow(unused))]
124 pub fn read_bit(field: EfuseField) -> bool {
125 assert_eq!(field.bit_count, 1);
126 Self::read_field_le::<u8>(field) != 0
127 }
128}