tudelft_quadrupel/
flash.rs

1use crate::mutex::Mutex;
2use crate::once_cell::OnceCell;
3use crate::time::{delay_ms_assembly, delay_us_assembly};
4use nb::block;
5use nrf51_hal::gpio::p0::{P0_00, P0_09, P0_11, P0_13, P0_17, P0_18};
6use nrf51_hal::gpio::Level;
7use nrf51_hal::gpio::{Disconnected, Output, PushPull};
8use nrf51_hal::prelude::OutputPin;
9use nrf51_hal::spi::{Frequency, Pins};
10use nrf51_hal::spi::{FullDuplex, MODE_0};
11use nrf51_hal::Spi;
12use nrf51_pac::SPI1;
13
14const WRSR: u8 = 0x01;
15const BYTEWRITE: u8 = 0x02;
16const BYTEREAD: u8 = 0x03;
17const WRDI: u8 = 0x04;
18// const RDSR: u8 = 0x05;
19const WREN: u8 = 0x06;
20const EWSR: u8 = 0x50;
21const CHIP_ERASE: u8 = 0x60;
22const AAI: u8 = 0xAF;
23
24static FLASH: Mutex<OnceCell<SpiFlash>> = Mutex::new(OnceCell::uninitialized());
25
26/// Errors that may occur while interacting with the flash chip
27#[derive(Debug)]
28pub enum FlashError {
29    /// Writing over spi failed.
30    SpiError(nrf51_hal::spi::Error),
31    /// When a buffer is written at a location too close to the end of flash
32    /// this error is raised
33    OutOfSpace,
34}
35
36impl From<void::Void> for FlashError {
37    fn from(v: void::Void) -> Self {
38        match v {}
39    }
40}
41
42impl From<nrf51_hal::spi::Error> for FlashError {
43    fn from(e: nrf51_hal::spi::Error) -> Self {
44        FlashError::SpiError(e)
45    }
46}
47
48struct SpiFlash {
49    spi: Spi<SPI1>,
50    _pin_wp: P0_00<Output<PushPull>>,
51    _pin_hold: P0_13<Output<PushPull>>,
52    pin_cs: P0_17<Output<PushPull>>,
53}
54
55/// Initialize the flash memory. Should be called only once.
56pub(crate) fn initialize(
57    spi1: SPI1,
58    pin_cs: P0_17<Disconnected>,
59    pin_miso: P0_18<Disconnected>,
60    pin_wp: P0_00<Disconnected>,
61    pin_hold: P0_13<Disconnected>,
62    pin_sck: P0_11<Disconnected>,
63    pin_mosi: P0_09<Disconnected>,
64) -> Result<(), FlashError> {
65    let spi = Spi::new(
66        spi1,
67        Pins {
68            sck: Some(pin_sck.into_push_pull_output(Level::Low).degrade()),
69            mosi: Some(pin_mosi.into_push_pull_output(Level::Low).degrade()),
70            miso: Some(pin_miso.into_floating_input().degrade()),
71        },
72        Frequency::M4,
73        MODE_0,
74    );
75    let pin_wp = pin_wp.into_push_pull_output(Level::High);
76    let pin_hold = pin_hold.into_push_pull_output(Level::High);
77    let pin_cs = pin_cs.into_push_pull_output(Level::High);
78
79    FLASH.modify(|spi_flash| {
80        spi_flash.initialize(SpiFlash {
81            spi,
82            _pin_wp: pin_wp,
83            _pin_hold: pin_hold,
84            pin_cs,
85        });
86    });
87
88    flash_enable_wsr()?;
89    flash_set_wrsr()?;
90    flash_chip_erase()?;
91    flash_write_enable()?;
92    Ok(())
93}
94
95/// Transmit data over SPI. Ignore any received data.
96fn spi_master_tx(tx_data: &[u8]) -> Result<(), FlashError> {
97    assert_ne!(tx_data.len(), 0);
98
99    // Safety: The FLASH mutex is not accessed in an interrupt
100    let guard = unsafe { FLASH.no_critical_section_lock_mut() };
101
102    // Enable slave
103    guard.pin_cs.set_low()?;
104
105    block!(guard.spi.send(tx_data[0]))?;
106    for i in 0..tx_data.len() - 1 {
107        block!(guard.spi.send(tx_data[i + 1]))?;
108        let _ = block!(guard.spi.read())?;
109    }
110    let _ = block!(guard.spi.read())?;
111
112    // Disable slave
113    guard.pin_cs.set_high()?;
114    Ok(())
115}
116
117/// Transmit data over SPI. Optimized to read bytes from the flash memory.
118fn spi_master_tx_rx_fast_read(tx_data: [u8; 4], rx_data: &mut [u8]) -> Result<(), FlashError> {
119    assert_ne!(rx_data.len(), 0);
120
121    // Safety: The FLASH mutex is not accessed in an interrupt
122    let guard = unsafe { FLASH.no_critical_section_lock_mut() };
123
124    // Enable slave
125    guard.pin_cs.set_low()?;
126
127    for byte in tx_data {
128        block!(guard.spi.send(byte))?;
129        let _ = block!(guard.spi.read())?;
130    }
131
132    for byte in rx_data {
133        block!(guard.spi.send(0))?;
134        *byte = block!(guard.spi.read())?;
135    }
136
137    // Disable slave
138    guard.pin_cs.set_high()?;
139
140    Ok(())
141}
142
143/// Transmit data over SPI. Optimized to write bytes to the flash memory.
144fn spi_master_tx_rx_fast_write(tx_data: [u8; 4], bytes: &[u8]) -> Result<(), FlashError> {
145    assert_ne!(bytes.len(), 0);
146
147    let mut bytes_written: u32 = 0;
148    let address: u32 =
149        u32::from(tx_data[3]) + (u32::from(tx_data[2]) << 8) + (u32::from(tx_data[1]) << 16);
150
151    // Safety: The FLASH mutex is not accessed in an interrupt
152    let guard = unsafe { FLASH.no_critical_section_lock_mut() };
153
154    // Enable slave
155    guard.pin_cs.set_low()?;
156
157    for byte in tx_data {
158        block!(guard.spi.send(byte))?;
159        let _ = block!(guard.spi.read())?;
160    }
161
162    // Send first byte
163    block!(guard.spi.send(bytes[0]))?;
164    let _ = block!(guard.spi.read())?;
165
166    // Disable slave
167    guard.pin_cs.set_high()?;
168
169    for i in 1..bytes.len() {
170        delay_us_assembly(15);
171
172        // Enable slave
173        guard.pin_cs.set_low()?;
174        block!(guard.spi.send(AAI))?;
175        let _ = block!(guard.spi.read())?;
176
177        block!(guard.spi.send(bytes[i]))?;
178        let _ = block!(guard.spi.read())?;
179
180        bytes_written += 1;
181
182        // Disable slave
183        guard.pin_cs.set_high()?;
184
185        if address + bytes_written >= 0x1FFFF && i < bytes.len() - 1 {
186            return Err(FlashError::OutOfSpace);
187        }
188    }
189
190    delay_us_assembly(20);
191
192    // Enable slave
193    guard.pin_cs.set_low()?;
194
195    //Send WRDI
196    block!(guard.spi.send(WRDI))?;
197    let _ = block!(guard.spi.read())?;
198
199    // Disable slave
200    guard.pin_cs.set_high()?;
201
202    Ok(())
203}
204
205/// Write-Enable(WREN).
206fn flash_write_enable() -> Result<(), FlashError> {
207    spi_master_tx(&[WREN])
208}
209
210/// This function clears the entire flash memory.
211///
212/// Note: This takes about 100ms to execute, and blocks!
213///
214/// # Errors
215/// When the SPI command fails
216pub fn flash_chip_erase() -> Result<(), FlashError> {
217    flash_write_enable()?;
218    spi_master_tx(&[CHIP_ERASE])?;
219    delay_ms_assembly(100);
220    Ok(())
221}
222
223/// Enable-Write-Status-Register (EWSR). This function must be followed by `flash_enable_WSR`().
224fn flash_enable_wsr() -> Result<(), FlashError> {
225    spi_master_tx(&[EWSR])
226}
227
228/// Sets Write-Status-Register (WRSR) to 0x00 to enable memory write.
229fn flash_set_wrsr() -> Result<(), FlashError> {
230    spi_master_tx(&[WRSR, 0x00])
231}
232
233/// Writes one byte data to specified address.
234///
235/// Note: Make sure that the memory location is cleared before writing data. If data is already present
236/// in the memory location (given address), new data cannot be written to that memory location unless
237/// `flash_chip_erase`() function is called.
238///
239/// address: starting address (between 0x000000 to 0x01FFFF exclusive) from which the data should be stored
240/// byte: one byte data to be stored at the specified address
241///
242/// # Errors
243/// When the SPI command fails
244pub fn flash_write_byte(address: u32, byte: u8) -> Result<(), FlashError> {
245    flash_write_enable()?;
246    spi_master_tx(&[
247        BYTEWRITE,
248        address.to_ne_bytes()[2],
249        address.to_ne_bytes()[1],
250        address.to_ne_bytes()[0],
251        byte,
252        0x00,
253    ])?;
254    delay_us_assembly(20);
255    Ok(())
256}
257
258/// Writes multi-byte data into memory starting from specified address. Each memory location (address)
259/// holds one byte of data.
260///
261/// Note: Make sure that the memory location is cleared before writing data. If data is already present
262/// in the memory location (given address), new data cannot be written to that memory location unless
263/// `flash_chip_erase`() function is called.
264///
265/// address: starting address (between 0x000000 to 0x01FFFF exclusive) from which the data should be stored
266/// bytes: byte slice to write at the specified address
267///
268/// # Errors
269/// When the SPI command fails, or the address is not within the flash address range
270pub fn flash_write_bytes(address: u32, bytes: &[u8]) -> Result<(), FlashError> {
271    flash_write_enable()?;
272    spi_master_tx_rx_fast_write(
273        [
274            AAI,
275            address.to_ne_bytes()[2],
276            address.to_ne_bytes()[1],
277            address.to_ne_bytes()[0],
278        ],
279        bytes,
280    )?;
281    Ok(())
282}
283
284/// Reads one byte data from specified address.
285///
286/// address: any address between 0x000000 to 0x01FFFF from where the data should be read.
287///
288/// # Errors
289/// When the SPI command fails
290pub fn flash_read_byte(address: u32) -> Result<u8, FlashError> {
291    let mut rx_data = [0];
292    spi_master_tx_rx_fast_read(
293        [
294            BYTEREAD,
295            address.to_ne_bytes()[2],
296            address.to_ne_bytes()[1],
297            address.to_ne_bytes()[0],
298        ],
299        &mut rx_data,
300    )?;
301    Ok(rx_data[0])
302}
303
304///Reads multi-byte data starting from specified address.
305///
306/// address: starting address (between 0x000000 to 0x01FFFF exclusive) from which the data should be stored
307/// buffer: a slice to be filled with data read from the specified location
308/// # Errors
309/// When the SPI command fails
310///
311pub fn flash_read_bytes(address: u32, buffer: &mut [u8]) -> Result<(), FlashError> {
312    spi_master_tx_rx_fast_read(
313        [
314            BYTEREAD,
315            address.to_ne_bytes()[2],
316            address.to_ne_bytes()[1],
317            address.to_ne_bytes()[0],
318        ],
319        buffer,
320    )?;
321    Ok(())
322}