1use as_slice::AsSlice;
4use core::convert::TryInto;
5use core::marker::PhantomData;
6use core::ops::Deref;
7use core::pin::Pin;
8
9use crate::dma;
10use crate::pac::{QUADSPI, RCC};
11use crate::rcc::Enable;
12use crate::state;
13
14pub struct Qspi {
16 qspi: QUADSPI,
18 adsize: u8,
20}
21
22#[derive(Clone)]
25pub struct QspiTransaction {
26 pub iwidth: u8,
27 pub awidth: u8,
28 pub dwidth: u8,
29 pub instruction: u8,
30 pub address: Option<u32>,
31 pub dummy: u8,
32 pub data_len: Option<usize>,
33}
34
35#[derive(Debug)]
37pub enum Error {
38 BadParam,
40}
41
42pub struct QspiWidth;
45
46#[allow(dead_code)]
47impl QspiWidth {
48 pub const NONE: u8 = 0b00;
49 pub const SING: u8 = 0b01;
50 pub const DUAL: u8 = 0b10;
51 pub const QUAD: u8 = 0b11;
52}
53
54struct QspiMode;
57
58#[allow(dead_code)]
59impl QspiMode {
60 pub const INDIRECT_WRITE: u8 = 0b00;
61 pub const INDIRECT_READ: u8 = 0b01;
62 pub const AUTO_POLLING: u8 = 0b10;
63 pub const MEMORY_MAPPED: u8 = 0b11;
64}
65
66impl Qspi {
67 pub fn new(_rcc: &mut RCC, qspi: QUADSPI, size: u8, mut adsize: u8) -> Self {
71 assert!((1..=4).contains(&adsize));
72 adsize -= 1;
73
74 unsafe { QUADSPI::enable_unchecked() };
76
77 unsafe {
79 qspi.cr
82 .write_with_zero(|w| w.prescaler().bits(1).fthres().bits(3).en().set_bit());
83
84 qspi.dcr.write_with_zero(|w| w.fsize().bits(size - 1));
86 }
87
88 Qspi { qspi, adsize }
89 }
90
91 pub fn read_all<B>(
95 &mut self,
96 data: Pin<B>,
97 transaction: QspiTransaction,
98 dma: &dma::Handle<<RxTx<QUADSPI> as dma::Target>::Instance, state::Enabled>,
99 stream: <RxTx<QUADSPI> as dma::Target>::Stream,
100 ) -> Result<dma::Transfer<RxTx<QUADSPI>, B, dma::Started>, Error>
101 where
102 B: Deref + 'static,
103 B::Target: AsSlice<Element = u8>,
104 {
105 match transaction.data_len {
107 Some(data_len) => {
108 assert!(
109 (data_len as u32) % 4 == 0,
110 "DMA transfer must be word aligned."
111 );
112
113 self.setup_transaction(QspiMode::INDIRECT_READ, &transaction);
115
116 let rx_token = RxTx(PhantomData);
118 let rx_transfer = unsafe {
119 dma::Transfer::new(
120 dma,
121 stream,
122 data,
123 rx_token,
124 self.dr_address(),
125 dma::Direction::PeripheralToMemory,
126 )
127 };
128
129 let rx_transfer = rx_transfer.start(dma);
130
131 self.qspi.cr.modify(|_, w| w.dmaen().set_bit());
133
134 Ok(rx_transfer)
135 }
136 None => Err(Error::BadParam),
137 }
138 }
139
140 pub fn write_all<B>(
144 &mut self,
145 data: Pin<B>,
146 transaction: QspiTransaction,
147 dma: &dma::Handle<<RxTx<QUADSPI> as dma::Target>::Instance, state::Enabled>,
148 stream: <RxTx<QUADSPI> as dma::Target>::Stream,
149 ) -> Result<dma::Transfer<RxTx<QUADSPI>, B, dma::Started>, Error>
150 where
151 B: Deref + 'static,
152 B::Target: AsSlice<Element = u8>,
153 {
154 match transaction.data_len {
156 Some(data_len) => {
157 assert!(
158 (data_len as u32) % 4 == 0,
159 "DMA transfer must be word aligned."
160 );
161
162 self.setup_transaction(QspiMode::INDIRECT_WRITE, &transaction);
164
165 let tx_token = RxTx(PhantomData);
167 let tx_transfer = unsafe {
168 dma::Transfer::new(
169 dma,
170 stream,
171 data,
172 tx_token,
173 self.dr_address(),
174 dma::Direction::MemoryToPeripheral,
175 )
176 };
177
178 let tx_transfer = tx_transfer.start(dma);
179
180 self.qspi.cr.modify(|_, w| w.dmaen().set_bit());
182
183 Ok(tx_transfer)
184 }
185 None => Err(Error::BadParam),
186 }
187 }
188
189 pub fn read(&mut self, buf: &mut [u8], transaction: QspiTransaction) -> Result<(), Error> {
191 self.qspi.cr.modify(|_, w| w.dmaen().clear_bit());
193
194 self.setup_transaction(QspiMode::INDIRECT_READ, &transaction);
196
197 if let Some(len) = transaction.data_len {
199 let mut idx: usize = 0;
200 while idx < len {
201 let num_bytes = self.qspi.sr.read().flevel().bits();
203 if num_bytes > 0 {
204 let word = self.qspi.dr.read().data().bits();
206
207 let num_unpack = if num_bytes >= 4 { 4 } else { num_bytes };
209 for i in 0..num_unpack {
210 buf[idx] = ((word & (0xFF << (i * 8))) >> (i * 8)).try_into().unwrap();
211 idx += 1;
212 }
213 }
214 }
215 }
216
217 Ok(())
218 }
219
220 pub fn write(&mut self, buf: &[u8], transaction: QspiTransaction) -> Result<(), Error> {
222 self.qspi.cr.modify(|_, w| w.dmaen().clear_bit());
224
225 self.setup_transaction(QspiMode::INDIRECT_WRITE, &transaction);
227
228 if let Some(len) = transaction.data_len {
230 let mut idx: usize = 0;
231 while idx < len {
232 let num_bytes = self.qspi.sr.read().flevel().bits();
234 if num_bytes == 0 {
235 let mut word: u32 = 0;
237 let num_pack = if (len - idx) >= 4 { 4 } else { len - idx };
238 for i in 0..num_pack {
239 word |= (buf[idx] as u32) << (i * 8);
240 idx += 1;
241 }
242
243 unsafe {
245 self.qspi.dr.write(|w| w.data().bits(word));
246 }
247 }
248 }
249 }
250
251 Ok(())
252 }
253
254 fn setup_transaction(&mut self, fmode: u8, transaction: &QspiTransaction) {
256 unsafe {
257 self.qspi.fcr.write(|w| w.bits(0x1B));
259
260 if let Some(len) = transaction.data_len {
262 self.qspi.dlr.write(|w| w.bits(len as u32 - 1));
263 }
264
265 self.qspi.ccr.write_with_zero(|w| {
267 w.fmode()
268 .bits(fmode)
269 .imode()
270 .bits(transaction.iwidth)
271 .admode()
272 .bits(transaction.awidth)
273 .dmode()
274 .bits(transaction.dwidth)
275 .adsize()
276 .bits(self.adsize)
277 .abmode()
278 .bits(QspiWidth::NONE)
279 .dcyc()
280 .bits(transaction.dummy)
281 .instruction()
282 .bits(transaction.instruction)
283 });
284
285 if let Some(addr) = transaction.address {
287 self.qspi.ar.write(|w| w.bits(addr));
288 }
289 }
290 }
291
292 fn dr_address(&self) -> u32 {
294 &self.qspi.dr as *const _ as _
295 }
296}
297
298pub struct RxTx<I>(PhantomData<I>);