David-OConnor / stm32-hal

This library provides access to STM32 peripherals in Rust.
MIT License
147 stars 44 forks source link

Spi works when working within rtic init. It does not work within a rtic task. #81

Closed seanybaggins closed 4 months ago

seanybaggins commented 1 year ago

Hi David,

I am having an issue where spi will work when a write is called within rtic's init function but when a write is called within a software task, the write call hangs.

Initialization code

        let cs = Pin::new(Port::G, 12, PinMode::Output);
        let _sck = Pin::new(Port::C, 10, PinMode::Alt(6));
        let _miso = Pin::new(Port::C, 11, PinMode::Alt(6));
        let _mosi = Pin::new(Port::C, 12, PinMode::Alt(6));

        let mode = SpiMode {
            polarity: SpiPolarity::IdleLow,
            phase: SpiPhase::CaptureOnFirstTransition,
        };
        let spi_config = SpiConfig {
            mode,
            ..Default::default()
        };

        // spi_clock_frequency = 80MHz / BaudRate::<divisor>
        let spi = Spi::new(reg, spi_config, BaudRate::Div32);

Here is where things hang

// In spi.rs line 557
while !self.regs.sr.read().rxne().bit_is_set() {}

Any thoughts or workarounds to getting a spi.write call to work within a software task?

David-OConnor commented 1 year ago

No idea; have never used software tasks. Maybe the RTIC guys can help.

Yandrik commented 1 year ago

Here's the code from spi.rs from line 529 to 561:

  /// Read a single byte if available, or block until it's available.
    /// See L44 RM, section 40.4.9: Data transmission and reception procedures.
    #[cfg(not(feature = "h7"))]
    pub fn read(&mut self) -> Result<u8, SpiError> {
        let sr = self.regs.sr.read();

        cfg_if! {
            if #[cfg(feature = "h7")] {
                let crce = sr.crce().bit_is_set();
            } else {
                let crce = sr.crcerr().bit_is_set();
            }
        }

        if sr.ovr().bit_is_set() {
            return Err(SpiError::Overrun);
        } else if sr.modf().bit_is_set() {
            return Err(SpiError::ModeFault);
        } else if crce {
            return Err(SpiError::Crc);
        }

        cfg_if! {
            if #[cfg(feature = "h7")] {
                while !self.regs.sr.read().rxp().bit_is_set() {}
                // todo: note: H7 can support words beyond u8. (Can others too?)
                Ok(unsafe{ ptr::read_volatile(&self.regs.rxdr as *const _ as *const u8) })
            } else {
                while !self.regs.sr.read().rxne().bit_is_set() {}
                Ok(unsafe { ptr::read_volatile(&self.regs.dr as *const _ as *const u8) })
            }
        }
    }

The RXNE flag indicates that the buffer is not empty ("Receive Not Empty" literally) as far as I understand it. Could you show your software task code? Are you perfectly sure you're not calling read instead of write?

David-OConnor commented 4 months ago

Closing; re-open if this is still coming up.