stm32l4xx_hal/
qspi.rs

1//! Quad Serial Peripheral Interface (QSPI) bus
2
3use crate::gpio::{
4    gpioa::{PA6, PA7},
5    gpiob::{PB0, PB1, PB10, PB11},
6    gpioe::{PE10, PE11, PE12, PE13, PE14, PE15},
7};
8
9#[cfg(not(any(feature = "stm32l475")))]
10use crate::gpio::{
11    gpioa::{PA2, PA3},
12    gpiod::{PD3, PD4, PD5, PD6, PD7},
13};
14
15#[cfg(any(
16    feature = "stm32l476",
17    feature = "stm32l486",
18    feature = "stm32l496",
19    feature = "stm32l4a6"
20))]
21use crate::gpio::{
22    gpioc::{PC1, PC2, PC4, PC5},
23    gpiof::{PF6, PF7, PF8, PF9},
24};
25
26use crate::gpio::{Alternate, PushPull, Speed};
27use crate::rcc::{Enable, AHB3};
28use crate::stm32::QUADSPI;
29use core::ptr;
30
31#[doc(hidden)]
32mod private {
33    pub trait Sealed {}
34}
35
36/// CLK pin. This trait is sealed and cannot be implemented.
37pub trait ClkPin<QSPI>: private::Sealed {
38    fn set_speed(self, speed: Speed) -> Self;
39}
40/// nCS pin. This trait is sealed and cannot be implemented.
41pub trait NCSPin<QSPI>: private::Sealed {
42    fn set_speed(self, speed: Speed) -> Self;
43}
44/// IO0 pin. This trait is sealed and cannot be implemented.
45pub trait IO0Pin<QSPI>: private::Sealed {
46    fn set_speed(self, speed: Speed) -> Self;
47}
48/// IO1 pin. This trait is sealed and cannot be implemented.
49pub trait IO1Pin<QSPI>: private::Sealed {
50    fn set_speed(self, speed: Speed) -> Self;
51}
52/// IO2 pin. This trait is sealed and cannot be implemented.
53pub trait IO2Pin<QSPI>: private::Sealed {
54    fn set_speed(self, speed: Speed) -> Self;
55}
56/// IO3 pin. This trait is sealed and cannot be implemented.
57pub trait IO3Pin<QSPI>: private::Sealed {
58    fn set_speed(self, speed: Speed) -> Self;
59}
60
61macro_rules! pins {
62    ($qspi:ident, $af:literal, CLK: [$($clk:ident),*], nCS: [$($ncs:ident),*],
63        IO0: [$($io0:ident),*], IO1: [$($io1:ident),*], IO2: [$($io2:ident),*],
64        IO3: [$($io3:ident),*]) => {
65        $(
66            impl private::Sealed for $clk<Alternate<PushPull, $af>> {}
67            impl ClkPin<$qspi> for $clk<Alternate<PushPull, $af>> {
68                fn set_speed(self, speed: Speed) -> Self{
69                    self.set_speed(speed)
70                }
71            }
72        )*
73        $(
74            impl private::Sealed for $ncs<Alternate<PushPull, $af>> {}
75            impl NCSPin<$qspi> for $ncs<Alternate<PushPull, $af>> {
76                fn set_speed(self, speed: Speed) -> Self{
77                    self.set_speed(speed)
78                }
79            }
80        )*
81        $(
82            impl private::Sealed for $io0<Alternate<PushPull, $af>> {}
83            impl IO0Pin<$qspi> for $io0<Alternate<PushPull, $af>> {
84                fn set_speed(self, speed: Speed) -> Self{
85                    self.set_speed(speed)
86                }
87            }
88        )*
89        $(
90            impl private::Sealed for $io1<Alternate<PushPull, $af>> {}
91            impl IO1Pin<$qspi> for $io1<Alternate<PushPull, $af>> {
92                fn set_speed(self, speed: Speed) -> Self{
93                    self.set_speed(speed)
94                }
95            }
96        )*
97        $(
98            impl private::Sealed for $io2<Alternate<PushPull, $af>> {}
99            impl IO2Pin<$qspi> for $io2<Alternate<PushPull, $af>> {
100                fn set_speed(self, speed: Speed) -> Self{
101                    self.set_speed(speed)
102                }
103            }
104        )*
105        $(
106            impl private::Sealed for $io3<Alternate<PushPull, $af>> {}
107            impl IO3Pin<$qspi> for $io3<Alternate<PushPull, $af>> {
108                fn set_speed(self, speed: Speed) -> Self{
109                    self.set_speed(speed)
110                }
111            }
112        )*
113    }
114}
115
116#[derive(Copy, Clone, Debug, PartialEq)]
117#[repr(u8)]
118pub enum QspiMode {
119    SingleChannel = 0b01,
120    DualChannel = 0b10,
121    QuadChannel = 0b11,
122}
123
124#[derive(Copy, Clone, Debug, PartialEq)]
125#[repr(u8)]
126pub enum AddressSize {
127    Addr8Bit = 0b00,
128    Addr16Bit = 0b01,
129    Addr24Bit = 0b10,
130    Addr32Bit = 0b11,
131}
132
133#[derive(Copy, Clone, Debug, PartialEq)]
134pub enum SampleShift {
135    None,
136    HalfACycle,
137}
138
139#[derive(Copy, Clone, Debug, PartialEq)]
140pub enum ClockMode {
141    Mode0,
142    Mode3,
143}
144
145#[derive(Copy, Clone, Debug, PartialEq)]
146pub enum QspiError {
147    Busy,
148    Address,
149    Unknown,
150}
151
152#[derive(Copy, Clone, Debug, PartialEq)]
153pub struct QspiConfig {
154    /// This field defines the scaler factor for generating CLK based on the AHB clock
155    /// (value+1).
156    clock_prescaler: u8,
157    /// Number of bytes in Flash memory = 2^[FSIZE+1]
158    flash_size: u8,
159    address_size: AddressSize,
160    /// This bit indicates the level that CLK takes between commands Mode 0(low) / mode 3(high)
161    clock_mode: ClockMode,
162    /// FIFO threshold level (Activates FTF, QUADSPI_SR[2]) 0-15.
163    fifo_threshold: u8,
164    sample_shift: SampleShift,
165    /// CSHT+1 defines the minimum number of CLK cycles which the chip select (nCS) must
166    /// remain high between commands issued to the Flash memory.
167    chip_select_high_time: u8,
168    qpi_mode: bool,
169}
170
171impl Default for QspiConfig {
172    fn default() -> QspiConfig {
173        QspiConfig {
174            clock_prescaler: 0,
175            flash_size: 22, // 8MB // 26 = 128MB
176            address_size: AddressSize::Addr24Bit,
177            clock_mode: ClockMode::Mode0,
178            fifo_threshold: 1,
179            sample_shift: SampleShift::HalfACycle,
180            chip_select_high_time: 1,
181            qpi_mode: false,
182        }
183    }
184}
185
186impl QspiConfig {
187    pub fn clock_prescaler(mut self, clk_pre: u8) -> Self {
188        self.clock_prescaler = clk_pre;
189        self
190    }
191
192    pub fn flash_size(mut self, fl_size: u8) -> Self {
193        self.flash_size = fl_size;
194        self
195    }
196
197    pub fn address_size(mut self, add_size: AddressSize) -> Self {
198        self.address_size = add_size;
199        self
200    }
201
202    pub fn clock_mode(mut self, clk_mode: ClockMode) -> Self {
203        self.clock_mode = clk_mode;
204        self
205    }
206
207    pub fn fifo_threshold(mut self, fifo_thres: u8) -> Self {
208        self.fifo_threshold = fifo_thres;
209        self
210    }
211
212    pub fn sample_shift(mut self, shift: SampleShift) -> Self {
213        self.sample_shift = shift;
214        self
215    }
216
217    pub fn chip_select_high_time(mut self, csht: u8) -> Self {
218        self.chip_select_high_time = csht;
219        self
220    }
221
222    pub fn qpi_mode(mut self, qpi: bool) -> Self {
223        self.qpi_mode = qpi;
224        self
225    }
226}
227
228#[derive(Copy, Clone, Debug, PartialEq)]
229pub struct QspiWriteCommand<'a> {
230    pub instruction: Option<(u8, QspiMode)>,
231    pub address: Option<(u32, QspiMode)>,
232    pub alternative_bytes: Option<(&'a [u8], QspiMode)>,
233    pub dummy_cycles: u8,
234    pub data: Option<(&'a [u8], QspiMode)>,
235    pub double_data_rate: bool,
236}
237
238#[derive(Copy, Clone, Debug, PartialEq)]
239pub struct QspiReadCommand<'a> {
240    pub instruction: Option<(u8, QspiMode)>,
241    pub address: Option<(u32, QspiMode)>,
242    pub alternative_bytes: Option<(&'a [u8], QspiMode)>,
243    pub dummy_cycles: u8,
244    pub data_mode: QspiMode,
245    pub receive_length: u32,
246    pub double_data_rate: bool,
247}
248
249impl<'a> QspiWriteCommand<'a> {
250    pub fn address(self, addr: u32, mode: QspiMode) -> Self {
251        QspiWriteCommand {
252            address: Some((addr, mode)),
253            ..self
254        }
255    }
256
257    pub fn alternative_bytes(self, bytes: &'a [u8], mode: QspiMode) -> Self {
258        QspiWriteCommand {
259            alternative_bytes: Some((bytes, mode)),
260            ..self
261        }
262    }
263
264    pub fn dummy_cycles(self, n: u8) -> Self {
265        QspiWriteCommand {
266            dummy_cycles: n,
267            ..self
268        }
269    }
270
271    pub fn data(self, bytes: &'a [u8], mode: QspiMode) -> Self {
272        QspiWriteCommand {
273            data: Some((bytes, mode)),
274            ..self
275        }
276    }
277}
278
279impl<'a> QspiReadCommand<'a> {
280    pub fn address(self, addr: u32, mode: QspiMode) -> Self {
281        QspiReadCommand {
282            address: Some((addr, mode)),
283            ..self
284        }
285    }
286
287    pub fn alternative_bytes(self, bytes: &'a [u8], mode: QspiMode) -> Self {
288        QspiReadCommand {
289            alternative_bytes: Some((bytes, mode)),
290            ..self
291        }
292    }
293
294    pub fn dummy_cycles(self, n: u8) -> Self {
295        QspiReadCommand {
296            dummy_cycles: n,
297            ..self
298        }
299    }
300
301    pub fn receive_length(self, length: u32) -> Self {
302        QspiReadCommand {
303            receive_length: length,
304            ..self
305        }
306    }
307}
308
309pub struct Qspi<PINS> {
310    qspi: QUADSPI,
311    _pins: PINS,
312    config: QspiConfig,
313}
314
315impl<CLK, NCS, IO0, IO1, IO2, IO3> Qspi<(CLK, NCS, IO0, IO1, IO2, IO3)> {
316    pub fn new(
317        qspi: QUADSPI,
318        pins: (CLK, NCS, IO0, IO1, IO2, IO3),
319        ahb3: &mut AHB3,
320        config: QspiConfig,
321    ) -> Self
322    where
323        CLK: ClkPin<QUADSPI>,
324        NCS: NCSPin<QUADSPI>,
325        IO0: IO0Pin<QUADSPI>,
326        IO1: IO1Pin<QUADSPI>,
327        IO2: IO2Pin<QUADSPI>,
328        IO3: IO3Pin<QUADSPI>,
329    {
330        // Enable quad SPI in the clocks.
331        QUADSPI::enable(ahb3);
332
333        // Disable QUADSPI before configuring it.
334        qspi.cr.modify(|_, w| w.en().clear_bit());
335
336        // Clear all pending flags.
337        qspi.fcr.write(|w| {
338            w.ctof()
339                .set_bit()
340                .csmf()
341                .set_bit()
342                .ctcf()
343                .set_bit()
344                .ctef()
345                .set_bit()
346        });
347
348        // Set gpio speed
349        let high_speed_pins = (
350            pins.0.set_speed(Speed::VeryHigh),
351            pins.1.set_speed(Speed::VeryHigh),
352            pins.2.set_speed(Speed::VeryHigh),
353            pins.3.set_speed(Speed::VeryHigh),
354            pins.4.set_speed(Speed::VeryHigh),
355            pins.5.set_speed(Speed::VeryHigh),
356        );
357
358        let mut unit = Qspi {
359            qspi,
360            _pins: high_speed_pins,
361            config,
362        };
363        unit.apply_config(config);
364        unit
365    }
366
367    pub fn is_busy(&self) -> bool {
368        self.qspi.sr.read().busy().bit_is_set()
369    }
370
371    /// Aborts any ongoing transaction
372    /// Note can cause problems if aborting writes to flash satus register
373    pub fn abort_transmission(&self) {
374        self.qspi.cr.modify(|_, w| w.abort().set_bit());
375        while self.qspi.sr.read().busy().bit_is_set() {}
376    }
377
378    pub fn get_config(&self) -> QspiConfig {
379        self.config
380    }
381
382    pub fn apply_config(&mut self, config: QspiConfig) {
383        if self.qspi.sr.read().busy().bit_is_set() {
384            self.abort_transmission();
385        }
386
387        self.qspi
388            .cr
389            .modify(|_, w| unsafe { w.fthres().bits(config.fifo_threshold as u8) });
390
391        while self.qspi.sr.read().busy().bit_is_set() {}
392
393        // Modify the prescaler and select flash bank 2 - flash bank 1 is currently unsupported.
394        self.qspi.cr.modify(|_, w| unsafe {
395            w.prescaler()
396                .bits(config.clock_prescaler as u8)
397                .sshift()
398                .bit(config.sample_shift == SampleShift::HalfACycle)
399        });
400        while self.is_busy() {}
401
402        // Modify DCR with flash size, CSHT and clock mode
403        self.qspi.dcr.modify(|_, w| unsafe {
404            w.fsize()
405                .bits(config.flash_size as u8)
406                .csht()
407                .bits(config.chip_select_high_time as u8)
408                .ckmode()
409                .bit(config.clock_mode == ClockMode::Mode3)
410        });
411        while self.is_busy() {}
412
413        // Enable QSPI
414        self.qspi.cr.modify(|_, w| w.en().set_bit());
415        while self.is_busy() {}
416
417        self.config = config;
418    }
419
420    pub fn transfer(&self, command: QspiReadCommand, buffer: &mut [u8]) -> Result<(), QspiError> {
421        if self.is_busy() {
422            return Err(QspiError::Busy);
423        }
424
425        // If double data rate change shift
426        if command.double_data_rate {
427            self.qspi.cr.modify(|_, w| w.sshift().bit(false));
428        }
429        while self.is_busy() {}
430
431        // Clear the transfer complete flag.
432        self.qspi.fcr.modify(|_, w| w.ctcf().set_bit());
433
434        let mut dmode: u8 = 0;
435        let mut instruction: u8 = 0;
436        let mut imode: u8 = 0;
437        let mut admode: u8 = 0;
438        let mut adsize: u8 = 0;
439        let mut abmode: u8 = 0;
440        let mut absize: u8 = 0;
441
442        // Write the length and format of data
443        if command.receive_length > 0 {
444            self.qspi
445                .dlr
446                .write(|w| unsafe { w.dl().bits(command.receive_length as u32 - 1) });
447            if self.config.qpi_mode {
448                dmode = QspiMode::QuadChannel as u8;
449            } else {
450                dmode = command.data_mode as u8;
451            }
452        }
453
454        // Write instruction mode
455        if let Some((inst, mode)) = command.instruction {
456            if self.config.qpi_mode {
457                imode = QspiMode::QuadChannel as u8;
458            } else {
459                imode = mode as u8;
460            }
461            instruction = inst;
462        }
463
464        // Note Address mode
465        if let Some((_, mode)) = command.address {
466            if self.config.qpi_mode {
467                admode = QspiMode::QuadChannel as u8;
468            } else {
469                admode = mode as u8;
470            }
471            adsize = self.config.address_size as u8;
472        }
473
474        // Write Alternative bytes
475        if let Some((a_bytes, mode)) = command.alternative_bytes {
476            if self.config.qpi_mode {
477                abmode = QspiMode::QuadChannel as u8;
478            } else {
479                abmode = mode as u8;
480            }
481
482            absize = a_bytes.len() as u8 - 1;
483
484            self.qspi.abr.write(|w| {
485                let mut reg_byte: u32 = 0;
486                for (i, element) in a_bytes.iter().rev().enumerate() {
487                    reg_byte |= (*element as u32) << (i * 8);
488                }
489                unsafe { w.alternate().bits(reg_byte) }
490            });
491        }
492
493        // Write CCR register with instruction etc.
494        self.qspi.ccr.modify(|_, w| unsafe {
495            w.fmode()
496                .bits(0b01)
497                .admode()
498                .bits(admode)
499                .adsize()
500                .bits(adsize)
501                .abmode()
502                .bits(abmode)
503                .absize()
504                .bits(absize)
505                .ddrm()
506                .bit(command.double_data_rate)
507                .dcyc()
508                .bits(command.dummy_cycles)
509                .dmode()
510                .bits(dmode)
511                .imode()
512                .bits(imode)
513                .instruction()
514                .bits(instruction)
515        });
516
517        // Write address, triggers send
518        if let Some((addr, _)) = command.address {
519            self.qspi.ar.write(|w| unsafe { w.address().bits(addr) });
520
521            // Transfer error
522            if self.qspi.sr.read().tef().bit_is_set() {
523                return Err(QspiError::Address);
524            }
525        }
526
527        // Transfer error
528        if self.qspi.sr.read().tef().bit_is_set() {
529            return Err(QspiError::Unknown);
530        }
531
532        // Read data from the buffer
533        let mut b = buffer.iter_mut();
534        while self.qspi.sr.read().tcf().bit_is_clear() {
535            if self.qspi.sr.read().ftf().bit_is_set() {
536                if let Some(v) = b.next() {
537                    unsafe {
538                        *v = ptr::read_volatile(&self.qspi.dr as *const _ as *const u8);
539                    }
540                } else {
541                    // OVERFLOW
542                }
543            }
544        }
545        // When transfer complete, empty fifo buffer
546        while self.qspi.sr.read().flevel().bits() > 0 {
547            if let Some(v) = b.next() {
548                unsafe {
549                    *v = ptr::read_volatile(&self.qspi.dr as *const _ as *const u8);
550                }
551            } else {
552                // OVERFLOW
553            }
554        }
555        // If double data rate set shift back to original and if busy abort.
556        if command.double_data_rate {
557            if self.is_busy() {
558                self.abort_transmission();
559            }
560            self.qspi.cr.modify(|_, w| {
561                w.sshift()
562                    .bit(self.config.sample_shift == SampleShift::HalfACycle)
563            });
564        }
565        while self.is_busy() {}
566        self.qspi.fcr.write(|w| w.ctcf().set_bit());
567        Ok(())
568    }
569
570    pub fn write(&self, command: QspiWriteCommand) -> Result<(), QspiError> {
571        if self.is_busy() {
572            return Err(QspiError::Busy);
573        }
574        // Clear the transfer complete flag.
575        self.qspi.fcr.modify(|_, w| w.ctcf().set_bit());
576
577        let mut dmode: u8 = 0;
578        let mut instruction: u8 = 0;
579        let mut imode: u8 = 0;
580        let mut admode: u8 = 0;
581        let mut adsize: u8 = 0;
582        let mut abmode: u8 = 0;
583        let mut absize: u8 = 0;
584
585        // Write the length and format of data
586        if let Some((data, mode)) = command.data {
587            self.qspi
588                .dlr
589                .write(|w| unsafe { w.dl().bits(data.len() as u32 - 1) });
590            if self.config.qpi_mode {
591                dmode = QspiMode::QuadChannel as u8;
592            } else {
593                dmode = mode as u8;
594            }
595        }
596
597        // Write instruction mode
598        if let Some((inst, mode)) = command.instruction {
599            if self.config.qpi_mode {
600                imode = QspiMode::QuadChannel as u8;
601            } else {
602                imode = mode as u8;
603            }
604            instruction = inst;
605        }
606
607        // Note Address mode
608        if let Some((_, mode)) = command.address {
609            if self.config.qpi_mode {
610                admode = QspiMode::QuadChannel as u8;
611            } else {
612                admode = mode as u8;
613            }
614            adsize = self.config.address_size as u8;
615        }
616
617        // Write Alternative bytes
618        if let Some((a_bytes, mode)) = command.alternative_bytes {
619            if self.config.qpi_mode {
620                abmode = QspiMode::QuadChannel as u8;
621            } else {
622                abmode = mode as u8;
623            }
624
625            absize = a_bytes.len() as u8 - 1;
626
627            self.qspi.abr.write(|w| {
628                let mut reg_byte: u32 = 0;
629                for (i, element) in a_bytes.iter().rev().enumerate() {
630                    reg_byte |= (*element as u32) << (i * 8);
631                }
632                unsafe { w.alternate().bits(reg_byte) }
633            });
634        }
635
636        if command.double_data_rate {
637            self.qspi.cr.modify(|_, w| w.sshift().bit(false));
638        }
639
640        // Write CCR register with instruction etc.
641        self.qspi.ccr.modify(|_, w| unsafe {
642            w.fmode()
643                .bits(0b00)
644                .admode()
645                .bits(admode)
646                .adsize()
647                .bits(adsize)
648                .abmode()
649                .bits(abmode)
650                .absize()
651                .bits(absize)
652                .ddrm()
653                .bit(command.double_data_rate)
654                .dcyc()
655                .bits(command.dummy_cycles)
656                .dmode()
657                .bits(dmode)
658                .imode()
659                .bits(imode)
660                .instruction()
661                .bits(instruction)
662        });
663
664        // Write address, triggers send
665        if let Some((addr, _)) = command.address {
666            self.qspi.ar.write(|w| unsafe { w.address().bits(addr) });
667        }
668
669        // Transfer error
670        if self.qspi.sr.read().tef().bit_is_set() {
671            return Err(QspiError::Unknown);
672        }
673
674        // Write data to the FIFO
675        if let Some((data, _)) = command.data {
676            for byte in data {
677                while self.qspi.sr.read().ftf().bit_is_clear() {}
678                unsafe {
679                    ptr::write_volatile(&self.qspi.dr as *const _ as *mut u8, *byte);
680                }
681            }
682        }
683
684        while self.qspi.sr.read().tcf().bit_is_clear() {}
685
686        self.qspi.fcr.write(|w| w.ctcf().set_bit());
687
688        if self.is_busy() {}
689
690        if command.double_data_rate {
691            self.qspi.cr.modify(|_, w| {
692                w.sshift()
693                    .bit(self.config.sample_shift == SampleShift::HalfACycle)
694            });
695        }
696        Ok(())
697    }
698}
699
700pins!(
701    QUADSPI,
702    10,
703    CLK: [PE10, PB10],
704    nCS: [PE11, PB11],
705    IO0: [PE12, PB1],
706    IO1: [PE13, PB0],
707    IO2: [PE14, PA7],
708    IO3: [PE15, PA6]
709);
710
711#[cfg(not(any(feature = "stm32l475")))]
712pins!(
713    QUADSPI,
714    10,
715    CLK: [PA3],
716    nCS: [PA2, PD3],
717    IO0: [PD4],
718    IO1: [PD5],
719    IO2: [PD6],
720    IO3: [PD7]
721);
722
723#[cfg(any(
724    feature = "stm32l476",
725    feature = "stm32l486",
726    feature = "stm32l496",
727    feature = "stm32l4a6"
728))]
729pins!(
730    QUADSPI,
731    10,
732    CLK: [],
733    nCS: [],
734    IO0: [PC1, PF8],
735    IO1: [PC2, PF9],
736    IO2: [PC4, PF7],
737    IO3: [PC5, PF6]
738);