tm4c_hal/
eeprom.rs

1//! Code for the EEProm module.
2//!
3//! Tested on a TM4C123 Tiva C Series Launchpad
4//!
5//! Note: This code manually increments the EEBLOCK and EEOFFSET registers
6//! after each read and write instead of using the EERDWRINC register. The
7//! debugger was giving inconsistent register results for the EEOFFSET register
8//! after using EERDWRINC. Also, the EERDWRINC does not increment the block in
9//! the case of a wrap of the offset, so it seems less useful for data that
10//! spans blocks.
11//!
12//! This flexibility comes at the cost of efficiency, as the
13//! datasheet calls for at least 4 cycles of delay after setting the EEBLOCK
14//! register.
15
16/// Possible errors for the Flash memory module
17#[derive(Debug, PartialEq)]
18pub enum EepromError {
19    /// Eeprom is not finished
20    Busy,
21    /// Address is out of bounds
22    AddressOutOfBounds,
23    /// Block is out of bounds
24    BlockOutOfBounds,
25    /// Offset is out of bounds
26    OffsetOutOfBounds,
27    /// Indicates that writing data would exceed the EEPROM memory space
28    WriteWouldOverflow,
29    /// Indicates that reading data would exceed the EEPROM memory space
30    ReadWouldOverflow,
31    /// Requesting to read more data than the provided buffer can hold
32    ReadBufferTooSmall,
33}
34
35impl core::fmt::Display for EepromError {
36    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37        match self {
38            EepromError::Busy => write!(f, "Eeprom is busy"),
39            EepromError::AddressOutOfBounds => write!(f, "Address is out of bounds"),
40            EepromError::BlockOutOfBounds => write!(f, "Block is out of bounds"),
41            EepromError::OffsetOutOfBounds => write!(f, "Offset is out of bounds"),
42            EepromError::WriteWouldOverflow => {
43                write!(f, "Writing this data would overflow the EEPROM")
44            }
45            EepromError::ReadWouldOverflow => {
46                write!(f, "Reading this data would overflow the EEPROM")
47            }
48            EepromError::ReadBufferTooSmall => write!(f, "Allocated buffer too small for reading"),
49        }
50    }
51}
52
53/// Struct used to pack the block and offset
54#[derive(Clone, Copy)]
55pub struct EepromAddress {
56    /// Eeprom block
57    block: usize,
58    /// Eeprom offset in a block
59    offset: usize,
60}
61
62impl EepromAddress {
63    /// Creates a new EepromAddres with configured block and offset
64    pub fn new(block: usize, offset: usize) -> Self {
65        EepromAddress { block, offset }
66    }
67
68    /// Returns the block
69    pub fn block(&self) -> usize {
70        self.block
71    }
72
73    /// Returns the offset
74    pub fn offset(&self) -> usize {
75        self.offset
76    }
77
78    /// Increments the offset by one, if that would cause an overflow, increment the block. If
79    /// both the block and offset wrap, the output for the new block and offset
80    /// will both be 0.
81    pub fn increment(&mut self, offset_size: usize, block_size: usize) -> &mut Self {
82        self.offset += 1;
83        if self.offset >= offset_size {
84            self.offset = 0;
85            self.block += 1;
86            if self.block >= block_size {
87                self.block = 0;
88            }
89        }
90
91        self
92    }
93}
94
95/// Series of traits to make access blocks easier
96pub trait Blocks {
97    /// Returns the blocksize for read / write to the flash
98    fn block_size(&self) -> Result<usize, EepromError>;
99
100    /// Returns the EepromAddress for a given index. Valid indexes are 0 to
101    /// EEPROM_END_ADDRESS_WORDS.
102    fn word_index_to_address(&self, index: usize) -> Result<EepromAddress, EepromError>;
103
104    /// Gives the the word index (0 to EEPROM_END_ADDRESS_WORDS) for a
105    /// given EepromAddress
106    fn address_to_word_index(&self, block: &EepromAddress) -> Result<usize, EepromError>;
107}
108
109/// Erase functions of the EEPROM
110pub trait Erase {
111    /// Erase (zero out) data starting at an address spanning a length of bytes (not words!)
112    fn erase(&mut self, address: &EepromAddress, length_bytes: usize) -> Result<(), EepromError>;
113
114    /// Erase (zero out) a block
115    fn erase_block(&mut self, block: usize) -> Result<(), EepromError>;
116}
117
118/// Check if the Eeprom is busy
119pub trait Busy {
120    /// Check the EEDONE register, true if busy
121    fn is_busy(&self) -> bool;
122
123    /// Blocks until the EEPROM is not busy
124    fn wait(&self);
125}
126
127/// Write data to the EEPROM
128pub trait Write {
129    /// Write data to a flash address
130    fn write(&mut self, address: &EepromAddress, data: &[u8]) -> Result<(), EepromError>;
131}
132
133/// Read data from the EEPROM
134pub trait Read {
135    /// Eeprom Address to start reading data from
136    fn read(
137        &mut self,
138        address: &EepromAddress,
139        bytes_to_read: usize,
140        buffer: &mut [u8],
141    ) -> Result<(), EepromError>;
142}