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()
284 .write(|w| w.eemwe().set_bit().eewe().clear_bit());
285
286 self.eecr().write(|w| w.eewe().set_bit());
287 }
288
289 fn raw_erase_byte(&mut self, address: u16) {
290 self.raw_write_byte(address, 0);
291 }
292 }
293 };
294}
295
296#[macro_export]
297macro_rules! impl_eeprom_atmega {
298 (
299 hal: $HAL:ty,
300 peripheral: $EEPROM:ty,
301 capacity: $capacity:literal,
302 addr_width: $addrwidth:ty,
303 set_address: |$periph_var:ident, $address:ident| $set_address:block,
304 ) => {
305 mod atmega_helper {
306 #[inline]
307 pub unsafe fn wait_read(regs: &$EEPROM) {
308 while regs.eecr().read().eepe().bit_is_set() {}
310 }
311 #[inline]
312 pub unsafe fn set_address(regs: &$EEPROM, address: $addrwidth) {
313 wait_read(regs);
314 let $periph_var = regs;
315 let $address = address;
316 $set_address
317 }
318 #[inline]
319 pub unsafe fn set_erasewrite_mode(regs: &$EEPROM) {
320 regs.eecr().write(|w| {
321 w.eempe().set_bit().eepm().val_0x00()
323 });
324 }
325 #[inline]
326 pub unsafe fn set_erase_mode(regs: &$EEPROM) {
327 regs.eecr().write(|w| {
328 w.eempe().set_bit().eepm().val_0x01()
330 });
331 }
332 #[inline]
333 pub unsafe fn set_write_mode(regs: &$EEPROM) {
334 regs.eecr().write(|w| {
335 w.eempe().set_bit().eepm().val_0x02()
337 });
338 }
339 }
340
341 $crate::impl_eeprom_common! {
342 hal: $HAL,
343 peripheral: $EEPROM,
344 capacity: $capacity,
345 addr_width: $addrwidth,
346 set_address: |peripheral, address| {atmega_helper::set_address(peripheral, address)},
347 set_erasewrite_mode: |peripheral| {atmega_helper::set_erasewrite_mode(peripheral)},
348 set_erase_mode: |peripheral| {atmega_helper::set_erase_mode(peripheral)},
349 set_write_mode: |peripheral| {atmega_helper::set_write_mode(peripheral)},
350 }
351 };
352}
353
354#[macro_export]
355macro_rules! impl_eeprom_attiny {
356 (
357 hal: $HAL:ty,
358 peripheral: $EEPROM:ty,
359 capacity: $capacity:literal,
360 addr_width: $addrwidth:ty,
361 set_address: |$periph_var:ident, $address:ident| $set_address:block,
362 ) => {
363 mod attiny_helper {
364 #[inline]
365 pub unsafe fn wait_read(regs: &$EEPROM) {
366 while regs.eecr().read().eepe().bit_is_set() {}
367 }
368 #[inline]
369 pub unsafe fn set_address(regs: &$EEPROM, address: $addrwidth) {
370 wait_read(regs);
371 let $periph_var = regs;
372 let $address = address;
373 $set_address
374 }
375 #[inline]
376 pub unsafe fn set_erasewrite_mode(regs: &$EEPROM) {
377 regs.eecr().write(|w| {
378 w.eempe().set_bit().eepm().atomic()
380 });
381 }
382 #[inline]
383 pub unsafe fn set_erase_mode(regs: &$EEPROM) {
384 regs.eecr().write(|w| {
385 w.eempe().set_bit().eepm().erase()
387 });
388 }
389 #[inline]
390 pub unsafe fn set_write_mode(regs: &$EEPROM) {
391 regs.eecr().write(|w| {
392 w.eempe().set_bit().eepm().write()
394 });
395 }
396 }
397
398 $crate::impl_eeprom_common! {
399 hal: $HAL,
400 peripheral: $EEPROM,
401 capacity: $capacity,
402 addr_width: $addrwidth,
403 set_address: |peripheral, address| {attiny_helper::set_address(peripheral, address)},
404 set_erasewrite_mode: |peripheral| {attiny_helper::set_erasewrite_mode(peripheral)},
405 set_erase_mode: |peripheral| {attiny_helper::set_erase_mode(peripheral)},
406 set_write_mode: |peripheral| {attiny_helper::set_write_mode(peripheral)},
407 }
408 };
409}