-
Notifications
You must be signed in to change notification settings - Fork 209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SPI BIDI mode not working #520
Comments
cc @no111u3 I think we should implement optimized versions of transmission procedures like it described in About example. |
In case someone runs into this issue as well, this is a working BIDI SPI implementation conforming to embedded_hal. pub struct BidiSPI<SPI> {
pub spi: SPI,
}
impl<SPI> BidiSPI<SPI>
where
SPI: Instance,
{
pub fn new(spi: SPI) -> BidiSPI<SPI> {
spi.cr1.modify(|_, w| {
w.cpha()
.second_edge()
.bidimode()
.bidirectional()
.br()
.div32()
.cpol()
.idle_high()
.mstr()
.master()
.ssm()
.enabled()
.ssi()
.slave_not_selected()
.bidioe()
.output_enabled()
.spe()
.enabled()
});
BidiSPI { spi }
}
fn read_word(&self) -> u8 {
self.spi.cr1.modify(|_, w| w.spe().clear_bit());
self.spi.cr1.modify(|_, v| v.bidioe().clear_bit());
self.spi.cr1.modify(|_, w| w.spe().set_bit());
for _l in 0..70 {
dsb();
}
self.spi.cr1.modify(|_, v| v.spe().clear_bit());
while self.spi.sr.read().rxne().bit_is_clear() {}
let word = self.spi.dr.read().dr().bits() as u8;
while self.spi.sr.read().bsy().bit_is_set() {}
self.spi.cr1.modify(|_, v| v.bidioe().set_bit());
self.spi.cr1.modify(|_, v| v.spe().set_bit());
word
}
fn write_word(&self, word: u8) {
while self.spi.sr.read().txe().bit_is_clear() {}
self.spi.dr.modify(|_, w| w.dr().bits(word as u16));
while self.spi.sr.read().txe().bit_is_clear() {}
while self.spi.sr.read().bsy().bit_is_set() {}
}
}
impl<SPI> embedded_hal::blocking::spi::Transfer<u8> for BidiSPI<SPI>
where
SPI: Instance,
{
type Error = stm32f4xx_hal::spi::Error;
/// transfer n bytes from the address at words[0]. follows the STM sample code
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
// to support multiple byte transfer you have to toggle the CS pin between words
// this trait does not allow to hold mutable pin references with a diferent lifetime
assert!(
words.len() == 1,
"only one word transfers are supported without CS pin control"
);
if let Some(word) = words.iter_mut().next() {
self.write_word(*word | 0x80);
*word = self.read_word();
}
Ok(words)
}
}
impl<SPI> embedded_hal::blocking::spi::Write<u8> for BidiSPI<SPI>
where
SPI: Instance,
{
type Error = stm32f4xx_hal::spi::Error;
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
for w in words {
self.write_word(*w);
}
Ok(())
}
} |
The SPI BIDI mode does not seem to function, it never reads anything other than 255 or 0.
I'm using a STEVAL-FCU001 board with a STM32F401 and trying to interface with the LPS22HD sensor which is present on SPI2 together with a LSM6DSL and LIS2MDL sensor. The SPI is 3-wire.
Using the same setup for both examples below, the one using the HAL SPI methods never works. All GPIO pins are configured correctly (PP, AF5, Very High Speed) and equally for both examples. The resulting config in the SPI2 CR1 reg is equal. Both examples attempt to read the WHO_AM_I register on the LPS22HD at 0x0F.
tx
is USART1.HAL SPI example, does not work:
Writes
177 == [0]
👎Working example, based on the C firmware sample from STM. I have included every SPI2 reg access with the exception of a NOP SPI2 SPE OFF-ON sequence.
Writes
177 == [177]
👍There seem to be 2 key differences with the latter example compared to the HAL SPI example: the SPI2 interface is disabled after write before read and a comically large amount of DSB instructions are issued following the clear of the BIDIOE bit in CR1.
The text was updated successfully, but these errors were encountered: