stm32_rust_template/bsp/
at24.rs

1//! Atmel 24 Series EEPROM BSP Driver
2//!
3//! This module provides a Board Support Package (BSP) for Atmel 24 series EEPROM chips
4//! using the generic I2C trait interface.
5//!
6//! Supported EEPROM sizes:
7//! - 24C01, 24C02 (1Kbit, 2Kbit)
8//! - 24C04 (4Kbit)
9//! - 24C08 (8Kbit)
10//! - 24C16 (16Kbit)
11//! - 24C32 and above (32Kbit+)
12
13use crate::driver::i2c::{Event, I2c, Result};
14use core::marker::PhantomData;
15
16/// Default I2C address for 24 series EEPROM (0xA0 >> 1 = 0x50)
17pub const EE24_ADDRESS_DEFAULT: u32 = 0x50;
18
19/// EEPROM size variants
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum EepromSize {
22    /// 1Kbit (128 bytes)
23    Kbit1 = 1,
24    /// 2Kbit (256 bytes)
25    Kbit2 = 2,
26    /// 4Kbit (512 bytes)
27    Kbit4 = 4,
28    /// 8Kbit (1024 bytes)
29    Kbit8 = 8,
30    /// 16Kbit (2048 bytes)
31    Kbit16 = 16,
32    /// 32Kbit (4096 bytes)
33    Kbit32 = 32,
34    /// 64Kbit (8192 bytes)
35    Kbit64 = 64,
36    /// 128Kbit (16384 bytes)
37    Kbit128 = 128,
38    /// 256Kbit (32768 bytes)
39    Kbit256 = 256,
40    /// 512Kbit (65536 bytes)
41    Kbit512 = 512,
42}
43
44impl EepromSize {
45    /// Get the page size for this EEPROM size
46    pub fn page_size(&self) -> usize {
47        match self {
48            EepromSize::Kbit1 | EepromSize::Kbit2 => 8,
49            EepromSize::Kbit4 | EepromSize::Kbit8 | EepromSize::Kbit16 => 16,
50            _ => 32,
51        }
52    }
53
54    /// Get the total capacity in bytes
55    pub fn capacity(&self) -> usize {
56        (*self as usize) * 128 // Convert Kbit to bytes
57    }
58
59    /// Check if this EEPROM uses 8-bit addressing
60    pub fn uses_8bit_addressing(&self) -> bool {
61        match self {
62            EepromSize::Kbit1
63            | EepromSize::Kbit2
64            | EepromSize::Kbit4
65            | EepromSize::Kbit8
66            | EepromSize::Kbit16 => true,
67            _ => false,
68        }
69    }
70}
71
72/// Error types for EEPROM operations
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub enum EepromError {
75    /// I2C communication error
76    I2cError(i32),
77    /// Invalid address
78    InvalidAddress,
79    /// Device not ready
80    DeviceNotReady,
81    /// Write protected
82    WriteProtected,
83    /// Timeout occurred
84    Timeout,
85}
86
87impl From<i32> for EepromError {
88    fn from(err: i32) -> Self {
89        EepromError::I2cError(err)
90    }
91}
92
93pub type EepromResult<T> = core::result::Result<T, EepromError>;
94
95/// Configuration for the EEPROM driver
96pub struct EepromConfig {
97    /// I2C address of the EEPROM
98    pub address: u32,
99    /// Size of the EEPROM
100    pub size: EepromSize,
101    /// Write protect pin configuration (optional)
102    pub wp_pin: Option<fn(bool)>, // Function to control WP pin: true = protected, false = writable
103    /// Default timeout in milliseconds
104    pub timeout_ms: u32,
105}
106
107impl Default for EepromConfig {
108    fn default() -> Self {
109        Self {
110            address: EE24_ADDRESS_DEFAULT,
111            size: EepromSize::Kbit32,
112            wp_pin: None,
113            timeout_ms: 100,
114        }
115    }
116}
117
118/// EEPROM driver handle
119pub struct Eeprom<'a, I2C> {
120    i2c: I2C,
121    config: EepromConfig,
122    busy: bool,
123    _phantom: PhantomData<&'a ()>,
124}
125
126impl<'a, I2C> Eeprom<'a, I2C>
127where
128    I2C: I2c<'a>,
129{
130    /// Create a new EEPROM driver instance
131    pub fn new(mut i2c: I2C, config: EepromConfig) -> EepromResult<Self> {
132        // Initialize I2C with event callback
133        i2c.initialize(|event| {
134            // Handle I2C events if needed
135            if event.contains(Event::BUS_ERROR) {
136                // Handle bus error
137            }
138            if event.contains(Event::TRANSFER_DONE) {
139                // Transfer completed
140            }
141        })
142        .map_err(EepromError::from)?;
143
144        let mut eeprom = Self {
145            i2c,
146            config,
147            busy: false,
148            _phantom: PhantomData,
149        };
150
151        // Test if device is ready
152        eeprom.is_device_ready()?;
153
154        Ok(eeprom)
155    }
156
157    /// Check if the EEPROM device is ready
158    pub fn is_device_ready(&mut self) -> EepromResult<()> {
159        // Simple way to check device readiness - try to read status
160        let status = self.i2c.get_status();
161        if status.bus_error {
162            return Err(EepromError::DeviceNotReady);
163        }
164        Ok(())
165    }
166
167    /// Read data from EEPROM
168    pub fn read(&mut self, address: u32, data: &mut [u8]) -> EepromResult<()> {
169        if self.busy {
170            return Err(EepromError::DeviceNotReady);
171        }
172
173        if address + data.len() as u32 > self.config.size.capacity() as u32 {
174            return Err(EepromError::InvalidAddress);
175        }
176
177        self.busy = true;
178
179        let result = match self.config.size {
180            EepromSize::Kbit1 | EepromSize::Kbit2 => {
181                // 8-bit addressing
182                self.read_with_8bit_address(address, data)
183            }
184            EepromSize::Kbit4 => {
185                // 4Kbit uses device address + 8-bit memory address
186                self.read_4kbit(address, data)
187            }
188            EepromSize::Kbit8 => {
189                // 8Kbit uses device address + 8-bit memory address
190                self.read_8kbit(address, data)
191            }
192            EepromSize::Kbit16 => {
193                // 16Kbit uses device address + 8-bit memory address
194                self.read_16kbit(address, data)
195            }
196            _ => {
197                // 16-bit addressing for larger EEPROMs
198                self.read_with_16bit_address(address, data)
199            }
200        };
201
202        self.busy = false;
203        result
204    }
205
206    /// Write data to EEPROM
207    pub fn write(&mut self, address: u32, data: &[u8]) -> EepromResult<()> {
208        if self.busy {
209            return Err(EepromError::DeviceNotReady);
210        }
211
212        if address + data.len() as u32 > self.config.size.capacity() as u32 {
213            return Err(EepromError::InvalidAddress);
214        }
215
216        self.busy = true;
217
218        // Disable write protection if configured
219        if let Some(wp_control) = self.config.wp_pin {
220            wp_control(false);
221        }
222
223        let result = self.write_pages(address, data);
224
225        // Re-enable write protection if configured
226        if let Some(wp_control) = self.config.wp_pin {
227            wp_control(true);
228        }
229
230        self.busy = false;
231        result
232    }
233
234    /// Write data with page boundary handling
235    fn write_pages(&mut self, mut address: u32, mut data: &[u8]) -> EepromResult<()> {
236        let page_size = self.config.size.page_size();
237
238        while !data.is_empty() {
239            // Calculate how many bytes we can write in this page
240            let bytes_to_page_end = page_size - (address as usize % page_size);
241            let write_size = core::cmp::min(data.len(), bytes_to_page_end);
242
243            // Write this chunk
244            self.write_chunk(address, &data[..write_size])?;
245
246            // Wait for write cycle to complete (typically 5-10ms)
247            self.delay_ms(10);
248
249            // Update for next iteration
250            address += write_size as u32;
251            data = &data[write_size..];
252        }
253
254        Ok(())
255    }
256
257    /// Write a single chunk (within page boundary)
258    fn write_chunk(&mut self, address: u32, data: &[u8]) -> EepromResult<()> {
259        match self.config.size {
260            EepromSize::Kbit1 | EepromSize::Kbit2 => self.write_with_8bit_address(address, data),
261            EepromSize::Kbit4 => self.write_4kbit(address, data),
262            EepromSize::Kbit8 => self.write_8kbit(address, data),
263            EepromSize::Kbit16 => self.write_16kbit(address, data),
264            _ => self.write_with_16bit_address(address, data),
265        }
266    }
267
268    /// Read with 8-bit addressing
269    fn read_with_8bit_address(&mut self, address: u32, data: &mut [u8]) -> EepromResult<()> {
270        // For 8-bit addressing, send address as first byte, then read
271        let addr_bytes = [address as u8];
272
273        // Send address
274        self.i2c
275            .master_transmit(self.config.address, &addr_bytes, true)
276            .map_err(EepromError::from)?;
277
278        // Read data
279        self.i2c
280            .master_receive(self.config.address, data, false)
281            .map_err(EepromError::from)?;
282
283        Ok(())
284    }
285
286    /// Read with 16-bit addressing
287    fn read_with_16bit_address(&mut self, address: u32, data: &mut [u8]) -> EepromResult<()> {
288        // For 16-bit addressing, send address as two bytes, then read
289        let addr_bytes = [(address >> 8) as u8, address as u8];
290
291        // Send address
292        self.i2c
293            .master_transmit(self.config.address, &addr_bytes, true)
294            .map_err(EepromError::from)?;
295
296        // Read data
297        self.i2c
298            .master_receive(self.config.address, data, false)
299            .map_err(EepromError::from)?;
300
301        Ok(())
302    }
303
304    /// Read from 4Kbit EEPROM (uses device address bits)
305    fn read_4kbit(&mut self, address: u32, data: &mut [u8]) -> EepromResult<()> {
306        let device_addr = self.config.address | ((address & 0x0100) >> 7);
307        let mem_addr = [address as u8];
308
309        self.i2c
310            .master_transmit(device_addr, &mem_addr, true)
311            .map_err(EepromError::from)?;
312
313        self.i2c
314            .master_receive(device_addr, data, false)
315            .map_err(EepromError::from)?;
316
317        Ok(())
318    }
319
320    /// Read from 8Kbit EEPROM (uses device address bits)
321    fn read_8kbit(&mut self, address: u32, data: &mut [u8]) -> EepromResult<()> {
322        let device_addr = self.config.address | ((address & 0x0300) >> 7);
323        let mem_addr = [address as u8];
324
325        self.i2c
326            .master_transmit(device_addr, &mem_addr, true)
327            .map_err(EepromError::from)?;
328
329        self.i2c
330            .master_receive(device_addr, data, false)
331            .map_err(EepromError::from)?;
332
333        Ok(())
334    }
335
336    /// Read from 16Kbit EEPROM (uses device address bits)
337    fn read_16kbit(&mut self, address: u32, data: &mut [u8]) -> EepromResult<()> {
338        let device_addr = self.config.address | ((address & 0x0700) >> 7);
339        let mem_addr = [address as u8];
340
341        self.i2c
342            .master_transmit(device_addr, &mem_addr, true)
343            .map_err(EepromError::from)?;
344
345        self.i2c
346            .master_receive(device_addr, data, false)
347            .map_err(EepromError::from)?;
348
349        Ok(())
350    }
351
352    /// Write with 8-bit addressing
353    fn write_with_8bit_address(&mut self, address: u32, data: &[u8]) -> EepromResult<()> {
354        let mut buffer = [0u8; 256]; // Max page size + address
355        buffer[0] = address as u8;
356        buffer[1..=data.len()].copy_from_slice(data);
357
358        self.i2c
359            .master_transmit(self.config.address, &buffer[..=data.len()], false)
360            .map_err(EepromError::from)?;
361
362        Ok(())
363    }
364
365    /// Write with 16-bit addressing
366    fn write_with_16bit_address(&mut self, address: u32, data: &[u8]) -> EepromResult<()> {
367        let mut buffer = [0u8; 256]; // Max page size + address
368        buffer[0] = (address >> 8) as u8;
369        buffer[1] = address as u8;
370        buffer[2..2 + data.len()].copy_from_slice(data);
371
372        self.i2c
373            .master_transmit(self.config.address, &buffer[..2 + data.len()], false)
374            .map_err(EepromError::from)?;
375
376        Ok(())
377    }
378
379    /// Write to 4Kbit EEPROM
380    fn write_4kbit(&mut self, address: u32, data: &[u8]) -> EepromResult<()> {
381        let device_addr = self.config.address | ((address & 0x0100) >> 7);
382        let mut buffer = [0u8; 256];
383        buffer[0] = address as u8;
384        buffer[1..=data.len()].copy_from_slice(data);
385
386        self.i2c
387            .master_transmit(device_addr, &buffer[..=data.len()], false)
388            .map_err(EepromError::from)?;
389
390        Ok(())
391    }
392
393    /// Write to 8Kbit EEPROM
394    fn write_8kbit(&mut self, address: u32, data: &[u8]) -> EepromResult<()> {
395        let device_addr = self.config.address | ((address & 0x0300) >> 7);
396        let mut buffer = [0u8; 256];
397        buffer[0] = address as u8;
398        buffer[1..=data.len()].copy_from_slice(data);
399
400        self.i2c
401            .master_transmit(device_addr, &buffer[..=data.len()], false)
402            .map_err(EepromError::from)?;
403
404        Ok(())
405    }
406
407    /// Write to 16Kbit EEPROM
408    fn write_16kbit(&mut self, address: u32, data: &[u8]) -> EepromResult<()> {
409        let device_addr = self.config.address | ((address & 0x0700) >> 7);
410        let mut buffer = [0u8; 256];
411        buffer[0] = address as u8;
412        buffer[1..=data.len()].copy_from_slice(data);
413
414        self.i2c
415            .master_transmit(device_addr, &buffer[..=data.len()], false)
416            .map_err(EepromError::from)?;
417
418        Ok(())
419    }
420
421    /// Simple delay function - in real implementation, this would use the system timer
422    fn delay_ms(&self, _ms: u32) {
423        // TODO: Implement proper delay using system timer
424        // For now, this is a placeholder
425        for _ in 0..1000 {
426            // Simple busy wait - replace with proper delay
427        }
428    }
429
430    /// Get the EEPROM configuration
431    pub fn config(&self) -> &EepromConfig {
432        &self.config
433    }
434
435    /// Check if the driver is busy
436    pub fn is_busy(&self) -> bool {
437        self.busy
438    }
439}
440
441/// Convenience functions for common operations
442impl<'a, I2C> Eeprom<'a, I2C>
443where
444    I2C: I2c<'a>,
445{
446    /// Read a single byte
447    pub fn read_byte(&mut self, address: u32) -> EepromResult<u8> {
448        let mut data = [0u8; 1];
449        self.read(address, &mut data)?;
450        Ok(data[0])
451    }
452
453    /// Write a single byte
454    pub fn write_byte(&mut self, address: u32, data: u8) -> EepromResult<()> {
455        self.write(address, &[data])
456    }
457
458    /// Read a u16 value (big-endian)
459    pub fn read_u16(&mut self, address: u32) -> EepromResult<u16> {
460        let mut data = [0u8; 2];
461        self.read(address, &mut data)?;
462        Ok(u16::from_be_bytes(data))
463    }
464
465    /// Write a u16 value (big-endian)
466    pub fn write_u16(&mut self, address: u32, data: u16) -> EepromResult<()> {
467        self.write(address, &data.to_be_bytes())
468    }
469
470    /// Read a u32 value (big-endian)
471    pub fn read_u32(&mut self, address: u32) -> EepromResult<u32> {
472        let mut data = [0u8; 4];
473        self.read(address, &mut data)?;
474        Ok(u32::from_be_bytes(data))
475    }
476
477    /// Write a u32 value (big-endian)
478    pub fn write_u32(&mut self, address: u32, data: u32) -> EepromResult<()> {
479        self.write(address, &data.to_be_bytes())
480    }
481
482    /// Clear (fill with 0xFF) a range of EEPROM
483    pub fn clear_range(&mut self, start_address: u32, length: u32) -> EepromResult<()> {
484        let page_size = self.config.size.page_size() as u32;
485        let mut address = start_address;
486        let mut remaining = length;
487
488        while remaining > 0 {
489            let write_size = core::cmp::min(remaining, page_size);
490            let fill_data = [0xFF; 32]; // Max page size
491
492            self.write(address, &fill_data[..write_size as usize])?;
493
494            address += write_size;
495            remaining -= write_size;
496        }
497
498        Ok(())
499    }
500}