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}