Skip to main content

esp_hal/spi/master/low_level/
mod.rs

1#[cfg(spi_master_version = "1")]
2use core::cell::Cell;
3use core::{
4    cell::UnsafeCell,
5    future::Future,
6    mem::MaybeUninit,
7    pin::Pin,
8    sync::atomic::{AtomicUsize, Ordering},
9    task::{Context, Poll},
10};
11
12use enumset::{EnumSet, enum_set};
13
14use super::{
15    Address,
16    AnySpi,
17    Command,
18    Config,
19    ConfigError,
20    DataMode,
21    EMPTY_WRITE_PAD,
22    FIFO_SIZE,
23    SpiInterrupt,
24    SpiPinGuard,
25    any,
26};
27use crate::{
28    asynch::AtomicWaker,
29    clock::ll::SpiInstance,
30    gpio::{InputSignal, OutputSignal},
31    handler,
32    interrupt::InterruptHandler,
33    pac::spi2::RegisterBlock,
34    private::{self, DropGuard},
35    ram,
36    spi::{BitOrder, Error, Mode},
37    system::PeripheralGuard,
38};
39
40#[cfg_attr(spi_master_version = "1", path = "v1.rs")]
41#[cfg_attr(spi_master_version = "2", path = "v2.rs")]
42#[cfg_attr(spi_master_version = "3", path = "v3.rs")]
43mod version;
44
45#[derive(Debug)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub(super) struct SpiWrapper<'d> {
48    pub(super) spi: AnySpi<'d>,
49    _guard: PeripheralGuard,
50}
51
52impl<'d> SpiWrapper<'d> {
53    pub(super) fn new(spi: impl Instance + 'd) -> Self {
54        let p = spi.info().peripheral;
55        let this = Self {
56            spi: spi.degrade(),
57            _guard: PeripheralGuard::new(p),
58        };
59
60        // Initialize state
61        unsafe {
62            this.state()
63                .pins
64                .get()
65                .write(MaybeUninit::new(SpiPinGuard::new_unconnected()))
66        }
67
68        this
69    }
70
71    pub(super) fn info(&self) -> &'static Info {
72        self.spi.info()
73    }
74
75    pub(super) fn state(&self) -> &'static State {
76        self.spi.state()
77    }
78
79    pub(super) fn disable_peri_interrupt_on_all_cores(&self) {
80        self.spi.disable_peri_interrupt_on_all_cores();
81    }
82
83    pub(super) fn set_interrupt_handler(&self, handler: InterruptHandler) {
84        self.spi.set_interrupt_handler(handler);
85    }
86
87    pub(super) fn pins(&mut self) -> &mut SpiPinGuard {
88        unsafe {
89            // SAFETY: we "own" the state, we are allowed to borrow it mutably
90            self.state().pins()
91        }
92    }
93}
94
95impl Drop for SpiWrapper<'_> {
96    fn drop(&mut self) {
97        unsafe {
98            // SAFETY: we "own" the state, we are allowed to deinit it
99            self.spi.state().deinit();
100        }
101    }
102}
103
104pub(super) struct SpiClockGuard {
105    clock: SpiInstance,
106}
107
108impl SpiClockGuard {
109    pub(super) fn new(spi: &Info) -> Self {
110        let clock = spi.clock_instance;
111        crate::clock::ll::ClockTree::with(|clocks| clock.request_function_clock(clocks));
112        Self { clock }
113    }
114}
115
116impl Drop for SpiClockGuard {
117    fn drop(&mut self) {
118        crate::clock::ll::ClockTree::with(|clocks| self.clock.release_function_clock(clocks));
119    }
120}
121
122/// SPI peripheral instance.
123pub trait Instance: private::Sealed + any::Degrade {
124    #[doc(hidden)]
125    /// Returns the peripheral data and state describing this instance.
126    fn parts(&self) -> (&'static Info, &'static State);
127
128    /// Returns the peripheral data describing this instance.
129    #[doc(hidden)]
130    #[inline(always)]
131    fn info(&self) -> &'static Info {
132        self.parts().0
133    }
134
135    /// Returns the peripheral state for this instance.
136    #[doc(hidden)]
137    #[inline(always)]
138    fn state(&self) -> &'static State {
139        self.parts().1
140    }
141}
142
143/// Marker trait for QSPI-capable SPI peripherals.
144#[doc(hidden)]
145pub trait QspiInstance: Instance {}
146
147/// Peripheral data describing a particular SPI instance.
148#[doc(hidden)]
149#[non_exhaustive]
150#[allow(private_interfaces, reason = "Unstable details")]
151pub struct Info {
152    /// Pointer to the register block for this SPI instance.
153    ///
154    /// Used with [`Self::register_block`] to access the register block.
155    pub register_block: *const RegisterBlock,
156
157    /// The system peripheral marker.
158    pub peripheral: crate::system::Peripheral,
159
160    /// Interrupt handler for the asynchronous operations.
161    pub async_handler: InterruptHandler,
162
163    /// SCLK signal.
164    pub sclk: OutputSignal,
165
166    /// Chip select signals.
167    pub cs: &'static [OutputSignal],
168
169    pub sio_inputs: &'static [InputSignal],
170    pub sio_outputs: &'static [OutputSignal],
171
172    /// Clocks tree instance for this SPI peripheral.
173    pub clock_instance: crate::soc::clocks::SpiInstance,
174}
175
176impl Info {
177    pub(super) fn cs(&self, n: usize) -> OutputSignal {
178        *unwrap!(self.cs.get(n), "CS{} is not defined", n)
179    }
180
181    pub(super) fn opt_sio_input(&self, n: usize) -> Option<InputSignal> {
182        self.sio_inputs.get(n).copied()
183    }
184
185    pub(super) fn opt_sio_output(&self, n: usize) -> Option<OutputSignal> {
186        self.sio_outputs.get(n).copied()
187    }
188
189    pub(super) fn sio_input(&self, n: usize) -> InputSignal {
190        unwrap!(self.opt_sio_input(n), "SIO{} is not defined", n)
191    }
192
193    pub(super) fn sio_output(&self, n: usize) -> OutputSignal {
194        unwrap!(self.opt_sio_output(n), "SIO{} is not defined", n)
195    }
196}
197
198pub(super) struct Driver {
199    pub(super) info: &'static Info,
200    pub(super) state: &'static State,
201}
202
203// Private implementation bits.
204impl Driver {
205    /// Returns the register block for this SPI instance.
206    pub(super) fn regs(&self) -> &RegisterBlock {
207        unsafe { &*self.info.register_block }
208    }
209
210    pub(super) fn abort_transfer(&self) {
211        version::abort_transfer(self);
212        self.update();
213    }
214
215    /// Initializes for full-duplex 1 bit mode.
216    pub(super) fn init(&self) {
217        version::enable_peripheral_clock(self);
218
219        crate::soc::clocks::ClockTree::with(|clocks| {
220            #[cfg(soc_clock_node_spi_function_clock_is_configurable)]
221            self.info.clock_instance.configure_function_clock(
222                clocks,
223                crate::soc::clocks::SpiFunctionClockConfig::default(),
224            );
225            self.info.clock_instance.request_function_clock(clocks);
226
227            self.regs().user().modify(|_, w| {
228                w.usr_miso_highpart().clear_bit();
229                w.usr_mosi_highpart().clear_bit();
230                w.doutdin().set_bit();
231                w.usr_miso().set_bit();
232                w.usr_mosi().set_bit();
233                w.cs_hold().set_bit();
234                w.usr_dummy_idle().set_bit();
235                w.usr_addr().clear_bit();
236                w.usr_command().clear_bit()
237            });
238
239            version::init(self);
240            self.info.clock_instance.release_function_clock(clocks);
241        });
242
243        self.regs().slave().write(|w| unsafe { w.bits(0) });
244    }
245
246    fn init_spi_data_mode(
247        &self,
248        cmd_mode: DataMode,
249        address_mode: DataMode,
250        data_mode: DataMode,
251    ) -> Result<(), Error> {
252        version::init_spi_data_mode(self, cmd_mode, address_mode, data_mode)
253    }
254
255    /// Enables or disables listening for the given interrupts.
256    #[cfg_attr(not(feature = "unstable"), allow(dead_code))]
257    pub(super) fn enable_listen(&self, interrupts: EnumSet<SpiInterrupt>, enable: bool) {
258        version::enable_listen(self, interrupts, enable);
259    }
260
261    /// Returns the asserted interrupts.
262    #[cfg_attr(not(feature = "unstable"), allow(dead_code))]
263    pub(super) fn interrupts(&self) -> EnumSet<SpiInterrupt> {
264        version::interrupts(self)
265    }
266
267    /// Resets asserted interrupts.
268    pub(super) fn clear_interrupts(&self, interrupts: EnumSet<SpiInterrupt>) {
269        version::clear_interrupts(self, interrupts);
270    }
271
272    pub(super) fn apply_config(&self, config: &Config) -> Result<(), ConfigError> {
273        config.validate()?;
274
275        let raw = config.raw_clock_reg_value()?;
276        crate::soc::clocks::ClockTree::with(|clocks| {
277            #[cfg(soc_clock_node_spi_function_clock_is_configurable)]
278            self.info
279                .clock_instance
280                .configure_function_clock(clocks, config.clock_source);
281            self.info.clock_instance.request_function_clock(clocks);
282
283            self.regs().clock().write(|w| unsafe { w.bits(raw) });
284
285            self.set_bit_order(config.read_bit_order, config.write_bit_order);
286            self.set_data_mode(config.mode);
287
288            version::apply_config(self);
289            self.info.clock_instance.release_function_clock(clocks);
290        });
291
292        self.state
293            .min_async_transfer_size
294            .store(config.min_async_transfer_size, Ordering::Relaxed);
295
296        Ok(())
297    }
298
299    fn set_data_mode(&self, data_mode: Mode) {
300        version::set_data_mode(self, data_mode);
301    }
302
303    #[cfg(not(spi_master_bit_order_is_bool))]
304    fn set_bit_order(&self, read_order: BitOrder, write_order: BitOrder) {
305        let read_value = match read_order {
306            BitOrder::MsbFirst => 0,
307            BitOrder::LsbFirst => 1,
308        };
309        let write_value = match write_order {
310            BitOrder::MsbFirst => 0,
311            BitOrder::LsbFirst => 1,
312        };
313        self.regs().ctrl().modify(|_, w| unsafe {
314            w.rd_bit_order().bits(read_value);
315            w.wr_bit_order().bits(write_value);
316            w
317        });
318    }
319
320    #[cfg(spi_master_bit_order_is_bool)]
321    fn set_bit_order(&self, read_order: BitOrder, write_order: BitOrder) {
322        let read_value = match read_order {
323            BitOrder::MsbFirst => false,
324            BitOrder::LsbFirst => true,
325        };
326        let write_value = match write_order {
327            BitOrder::MsbFirst => false,
328            BitOrder::LsbFirst => true,
329        };
330        self.regs().ctrl().modify(|_, w| {
331            w.rd_bit_order().bit(read_value);
332            w.wr_bit_order().bit(write_value);
333            w
334        });
335    }
336
337    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
338    pub(super) fn fill_fifo(&self, chunk: &[u8]) {
339        let (chunks, rem) = chunk.as_chunks::<4>();
340        let mut w_iter = self.regs().w_iter();
341        for c in chunks {
342            if let Some(w_reg) = w_iter.next() {
343                let word = u32::from_le_bytes(*c);
344                w_reg.write(|w| w.buf().set(word));
345            }
346        }
347        if !rem.is_empty()
348            && let Some(w_reg) = w_iter.next()
349        {
350            let word = match rem.len() {
351                3 => (rem[0] as u32) | ((rem[1] as u32) << 8) | ((rem[2] as u32) << 16),
352                2 => (rem[0] as u32) | ((rem[1] as u32) << 8),
353                1 => rem[0] as u32,
354                _ => unreachable!(),
355            };
356            w_reg.write(|w| w.buf().set(word));
357        }
358    }
359
360    /// Writes bytes to SPI.
361    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
362    pub(super) fn write_one(&self, words: &[u8]) -> Result<(), Error> {
363        if words.len() > FIFO_SIZE {
364            return Err(Error::FifoSizeExeeded);
365        }
366        self.configure_datalen(0, words.len());
367        self.fill_fifo(words);
368        self.start_operation();
369        Ok(())
370    }
371
372    /// Writes bytes to SPI.
373    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
374    pub(super) fn write(&self, words: &[u8]) -> Result<(), Error> {
375        for chunk in words.chunks(FIFO_SIZE) {
376            self.write_one(chunk)?;
377            self.flush()?;
378        }
379        Ok(())
380    }
381
382    /// Writes bytes to SPI.
383    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
384    pub(super) async fn write_async(&self, words: &[u8]) -> Result<(), Error> {
385        for chunk in words.chunks(FIFO_SIZE) {
386            self.write_one(chunk)?;
387            self.flush_async_or_abort().await;
388        }
389        Ok(())
390    }
391
392    /// Reads bytes from SPI.
393    ///
394    /// Sends out a stuffing byte for every byte to read. Does not perform
395    /// flushing. To read the response to a prior write, use [`Self::transfer`]
396    /// instead.
397    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
398    pub(super) fn read(&self, words: &mut [u8]) -> Result<(), Error> {
399        let empty_array = [EMPTY_WRITE_PAD; FIFO_SIZE];
400
401        for chunk in words.chunks_mut(FIFO_SIZE) {
402            self.write_one(&empty_array[0..chunk.len()])?;
403            self.flush()?;
404            self.read_from_fifo(chunk)?;
405        }
406        Ok(())
407    }
408
409    /// Reads bytes from SPI.
410    ///
411    /// Sends out a stuffing byte for every byte to read. To read the response to a
412    /// prior write, use [`Self::transfer`] instead
413    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
414    pub(super) async fn read_async(&self, words: &mut [u8]) -> Result<(), Error> {
415        let empty_array = [EMPTY_WRITE_PAD; FIFO_SIZE];
416
417        for chunk in words.chunks_mut(FIFO_SIZE) {
418            self.write_one(&empty_array[0..chunk.len()])?;
419            self.flush_async_or_abort().await;
420            self.read_from_fifo(chunk)?;
421        }
422        Ok(())
423    }
424
425    /// Reads received bytes from SPI FIFO.
426    ///
427    /// Copies the contents of the SPI receive FIFO into `words`. Does not perform
428    /// any data transfer. To read the response to a prior write, use
429    /// [`Self::transfer`] instead
430    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
431    pub(super) fn read_from_fifo(&self, words: &mut [u8]) -> Result<(), Error> {
432        if words.len() > FIFO_SIZE {
433            return Err(Error::FifoSizeExeeded);
434        }
435
436        for (chunk, w_reg) in words.chunks_mut(4).zip(self.regs().w_iter()) {
437            let reg_val = w_reg.read().bits();
438            let bytes = reg_val.to_le_bytes();
439
440            let len = chunk.len();
441            chunk.copy_from_slice(&bytes[..len]);
442        }
443
444        Ok(())
445    }
446
447    pub(super) fn busy(&self) -> bool {
448        self.regs().cmd().read().usr().bit_is_set()
449    }
450
451    // Check if the bus is busy and if it is wait for it to be idle
452    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
453    pub(super) fn flush_async(&self) -> impl Future<Output = ()> {
454        SpiFuture { driver: self }
455    }
456
457    /// Waits for the current transfer to finish.
458    ///
459    /// If the future is dropped, the transfer is cut short, and the drop blocks for a short while
460    /// until the peripheral is idle.
461    ///
462    /// Await this directly after starting a CPU-driven chunk, with no `.await` in between. A
463    /// future can only be dropped while it is suspended, and the guard is created in the first
464    /// poll, before this future can first suspend. The chunk is therefore covered from the
465    /// moment it starts.
466    ///
467    /// Use [`Self::flush_async`] to wait for a transfer that the caller did not start, e.g. the
468    /// tail of an earlier operation. Cancelling that wait must not abort the other operation.
469    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
470    async fn flush_async_or_abort(&self) {
471        let cancel_on_drop = DropGuard::new((), |_| {
472            self.abort_transfer();
473            let _ = self.flush();
474        });
475        self.flush_async().await;
476        cancel_on_drop.defuse();
477    }
478
479    // Check if the bus is busy and if it is wait for it to be idle
480    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
481    pub(super) fn flush(&self) -> Result<(), Error> {
482        while self.busy() {
483            // wait for bus to be clear
484        }
485        Ok(())
486    }
487
488    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
489    pub(super) fn transfer_in_place(&self, words: &mut [u8]) -> Result<(), Error> {
490        for chunk in words.chunks_mut(FIFO_SIZE) {
491            self.write_one(chunk)?;
492            self.flush()?;
493            self.read_from_fifo(chunk)?;
494        }
495
496        Ok(())
497    }
498
499    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
500    pub(super) fn transfer(&self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
501        let mut write_from = 0;
502        let mut read_from = 0;
503
504        loop {
505            // How many bytes we write in this chunk
506            let write_inc = core::cmp::min(FIFO_SIZE, write.len() - write_from);
507            // How many bytes we read in this chunk
508            let read_inc = core::cmp::min(FIFO_SIZE, read.len() - read_from);
509
510            if (write_inc == 0) && (read_inc == 0) {
511                break;
512            }
513
514            if write_inc < read_inc {
515                // Read more than we write, must pad writing part with zeros
516                let mut empty = [EMPTY_WRITE_PAD; FIFO_SIZE];
517                empty[0..write_inc].copy_from_slice(&write[write_from..][..write_inc]);
518                self.write_one(&empty[..read_inc])?;
519            } else {
520                self.write_one(&write[write_from..][..write_inc])?;
521            }
522
523            self.flush()?;
524
525            if read_inc > 0 {
526                self.read_from_fifo(&mut read[read_from..][..read_inc])?;
527            }
528
529            write_from += write_inc;
530            read_from += read_inc;
531        }
532        Ok(())
533    }
534
535    fn prepare_half_duplex_chunk(&self, first: bool, last: bool) {
536        self.regs().user().modify(|_, w| {
537            if !first {
538                w.usr_command().clear_bit();
539                w.usr_addr().clear_bit();
540                w.usr_dummy().clear_bit();
541                w.cs_setup().clear_bit();
542            }
543            w.cs_hold().bit(!last)
544        });
545        version::set_cs_keep_active(self, !last);
546    }
547
548    /// Blocking, FIFO-based half-duplex read.
549    ///
550    /// Performs the command, address, dummy, and data phases as a single SPI transaction without
551    /// involving the DMA engine. Transfers larger than the FIFO are split into chunks while keeping
552    /// CS asserted.
553    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
554    pub(super) fn half_duplex_read(
555        &self,
556        data_mode: DataMode,
557        cmd: Command,
558        address: Address,
559        dummy: u8,
560        buffer: &mut [u8],
561    ) -> Result<(), Error> {
562        if buffer.is_empty() {
563            error!("Half-duplex mode does not support empty buffer");
564            return Err(Error::Unsupported);
565        }
566
567        self.setup_half_duplex(
568            false,
569            cmd,
570            address,
571            false,
572            dummy,
573            buffer.is_empty(),
574            data_mode,
575        )?;
576
577        let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
578        let mut first = true;
579        let mut chunks = buffer.chunks_mut(FIFO_SIZE).peekable();
580        while let Some(chunk) = chunks.next() {
581            let last = chunks.peek().is_none();
582            self.prepare_half_duplex_chunk(first, last);
583            self.configure_datalen(chunk.len(), 0);
584            self.start_operation();
585            self.flush()?;
586            self.read_from_fifo(chunk)?;
587            first = false;
588        }
589        Ok(())
590    }
591
592    /// Blocking, FIFO-based half-duplex write.
593    ///
594    /// Performs the command, address, dummy, and data phases as a single SPI transaction without
595    /// involving the DMA engine. Transfers larger than the FIFO are split into chunks while keeping
596    /// CS asserted.
597    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
598    pub(super) fn half_duplex_write(
599        &self,
600        data_mode: DataMode,
601        cmd: Command,
602        address: Address,
603        dummy: u8,
604        buffer: &[u8],
605    ) -> Result<(), Error> {
606        cfg_select! {
607            all(spi_master_version = "1", spi_address_workaround) => {
608                let mut buffer = buffer;
609                let mut data_mode = data_mode;
610                let mut address = address;
611                let addr_bytes;
612                if buffer.is_empty() && !address.is_none() {
613                    // If the buffer is empty, we need to send a dummy byte
614                    // to trigger the address phase.
615                    let bytes_to_write = address.width().div_ceil(8);
616                    // The address register is read in big-endian order,
617                    // we have to prepare the emulated write in the same way.
618                    addr_bytes = address.value().to_be_bytes();
619                    buffer = &addr_bytes[4 - bytes_to_write..][..bytes_to_write];
620                    data_mode = address.mode();
621                    address = Address::None;
622                }
623
624                if dummy > 0 {
625                    // FIXME: https://github.com/esp-rs/esp-hal/issues/2240
626                    error!("Dummy bits are not supported without data");
627                    return Err(Error::Unsupported);
628                }
629            }
630            _ => {}
631        }
632
633        self.setup_half_duplex(
634            true,
635            cmd,
636            address,
637            false,
638            dummy,
639            buffer.is_empty(),
640            data_mode,
641        )?;
642
643        let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
644        if buffer.is_empty() {
645            self.prepare_half_duplex_chunk(true, true);
646            self.start_operation();
647            self.flush()?;
648        } else {
649            let mut first = true;
650            let mut chunks = buffer.chunks(FIFO_SIZE).peekable();
651            while let Some(chunk) = chunks.next() {
652                let last = chunks.peek().is_none();
653                self.prepare_half_duplex_chunk(first, last);
654                self.configure_datalen(0, chunk.len());
655                self.fill_fifo(chunk);
656                self.start_operation();
657                self.flush()?;
658                first = false;
659            }
660        }
661        Ok(())
662    }
663
664    /// Asynchronous, FIFO-based half-duplex read.
665    ///
666    /// Performs the command, address, dummy, and data phases as a single SPI transaction without
667    /// involving the DMA engine. Transfers larger than the FIFO are split into chunks while keeping
668    /// CS asserted.
669    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
670    pub(super) async fn half_duplex_read_async(
671        &self,
672        data_mode: DataMode,
673        cmd: Command,
674        address: Address,
675        dummy: u8,
676        buffer: &mut [u8],
677    ) -> Result<(), Error> {
678        if buffer.is_empty() {
679            error!("Half-duplex mode does not support empty buffer");
680            return Err(Error::Unsupported);
681        }
682
683        self.setup_half_duplex(
684            false,
685            cmd,
686            address,
687            false,
688            dummy,
689            buffer.is_empty(),
690            data_mode,
691        )?;
692
693        let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
694        let mut first = true;
695        let mut chunks = buffer.chunks_mut(FIFO_SIZE).peekable();
696        while let Some(chunk) = chunks.next() {
697            let last = chunks.peek().is_none();
698            self.prepare_half_duplex_chunk(first, last);
699            self.configure_datalen(chunk.len(), 0);
700            self.start_operation();
701            self.flush_async_or_abort().await;
702            self.read_from_fifo(chunk)?;
703            first = false;
704        }
705        Ok(())
706    }
707
708    /// Asynchronous, FIFO-based half-duplex write.
709    ///
710    /// Performs the command, address, dummy, and data phases as a single SPI transaction without
711    /// involving the DMA engine. Transfers larger than the FIFO are split into chunks while keeping
712    /// CS asserted.
713    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
714    pub(super) async fn half_duplex_write_async(
715        &self,
716        data_mode: DataMode,
717        cmd: Command,
718        address: Address,
719        dummy: u8,
720        buffer: &[u8],
721    ) -> Result<(), Error> {
722        cfg_select! {
723            all(spi_master_version = "1", spi_address_workaround) => {
724                let mut buffer = buffer;
725                let mut data_mode = data_mode;
726                let mut address = address;
727                let addr_bytes;
728                if buffer.is_empty() && !address.is_none() {
729                    // If the buffer is empty, we need to send a dummy byte
730                    // to trigger the address phase.
731                    let bytes_to_write = address.width().div_ceil(8);
732                    // The address register is read in big-endian order,
733                    // we have to prepare the emulated write in the same way.
734                    addr_bytes = address.value().to_be_bytes();
735                    buffer = &addr_bytes[4 - bytes_to_write..][..bytes_to_write];
736                    data_mode = address.mode();
737                    address = Address::None;
738                }
739
740                if dummy > 0 {
741                    // FIXME: https://github.com/esp-rs/esp-hal/issues/2240
742                    error!("Dummy bits are not supported without data");
743                    return Err(Error::Unsupported);
744                }
745            }
746            _ => {}
747        }
748
749        self.setup_half_duplex(
750            true,
751            cmd,
752            address,
753            false,
754            dummy,
755            buffer.is_empty(),
756            data_mode,
757        )?;
758
759        let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
760        if buffer.is_empty() {
761            self.prepare_half_duplex_chunk(true, true);
762            self.start_operation();
763            self.flush_async_or_abort().await;
764        } else {
765            let mut first = true;
766            let mut chunks = buffer.chunks(FIFO_SIZE).peekable();
767            while let Some(chunk) = chunks.next() {
768                let last = chunks.peek().is_none();
769                self.prepare_half_duplex_chunk(first, last);
770                self.configure_datalen(0, chunk.len());
771                self.fill_fifo(chunk);
772                self.start_operation();
773                self.flush_async_or_abort().await;
774                first = false;
775            }
776        }
777        Ok(())
778    }
779
780    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
781    pub(super) async fn transfer_in_place_async(&self, words: &mut [u8]) -> Result<(), Error> {
782        for chunk in words.chunks_mut(FIFO_SIZE) {
783            self.write_one(chunk)?;
784            self.flush_async_or_abort().await;
785            self.read_from_fifo(chunk)?;
786        }
787
788        Ok(())
789    }
790
791    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
792    pub(super) async fn transfer_async(&self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
793        let mut write_from = 0;
794        let mut read_from = 0;
795
796        loop {
797            // How many bytes we write in this chunk
798            let write_inc = core::cmp::min(FIFO_SIZE, write.len() - write_from);
799            // How many bytes we read in this chunk
800            let read_inc = core::cmp::min(FIFO_SIZE, read.len() - read_from);
801
802            if (write_inc == 0) && (read_inc == 0) {
803                break;
804            }
805
806            self.flush_async().await;
807
808            if write_inc < read_inc {
809                // Read more than we write, must pad writing part with zeros
810                let mut empty = [EMPTY_WRITE_PAD; FIFO_SIZE];
811                empty[0..write_inc].copy_from_slice(&write[write_from..][..write_inc]);
812                self.write_one(&empty[..read_inc])?;
813            } else {
814                self.write_one(&write[write_from..][..write_inc])?;
815            }
816
817            self.flush_async_or_abort().await;
818
819            if read_inc > 0 {
820                self.read_from_fifo(&mut read[read_from..][..read_inc])?;
821            }
822
823            write_from += write_inc;
824            read_from += read_inc;
825        }
826        Ok(())
827    }
828
829    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
830    pub(super) fn start_operation(&self) {
831        self.update();
832        self.clear_interrupts(SpiInterrupt::TransferDone.into());
833        self.regs().cmd().modify(|_, w| w.usr().set_bit());
834    }
835
836    pub(super) fn setup_full_duplex(&self) -> Result<(), Error> {
837        self.regs().user().modify(|_, w| {
838            w.usr_miso().set_bit();
839            w.usr_mosi().set_bit();
840            w.doutdin().set_bit();
841            w.usr_dummy().clear_bit();
842            w.sio().clear_bit()
843        });
844
845        self.init_spi_data_mode(
846            DataMode::SingleTwoDataLines,
847            DataMode::SingleTwoDataLines,
848            DataMode::SingleTwoDataLines,
849        )?;
850
851        version::setup_full_duplex(self);
852
853        Ok(())
854    }
855
856    #[expect(clippy::too_many_arguments)]
857    pub(super) fn setup_half_duplex(
858        &self,
859        is_write: bool,
860        cmd: Command,
861        address: Address,
862        dummy_idle: bool,
863        dummy: u8,
864        no_mosi_miso: bool,
865        data_mode: DataMode,
866    ) -> Result<(), Error> {
867        self.init_spi_data_mode(cmd.mode(), address.mode(), data_mode)?;
868
869        let dummy = version::prepare_half_duplex(self, is_write, dummy);
870
871        let reg_block = self.regs();
872        reg_block.user().modify(|_, w| {
873            w.usr_miso_highpart().clear_bit();
874            w.usr_mosi_highpart().clear_bit();
875            // This bit tells the hardware whether we use Single or SingleTwoDataLines
876            w.sio().bit(data_mode == DataMode::Single);
877            w.doutdin().clear_bit();
878            w.usr_miso().bit(!is_write && !no_mosi_miso);
879            w.usr_mosi().bit(is_write && !no_mosi_miso);
880            w.cs_hold().set_bit();
881            w.usr_dummy_idle().bit(dummy_idle);
882            w.usr_dummy().bit(dummy != 0);
883            w.usr_addr().bit(!address.is_none());
884            w.usr_command().bit(!cmd.is_none())
885        });
886
887        version::setup_half_duplex(self);
888
889        reg_block.slave().write(|w| unsafe { w.bits(0) });
890
891        self.update();
892
893        // set cmd, address, dummy cycles
894        self.set_up_common_phases(cmd, address, dummy);
895
896        Ok(())
897    }
898
899    pub(super) fn set_up_common_phases(&self, cmd: Command, address: Address, dummy: u8) {
900        let reg_block = self.regs();
901        if !cmd.is_none() {
902            reg_block.user2().modify(|_, w| unsafe {
903                w.usr_command_bitlen().bits((cmd.width() - 1) as u8);
904                w.usr_command_value().bits(cmd.value())
905            });
906        }
907
908        if !address.is_none() {
909            reg_block
910                .user1()
911                .modify(|_, w| unsafe { w.usr_addr_bitlen().bits((address.width() - 1) as u8) });
912
913            version::write_address(self, address.value() << (32 - address.width()));
914        }
915
916        if dummy > 0 {
917            reg_block
918                .user1()
919                .modify(|_, w| unsafe { w.usr_dummy_cyclelen().bits(dummy - 1) });
920        }
921    }
922
923    pub(super) fn update(&self) {
924        cfg_select! {
925            spi_master_version = "3" => {
926                let reg_block = self.regs();
927
928                reg_block.cmd().modify(|_, w| w.update().set_bit());
929
930                while reg_block.cmd().read().update().bit_is_set() {
931                    // wait
932                }
933            }
934            _ => {
935                // Doesn't seem to be needed for ESP32 and ESP32-S2
936            }
937        }
938    }
939
940    pub(super) fn configure_datalen(&self, rx_len_bytes: usize, tx_len_bytes: usize) {
941        let rx_len = rx_len_bytes as u32 * 8;
942        let tx_len = tx_len_bytes as u32 * 8;
943
944        version::configure_datalen(self, rx_len.saturating_sub(1), tx_len.saturating_sub(1));
945    }
946}
947
948impl PartialEq for Info {
949    fn eq(&self, other: &Self) -> bool {
950        core::ptr::eq(self.register_block, other.register_block)
951    }
952}
953
954unsafe impl Sync for Info {}
955
956for_each_spi_master! {
957    ($peri:ident, $sys:ident, $sclk:ident [$($cs:ident),+] [$($sio:ident),*] $(, $is_qspi:tt)?) => {
958        impl Instance for crate::peripherals::$peri<'_> {
959            #[inline(always)]
960            fn parts(&self) -> (&'static Info, &'static State) {
961                #[handler]
962                #[ram]
963                fn irq_handler() {
964                    handle_async(&INFO, &STATE)
965                }
966
967                static INFO: Info = Info {
968                    register_block: crate::peripherals::$peri::ptr(),
969                    peripheral: crate::system::Peripheral::$sys,
970                    async_handler: irq_handler,
971                    sclk: OutputSignal::$sclk,
972                    cs: &[$(OutputSignal::$cs),+],
973                    sio_inputs: &[$(InputSignal::$sio),*],
974                    sio_outputs: &[$(OutputSignal::$sio),*],
975                    clock_instance: crate::soc::clocks::SpiInstance::$sys,
976                };
977
978                static STATE: State = State {
979                    waker: AtomicWaker::new(),
980                    pins: UnsafeCell::new(MaybeUninit::uninit()),
981                    min_async_transfer_size: AtomicUsize::new(0),
982
983                    #[cfg(spi_master_version = "1")]
984                    esp32_hack: Esp32Hack {
985                        timing_miso_delay: Cell::new(None),
986                        extra_dummy: Cell::new(0),
987                    },
988                };
989
990                (&INFO, &STATE)
991            }
992        }
993
994        $(
995            // If the extra pins are set, implement QspiInstance
996            $crate::ignore!($is_qspi);
997            impl QspiInstance for crate::peripherals::$peri<'_> {}
998        )?
999    };
1000}
1001
1002#[doc(hidden)]
1003pub struct State {
1004    pub(super) waker: AtomicWaker,
1005    pins: UnsafeCell<MaybeUninit<SpiPinGuard>>,
1006    pub(super) min_async_transfer_size: AtomicUsize,
1007
1008    #[cfg(spi_master_version = "1")]
1009    esp32_hack: Esp32Hack,
1010}
1011
1012impl State {
1013    // Syntactic helper to get a mutable reference to the pin guard.
1014    //
1015    // Intended to be called in `SpiWrapper::pins` only
1016    //
1017    // # Safety
1018    //
1019    // The caller must ensure that Rust's aliasing rules are upheld.
1020    #[allow(
1021        clippy::mut_from_ref,
1022        reason = "Safety requirements ensure this is okay"
1023    )]
1024    pub(super) unsafe fn pins(&self) -> &mut SpiPinGuard {
1025        unsafe { (&mut *self.pins.get()).assume_init_mut() }
1026    }
1027
1028    unsafe fn deinit(&self) {
1029        unsafe {
1030            let mut old = self.pins.get().replace(MaybeUninit::uninit());
1031            old.assume_init_drop();
1032        }
1033    }
1034}
1035
1036#[cfg(spi_master_version = "1")]
1037pub(super) struct Esp32Hack {
1038    timing_miso_delay: Cell<Option<u8>>,
1039    extra_dummy: Cell<u8>,
1040}
1041
1042unsafe impl Sync for State {}
1043
1044#[ram]
1045pub(super) fn handle_async(info: &'static Info, state: &'static State) {
1046    let driver = Driver { info, state };
1047    if driver.interrupts().contains(SpiInterrupt::TransferDone) {
1048        driver.enable_listen(SpiInterrupt::TransferDone.into(), false);
1049        state.waker.wake();
1050    }
1051}
1052
1053#[must_use = "futures do nothing unless you `.await` or poll them"]
1054struct SpiFuture<'a> {
1055    driver: &'a Driver,
1056}
1057
1058impl SpiFuture<'_> {
1059    const EVENTS: EnumSet<SpiInterrupt> = enum_set!(SpiInterrupt::TransferDone);
1060}
1061
1062impl Future for SpiFuture<'_> {
1063    type Output = ();
1064
1065    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
1066    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1067        if !self.driver.busy() {
1068            self.driver.clear_interrupts(Self::EVENTS);
1069            return Poll::Ready(());
1070        }
1071
1072        self.driver.state.waker.register(cx.waker());
1073        self.driver.enable_listen(Self::EVENTS, true);
1074
1075        // On some chips the interrupt enable bit and the interrupt status bit are in the same
1076        // register. If the transfer ends while we enable the interrupt, the read-modify-write
1077        // clears the status bit, and the peripheral does not request an interrupt. Check the
1078        // peripheral again to detect this case.
1079        if self.driver.busy() {
1080            Poll::Pending
1081        } else {
1082            self.driver.clear_interrupts(Self::EVENTS);
1083            Poll::Ready(())
1084        }
1085    }
1086}
1087
1088impl Drop for SpiFuture<'_> {
1089    fn drop(&mut self) {
1090        self.driver.enable_listen(Self::EVENTS, false);
1091    }
1092}