Skip to content
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 Readings Incorrect on MISO LSB #81

Open
mcopela opened this issue Feb 21, 2020 · 5 comments
Open

SPI Readings Incorrect on MISO LSB #81

mcopela opened this issue Feb 21, 2020 · 5 comments

Comments

@mcopela
Copy link

mcopela commented Feb 21, 2020

I'm seeing a strange problem with the Full Duplex SPI library I can't figure out. Any help is appreciated!

The LSB on my reads usually comes back flipped even though my oscilloscope shows the slave output to be as expected. Only the MISO LSB is affected. This happens no matter what I'm reading or which slave device I connect.

I'm running code on a STM32L031 Evaluation Board. The example below is with a TI CC1200 as the slave.

Example

The master writes 0x3D two times. The slave returns 0x0F two times (As confirmed by the oscilloscope). The transfer function incorrectly returns 0x0E 0x0F

My Code:

#![no_std]
#![no_main]

//Generical Must Use Stuff
extern crate panic_semihosting;
use cortex_m_semihosting::hprintln;
use cortex_m_rt::entry;
use stm32l0xx_hal::{pac, prelude::*, rcc::Config};

// SPI Stuff
use stm32l0xx_hal::spi::{Polarity,Mode,Phase};

#[entry]
fn main() -> ! {
    
    // Configure the clock.
    let dp = pac::Peripherals::take().unwrap();
    let mut rcc = dp.RCC.freeze(Config::hsi16());
    
    // Setup SPI.
    let gpioa = dp.GPIOA.split(&mut rcc);   
    let sck = gpioa.pa5;              
    let miso = gpioa.pa6;
    let mosi = gpioa.pa7;
    let mode = Mode{polarity:Polarity::IdleLow,phase:Phase::CaptureOnFirstTransition};
    let mut ss = gpioa.pa3.into_push_pull_output();
    ss.set_high().unwrap();
    let mut spi = dp
        .SPI1
        .spi((sck, miso, mosi), mode, 100.khz(), &mut rcc);

    // Buffer to be used
    let mut buffer: [u8; 2] = [0x3D; 2];
    
    //Transfer the 2 byte buffer
    ss.set_low().unwrap();
    let _result = spi.transfer(&mut buffer).unwrap();
    ss.set_high().unwrap();
    
    //Print the Buffer
    hprintln!("Buffer After Transfer: {},{}", buffer[0],buffer[1]).unwrap();

    loop{}
}

Code Output:

Buffer After Transfer: 14,15

Oscilloscope Output:

ZoomedIn

ZoomedOut

Things I've Tried:

  • Adjusting the clock from 100kHz - 2MHz
  • Switching Modes (Mode 0 is recommended by slave, but I've tried all 4)
  • Using a BME680 as the slave (Same behavior in MISO LSB)
  • Using a different STM32L031
  • Reading from the slave 10+ times is a row. With the example above, only the first read comes back incorrectly (0x0e).
@dzarda
Copy link

dzarda commented Feb 21, 2020

I think we may be operating the peripheral incorrectly. The manual states that specific bits in SPI_CR1 be adjusted only while not enabled (SPE = 0). For example:

obrazek

This is confirmed when inspecting SPI driver code from ChibiOS HAL:

  /* SPI setup and enable.*/
  spip->spi->CR1 &= ~SPI_CR1_SPE;
  spip->spi->CR1  = spip->config->cr1 | SPI_CR1_MSTR | SPI_CR1_SSM |
                    SPI_CR1_SSI;
  spip->spi->CR2  = spip->config->cr2 | SPI_CR2_SSOE | SPI_CR2_RXDMAEN |
                    SPI_CR2_TXDMAEN;
  spip->spi->CR1 |= SPI_CR1_SPE;

@dzarda
Copy link

dzarda commented Feb 22, 2020

What are you getting in _result?

@mcopela
Copy link
Author

mcopela commented Feb 24, 2020

What are you getting in _result?

The _result is the same as buffer. If I swap _result with buffer in the print statement I get the same output. Thanks for the help.

@mcopela
Copy link
Author

mcopela commented Feb 24, 2020

I think we may be operating the peripheral incorrectly. The manual states that specific bits in SPI_CR1 be adjusted only while not enabled (SPE = 0). For example:
...

I downloaded the crate locally and implemented the change; I set the settings first, then set SPE=1. It didn't seem to fix my problem. I'll keep messing with the settings.

Changes to STM32L0XX-HAL::spi


                    hprintln!("Changing CR1");
                    #[allow(unused)]
                    spi.cr1.write(|w| unsafe {
                        w.spe()
                            .clear_bit()
                    });
                    hprintln!("CR1: {}",spi.cr1.read().bits());

                    spi.cr1.write(|w| unsafe {
                        w.cpha()
                            .bit(mode.phase == Phase::CaptureOnSecondTransition)
                            .cpol()
                            .bit(mode.polarity == Polarity::IdleHigh)
                            .mstr()
                            .set_bit()
                            .br()
                            .bits(br)
                            .lsbfirst()
                            .clear_bit()
                            .ssm()
                            .set_bit()
                            .ssi()
                            .set_bit()
                            .rxonly()
                            .clear_bit()
                            .dff()
                            .clear_bit()
                            .bidimode()
                            .clear_bit()
                            .spe()
                            .clear_bit()
                    });
                    hprintln!("CR1: {}",spi.cr1.read().bits());

                    spi.cr1.write(|w| unsafe {
                        w.cpha()
                            .bit(mode.phase == Phase::CaptureOnSecondTransition)
                            .cpol()
                            .bit(mode.polarity == Polarity::IdleHigh)
                            .mstr()
                            .set_bit()
                            .br()
                            .bits(br)
                            .lsbfirst()
                            .clear_bit()
                            .ssm()
                            .set_bit()
                            .ssi()
                            .set_bit()
                            .rxonly()
                            .clear_bit()
                            .dff()
                            .clear_bit()
                            .bidimode()
                            .clear_bit()
                            .spe()
                            .set_bit()
                    });
                    hprintln!("CR1: {}",spi.cr1.read().bits());

Output

Changing CR1
CR1: 0
CR1: 820
CR1: 884
Buffer After Transfer: 14,15

@almusil
Copy link
Contributor

almusil commented Apr 17, 2020

Sounds to me like you are hitting HW bug. Take look at the errata section 2.6.2.

The problem is basically speed of the SCK pin. Unless your SCK pin connection has capacitance higher than 30 pF, setting the SCK pin speed as High or Very High should mitigate the issue. (It worked for me).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants