1use core::marker;
4
5#[derive(ufmt::derive::uDebug, Debug)]
6pub struct OutOfBoundsError;
7
8pub trait EepromOps<H> {
12 const CAPACITY: u16;
13
14 fn raw_read_byte(&self, address: u16) -> u8;
18 fn raw_write_byte(&mut self, address: u16, data: u8);
22 fn raw_erase_byte(&mut self, address: u16);
26}
27
28pub struct Eeprom<H, EEPROM> {
29 p: EEPROM,
30 _h: marker::PhantomData<H>,
31}
32
33impl<H, EEPROM> Eeprom<H, EEPROM>
34where
35 EEPROM: EepromOps<H>,
36{
37 pub const CAPACITY: u16 = EEPROM::CAPACITY;
38
39 #[inline]
40 pub fn new(p: EEPROM) -> Self {
41 Self {
42 p,
43 _h: marker::PhantomData,
44 }
45 }
46 #[inline]
47 pub fn capacity(&self) -> u16 {
48 Self::CAPACITY
49 }
50
51 #[inline]
52 pub fn read_byte(&self, offset: u16) -> u8 {
53 assert!(offset < Self::CAPACITY);
54 self.p.raw_read_byte(offset)
55 }
56
57 #[inline]
58 pub fn write_byte(&mut self, offset: u16, data: u8) {
59 assert!(offset < Self::CAPACITY);
60 self.p.raw_write_byte(offset, data)
61 }
62
63 #[inline]
64 pub fn erase_byte(&mut self, offset: u16) {
65 assert!(offset < Self::CAPACITY);
66 self.p.raw_erase_byte(offset)
67 }
68
69 pub fn read(&self, offset: u16, buf: &mut [u8]) -> Result<(), OutOfBoundsError> {
70 if buf.len() as u16 + offset > Self::CAPACITY {
71 return Err(OutOfBoundsError);
72 }
73 for (i, byte) in buf.iter_mut().enumerate() {
74 *byte = self.p.raw_read_byte(offset + i as u16);
75 }
76 Ok(())
77 }
78
79 pub fn write(&mut self, offset: u16, buf: &[u8]) -> Result<(), OutOfBoundsError> {
80 if buf.len() as u16 + offset > Self::CAPACITY {
81 return Err(OutOfBoundsError);
82 }
83
84 for (i, byte) in buf.iter().enumerate() {
85 self.p.raw_write_byte(offset + i as u16, *byte)
86 }
87 Ok(())
88 }
89
90 pub fn erase(&mut self, from: u16, to: u16) -> Result<(), OutOfBoundsError> {
91 if to > Self::CAPACITY || from > to {
92 return Err(OutOfBoundsError);
93 }
94
95 for i in from..to {
96 self.p.raw_erase_byte(i)
97 }
98
99 Ok(())
100 }
101}
102
103impl<H, EEPROM> embedded_storage::nor_flash::ReadNorFlash for Eeprom<H, EEPROM>
104where
105 EEPROM: EepromOps<H>,
106{
107 type Error = OutOfBoundsError;
108 const READ_SIZE: usize = 1;
109
110 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
111 Eeprom::<H, EEPROM>::read(self, offset as u16, bytes)
112 }
113
114 fn capacity(&self) -> usize {
115 Eeprom::<H, EEPROM>::capacity(self) as usize
116 }
117}
118
119impl<H, EEPROM> embedded_storage::nor_flash::NorFlash for Eeprom<H, EEPROM>
120where
121 EEPROM: EepromOps<H>,
122{
123 const WRITE_SIZE: usize = 1;
124 const ERASE_SIZE: usize = 1;
125 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
126 Eeprom::<H, EEPROM>::erase(self, from as u16, to as u16)
127 }
128
129 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
130 Eeprom::<H, EEPROM>::write(self, offset as u16, bytes)
131 }
132}
133impl<H, EEPROM> embedded_storage::nor_flash::MultiwriteNorFlash for Eeprom<H, EEPROM> where
135 EEPROM: EepromOps<H>
136{
137}
138
139#[macro_export]
140macro_rules! impl_eeprom_common {
141 (
142 hal: $HAL:ty,
143 peripheral: $EEPROM:ty,
144 capacity: $capacity:literal,
145 addr_width: $addrwidth:ty,
146 set_address: |$periph_var:ident, $address:ident| $set_address:block,
147 set_erasewrite_mode: |$periph_ewmode_var:ident| $set_erasewrite_mode:block,
148 set_erase_mode: |$periph_emode_var:ident| $set_erase_mode:block,
149 set_write_mode: |$periph_wmode_var:ident| $set_write_mode:block,
150 ) => {
151 impl $crate::eeprom::EepromOps<$HAL> for $EEPROM {
152 const CAPACITY: u16 = $capacity;
153
154 fn raw_read_byte(&self, address: u16) -> u8 {
155 unsafe {
156 {
157 let $periph_var = &self;
158 let $address = address as $addrwidth;
159 $set_address
160 }
161
162 self.eecr.write(|w| w.eere().set_bit());
163 self.eedr.read().bits()
164 }
165 }
166
167 fn raw_write_byte(&mut self, address: u16, data: u8) {
168 unsafe {
169 {
170 let $periph_var = &self;
171 let $address = address as $addrwidth;
172 $set_address
173 }
174
175 self.eecr.write(|w| w.eere().set_bit());
177 let old_value = self.eedr.read().bits();
178 let diff_mask = old_value ^ data;
179
180 if (diff_mask & data) != 0 {
182 if data != 0xff {
186 self.eedr.write(|w| w.bits(data)); {
190 let $periph_ewmode_var = &self;
191 $set_erasewrite_mode
192 }
193 self.eecr.modify(|_, w| w.eepe().set_bit()); } else {
195 {
197 let $periph_emode_var = &self;
198 $set_erase_mode
199 }
200 self.eecr.modify(|_, w| w.eepe().set_bit()); }
202 }
203 else {
205 if diff_mask != 0 {
207 self.eedr.write(|w| w.bits(data)); {
210 let $periph_wmode_var = &self;
211 $set_write_mode
212 }
213 self.eecr.modify(|_, w| w.eepe().set_bit()); }
215 }
216 }
217 }
218
219 fn raw_erase_byte(&mut self, address: u16) {
220 unsafe {
221 {
222 let $periph_var = &self;
223 let $address = address as $addrwidth;
224 $set_address
225 }
226 {
228 let $periph_emode_var = &self;
229 $set_erase_mode
230 }
231 self.eecr.modify(|_, w| w.eepe().set_bit());
233 }
234 }
235 }
236 };
237}
238
239#[macro_export]
240macro_rules! impl_eeprom_atmega_old {
241 (
242 hal: $HAL:ty,
243 peripheral: $EEPROM:ty,
244 capacity: $capacity:literal,
245 addr_width: $addrwidth:ty,
246 set_address: |$periph_var:ident, $address:ident| $set_address:block,
247 ) => {
248 mod atmega_helper {
249 #[inline]
250 pub unsafe fn wait_read(regs: &$EEPROM) {
251 while regs.eecr.read().eewe().bit_is_set() {}
253 }
254
255 #[inline]
256 pub unsafe fn set_address(regs: &$EEPROM, address: u16) {
257 wait_read(regs);
258 let $periph_var = regs;
259 let $address = address;
260 $set_address
261 }
262 }
263
264 impl $crate::eeprom::EepromOps<$HAL> for $EEPROM {
265 const CAPACITY: u16 = $capacity;
266
267 fn raw_read_byte(&self, address: u16) -> u8 {
268 unsafe {
269 atmega_helper::set_address(&self, address);
270 }
271 self.eecr.write(|w| w.eere().set_bit());
272 self.eedr.read().bits()
273 }
274
275 fn raw_write_byte(&mut self, address: u16, data: u8) {
276 unsafe {
277 atmega_helper::set_address(&self, address);
278 }
279
280 self.eedr.write(|w| unsafe { w.bits(data) });
282
283 self.eecr.write(|w| w.eemwe().set_bit().eewe().clear_bit());
284
285 self.eecr.write(|w| w.eewe().set_bit());
286 }
287
288 fn raw_erase_byte(&mut self, address: u16) {
289 self.raw_write_byte(address, 0);
290 }
291 }
292 };
293}
294
295#[macro_export]
296macro_rules! impl_eeprom_atmega {
297 (
298 hal: $HAL:ty,
299 peripheral: $EEPROM:ty,
300 capacity: $capacity:literal,
301 addr_width: $addrwidth:ty,
302 set_address: |$periph_var:ident, $address:ident| $set_address:block,
303 ) => {
304 mod atmega_helper {
305 #[inline]
306 pub unsafe fn wait_read(regs: &$EEPROM) {
307 while regs.eecr.read().eepe().bit_is_set() {}
309 }
310 #[inline]
311 pub unsafe fn set_address(regs: &$EEPROM, address: $addrwidth) {
312 wait_read(regs);
313 let $periph_var = regs;
314 let $address = address;
315 $set_address
316 }
317 #[inline]
318 pub unsafe fn set_erasewrite_mode(regs: &$EEPROM) {
319 regs.eecr.write(|w| {
320 w.eempe().set_bit().eepm().val_0x00()
322 })
323 }
324 #[inline]
325 pub unsafe fn set_erase_mode(regs: &$EEPROM) {
326 regs.eecr.write(|w| {
327 w.eempe().set_bit().eepm().val_0x01()
329 });
330 }
331 #[inline]
332 pub unsafe fn set_write_mode(regs: &$EEPROM) {
333 regs.eecr.write(|w| {
334 w.eempe().set_bit().eepm().val_0x02()
336 });
337 }
338 }
339
340 $crate::impl_eeprom_common! {
341 hal: $HAL,
342 peripheral: $EEPROM,
343 capacity: $capacity,
344 addr_width: $addrwidth,
345 set_address: |peripheral, address| {atmega_helper::set_address(peripheral, address)},
346 set_erasewrite_mode: |peripheral| {atmega_helper::set_erasewrite_mode(peripheral)},
347 set_erase_mode: |peripheral| {atmega_helper::set_erase_mode(peripheral)},
348 set_write_mode: |peripheral| {atmega_helper::set_write_mode(peripheral)},
349 }
350 };
351}
352
353#[macro_export]
354macro_rules! impl_eeprom_attiny {
355 (
356 hal: $HAL:ty,
357 peripheral: $EEPROM:ty,
358 capacity: $capacity:literal,
359 addr_width: $addrwidth:ty,
360 set_address: |$periph_var:ident, $address:ident| $set_address:block,
361 ) => {
362 mod attiny_helper {
363 #[inline]
364 pub unsafe fn wait_read(regs: &$EEPROM) {
365 while regs.eecr.read().eepe().bit_is_set() {}
366 }
367 #[inline]
368 pub unsafe fn set_address(regs: &$EEPROM, address: $addrwidth) {
369 wait_read(regs);
370 let $periph_var = regs;
371 let $address = address;
372 $set_address
373 }
374 #[inline]
375 pub unsafe fn set_erasewrite_mode(regs: &$EEPROM) {
376 regs.eecr.write(|w| {
377 w.eempe().set_bit().eepm().atomic()
379 });
380 }
381 #[inline]
382 pub unsafe fn set_erase_mode(regs: &$EEPROM) {
383 regs.eecr.write(|w| {
384 w.eempe().set_bit().eepm().erase()
386 });
387 }
388 #[inline]
389 pub unsafe fn set_write_mode(regs: &$EEPROM) {
390 regs.eecr.write(|w| {
391 w.eempe().set_bit().eepm().write()
393 });
394 }
395 }
396
397 $crate::impl_eeprom_common! {
398 hal: $HAL,
399 peripheral: $EEPROM,
400 capacity: $capacity,
401 addr_width: $addrwidth,
402 set_address: |peripheral, address| {attiny_helper::set_address(peripheral, address)},
403 set_erasewrite_mode: |peripheral| {attiny_helper::set_erasewrite_mode(peripheral)},
404 set_erase_mode: |peripheral| {attiny_helper::set_erase_mode(peripheral)},
405 set_write_mode: |peripheral| {attiny_helper::set_write_mode(peripheral)},
406 }
407 };
408}