1use embedded_hal::spi::MODE_0;
9use vorago_shared_hal::{
10 disable_peripheral_clock, enable_peripheral_clock, reset_peripheral_for_cycles,
11};
12
13use crate::clock::Clocks;
14use crate::pac;
15use crate::spi::{
16 mode_to_cpo_cph_bit, spi_clk_config_from_div, SpiInstance, SpiWord, BMSTART_BMSTOP_MASK,
17};
18
19const NVM_CLOCK_DIV: u16 = 2;
20
21pub const FRAM_WREN: u8 = 0x06;
25pub const FRAM_WRDI: u8 = 0x04;
26pub const FRAM_RDSR: u8 = 0x05;
27pub const FRAM_WRSR: u8 = 0x01;
29pub const FRAM_READ: u8 = 0x03;
30pub const FRAM_WRITE: u8 = 0x02;
31pub const FRAM_RDID: u8 = 0x9F;
32pub const FRAM_SLEEP: u8 = 0xB9;
33
34const ADDR_MSB_MASK: u32 = 0xFF0000;
37const ADDR_MID_MASK: u32 = 0x00FF00;
38const ADDR_LSB_MASK: u32 = 0x0000FF;
39
40#[inline(always)]
41const fn msb_addr_byte(addr: u32) -> u8 {
42 ((addr & ADDR_MSB_MASK) >> 16) as u8
43}
44
45#[inline(always)]
46const fn mid_addr_byte(addr: u32) -> u8 {
47 ((addr & ADDR_MID_MASK) >> 8) as u8
48}
49
50#[inline(always)]
51const fn lsb_addr_byte(addr: u32) -> u8 {
52 (addr & ADDR_LSB_MASK) as u8
53}
54
55pub const WPEN_ENABLE_MASK: u8 = 1 << 7;
56pub const BP_0_ENABLE_MASK: u8 = 1 << 2;
57pub const BP_1_ENABLE_MASK: u8 = 1 << 3;
58
59pub struct Nvm {
60 spi: Option<pac::Spi3>,
61}
62
63#[derive(Debug, PartialEq, Eq)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65pub struct VerifyError {
66 addr: u32,
67 found: u8,
68 expected: u8,
69}
70
71impl Nvm {
72 pub fn new(spi: pac::Spi3, _clocks: &Clocks) -> Self {
73 enable_peripheral_clock(pac::Spi3::PERIPH_SEL);
74 reset_peripheral_for_cycles(pac::Spi3::PERIPH_SEL, 2);
76
77 let spi_clk_cfg = spi_clk_config_from_div(NVM_CLOCK_DIV).unwrap();
78 let (cpo_bit, cph_bit) = mode_to_cpo_cph_bit(MODE_0);
79 spi.ctrl0().write(|w| {
80 unsafe {
81 w.size().bits(u8::word_reg());
82 w.scrdv().bits(spi_clk_cfg.scrdv());
83 w.spo().bit(cpo_bit);
86 w.sph().bit(cph_bit)
87 }
88 });
89 spi.ctrl1().write(|w| {
90 w.blockmode().set_bit();
91 unsafe { w.ss().bits(0) };
92 w.bmstart().set_bit();
93 w.bmstall().set_bit()
94 });
95 spi.clkprescale()
96 .write(|w| unsafe { w.bits(spi_clk_cfg.prescale_val() as u32) });
97
98 spi.fifo_clr().write(|w| {
99 w.rxfifo().set_bit();
100 w.txfifo().set_bit()
101 });
102 spi.ctrl1().modify(|_, w| w.enable().set_bit());
105
106 let mut nvm = Self { spi: Some(spi) };
107 nvm.disable_write_prot();
108 nvm
109 }
110
111 pub fn disable_write_prot(&mut self) {
112 self.wait_for_tx_idle();
113 self.write_with_bmstop(FRAM_WREN);
114 self.wait_for_tx_idle();
115 self.write_single(FRAM_WRSR);
116 self.write_with_bmstop(0x00);
117 self.wait_for_tx_idle();
118 }
119
120 pub fn read_rdsr(&self) -> u8 {
121 self.write_single(FRAM_RDSR);
122 self.write_with_bmstop(0x00);
123 self.wait_for_rx_available();
124 self.read_single_word();
125 self.wait_for_rx_available();
126 (self.read_single_word() & 0xff) as u8
127 }
128
129 pub fn enable_write_prot(&mut self) {
130 self.wait_for_tx_idle();
131 self.write_with_bmstop(FRAM_WREN);
132 self.wait_for_tx_idle();
133 self.write_single(FRAM_WRSR);
134 self.write_with_bmstop(0x00);
135 }
136 #[inline(always)]
137 pub fn spi(&self) -> &pac::Spi3 {
138 self.spi.as_ref().unwrap()
139 }
140
141 #[inline(always)]
142 pub fn write_single(&self, word: u8) {
143 self.spi().data().write(|w| unsafe { w.bits(word as u32) });
144 }
145
146 #[inline(always)]
147 pub fn write_with_bmstop(&self, word: u8) {
148 self.spi()
149 .data()
150 .write(|w| unsafe { w.bits(BMSTART_BMSTOP_MASK | word as u32) });
151 }
152
153 #[inline(always)]
154 pub fn wait_for_tx_idle(&self) {
155 while self.spi().status().read().tfe().bit_is_clear() {
156 cortex_m::asm::nop();
157 }
158 while self.spi().status().read().busy().bit_is_set() {
159 cortex_m::asm::nop();
160 }
161 self.clear_fifos()
162 }
163
164 #[inline(always)]
165 pub fn clear_fifos(&self) {
166 self.spi().fifo_clr().write(|w| {
167 w.rxfifo().set_bit();
168 w.txfifo().set_bit()
169 });
170 }
171
172 #[inline(always)]
173 pub fn wait_for_rx_available(&self) {
174 while !self.spi().status().read().rne().bit_is_set() {
175 cortex_m::asm::nop();
176 }
177 }
178
179 #[inline(always)]
180 pub fn read_single_word(&self) -> u32 {
181 self.spi().data().read().bits()
182 }
183
184 pub fn write_data(&self, addr: u32, data: &[u8]) {
185 self.wait_for_tx_idle();
186 self.write_with_bmstop(FRAM_WREN);
187 self.wait_for_tx_idle();
188 self.write_single(FRAM_WRITE);
189 self.write_single(msb_addr_byte(addr));
190 self.write_single(mid_addr_byte(addr));
191 self.write_single(lsb_addr_byte(addr));
192 for byte in data.iter().take(data.len() - 1) {
193 while self.spi().status().read().tnf().bit_is_clear() {
194 cortex_m::asm::nop();
195 }
196 self.write_single(*byte);
197 self.read_single_word();
198 }
199 while self.spi().status().read().tnf().bit_is_clear() {
200 cortex_m::asm::nop();
201 }
202 self.write_with_bmstop(*data.last().unwrap());
203 self.wait_for_tx_idle();
204 }
205
206 pub fn read_data(&self, addr: u32, buf: &mut [u8]) {
207 self.common_read_start(addr);
208 for byte in buf {
209 self.write_single(0);
211 self.wait_for_rx_available();
212 *byte = self.read_single_word() as u8;
213 }
214 self.write_with_bmstop(0);
215 self.wait_for_tx_idle();
216 }
217
218 pub fn verify_data(&self, addr: u32, comp_buf: &[u8]) -> Result<(), VerifyError> {
219 self.common_read_start(addr);
220 for (idx, byte) in comp_buf.iter().enumerate() {
221 self.write_single(0);
223 self.wait_for_rx_available();
224 let next_word = self.read_single_word() as u8;
225 if next_word != *byte {
226 self.write_with_bmstop(0);
227 self.wait_for_tx_idle();
228 return Err(VerifyError {
229 addr: addr + idx as u32,
230 found: next_word,
231 expected: *byte,
232 });
233 }
234 }
235 self.write_with_bmstop(0);
236 self.wait_for_tx_idle();
237 Ok(())
238 }
239
240 pub fn shutdown(&mut self) {
242 self.wait_for_tx_idle();
243 self.write_with_bmstop(FRAM_WREN);
244 self.wait_for_tx_idle();
245 self.write_single(WPEN_ENABLE_MASK | BP_0_ENABLE_MASK | BP_1_ENABLE_MASK);
246 disable_peripheral_clock(pac::Spi3::PERIPH_SEL);
247 }
248
249 pub fn release(mut self) -> pac::Spi3 {
251 self.shutdown();
252 self.spi.take().unwrap()
253 }
254
255 fn common_read_start(&self, addr: u32) {
256 self.wait_for_tx_idle();
257 self.write_single(FRAM_READ);
258 self.write_single(msb_addr_byte(addr));
259 self.write_single(mid_addr_byte(addr));
260 self.write_single(lsb_addr_byte(addr));
261 for _ in 0..4 {
262 self.write_single(0);
264 self.wait_for_rx_available();
265 self.read_single_word();
267 }
268 }
269}
270
271impl Drop for Nvm {
273 fn drop(&mut self) {
274 if self.spi.is_some() {
275 self.shutdown();
276 }
277 }
278}