l3gd20 陀螺仪在 stm32f3discovery 上发回重复字节

Posted

技术标签:

【中文标题】l3gd20 陀螺仪在 stm32f3discovery 上发回重复字节【英文标题】:l3gd20 gyroscope sending back repeated bytes on stm32f3discovery 【发布时间】:2020-10-02 12:35:05 【问题描述】:

我正在研究 stm32f3discovery 并试图从板上的 l3gd20 陀螺仪读取数据。当我尝试从 OUT_X_L 到 OUT_Z_H 连续读取 6 个字节(这是用于从陀螺仪读取读数的所有数据)时,发送的前三个字节与发送的最后三个字节相同。

当我尝试单独读取每个寄存器时,所有字节都相同,我在示波器上检查过,寄存器在 MOSI 线上发生变化,但响应是 6 个重复字节。

WHO_AM_I 和 OUT_TEMP 寄存器都工作得很好,所以我知道实际的 SPI 不是问题。

这是任何适当的代码,任何帮助或正确方向的指示将不胜感激,谢谢。

Main.rs

#![no_std]
#![no_main]

extern crate panic_itm; // logs messages over ITM; requires ITM support

use cortex_m::asm, iprintln, iprint, Peripherals as core_peripherals;
use cortex_m_rt::entry;
use cortex_m_semihosting::debug, hprintln;
use stm32f3::stm32f303;

mod my_api;
mod sensor;


#[entry]
fn main() -> ! 
    let periph = stm32f303::Peripherals::take().unwrap();
    let mut core_p = core_peripherals::take().unwrap();

    let itm = &mut core_p.ITM.stim[0];


    let gpioa = periph.GPIOA;
    let gpioe = periph.GPIOE;
    let rcc = periph.RCC
    let flash = periph.FLASH;
    let spi1 = periph.SPI1;

    set_to_72MHz(&rcc, &flash);

    let spi = my_api::spi_mod::spi_func::new(&rcc, &gpioa, &gpioe, &spi1);

    let mut gyro = sensor::Gyro::gyro::new(&spi, &spi1).init(&spi, &spi1, &gpioe);

    loop 

        iprintln!(itm, ":?", gyro.read_data(&spi, &spi1, &gpioe));
    


fn set_to_72MHz(rcc: &stm32f3::stm32f303::RCC, flash: &stm32f3::stm32f303::FLASH)
    rcc.cr.modify(|_,w| w.hseon().set_bit()); //turns on the external oscillator
    while rcc.cr.read().hserdy().bit_is_clear() //wait for it to be ready
    flash.acr.modify(|_,w| 
        w.prftbe().set_bit(); //turn on prefetch
        unsafew.latency().bits(0b010) //set latency for 72MHz
    ); 

    rcc.cfgr.modify(|_,w| 
        w.pllxtpre().clear_bit();
        unsafew.pllsrc().bits(0b10);
        w.pllmul().bits(0b0111);
        unsafew.hpre().bits(0b0000);
        w.ppre1().bits(0b100);
        w.ppre2().bits(0b000)
    );

    rcc.cr.modify(|_,w| w.pllon().set_bit());
    while rcc.cr.read().pllrdy().bit_is_clear()

    rcc.cfgr.modify(|_,w| unsafew.sw().bits(0b10));
    while rcc.cfgr.read().sws().bits() != 0b10

my_api.rs

    pub mod spi_mod
    pub struct spi_func

    impl spi_func
        pub fn new(rcc: &stm32f3::stm32f303::RCC, gpioa: &stm32f3::stm32f303::GPIOA, gpioe: &stm32f3::stm32f303::GPIOE, spi: &stm32f3::stm32f303::SPI1) -> Self 
            rcc.apb2enr.modify(|_,w| w.spi1en().set_bit()); //enable spi clock

            rcc.ahbenr.modify(|_,w| w.iopaen().set_bit()); // enable gpio clocks
            rcc.ahbenr.modify(|_,w| w.iopeen().set_bit());

            gpioe.moder.modify(|_,w| w.moder3().bits(0b01)); //CS pin
            gpioe.otyper.modify(|_,w| w.ot3().clear_bit());
            gpioe.odr.modify(|_,w| w.odr3().set_bit()); //bring pe3 high to disable gyro com

            // PA5 -> SCL  // PA6 -> MISO  // PA7 -> MOSI
            gpioa.moder.modify(|_,w| 
                w.moder5().bits(0b10); // output type
                w.moder6().bits(0b10);
                w.moder7().bits(0b10));

            gpioa.otyper.modify(|_,w| 
                w.ot5().clear_bit();// push pull type
                w.ot6().clear_bit();
                w.ot7().clear_bit());

            gpioa.ospeedr.modify(|_,w| 
                w.ospeedr5().bits(0b11);// fast mode
                w.ospeedr6().bits(0b11);
                w.ospeedr7().bits(0b11));

            gpioa.afrl.modify(|_,w| 
                w.afrl5().bits(0b0101);//Alternate function 5
                w.afrl6().bits(0b0101);
                w.afrl7().bits(0b0101)
            );

            spi.cr1.modify(|_,w| 
                w.bidimode().clear_bit(); //bidirectional mode
                w.ssm().set_bit(); // hardware slave management disabled
                w.ssi().set_bit(); // slave not selected    -------------------------------
                w.br().bits(0b011); // bring rate from 72MHz to 72/16MHz = 4.5MHz as gyro cant go above 10MHz
                w.mstr().set_bit(); // set to master mode
                w.cpol().set_bit(); // set to mode 3 to work for the l3gd20
                w.cpha().set_bit()
            );

            spi.cr2.modify(|_,w| 
                //unsafew.ds().bits(0b0111); // data size = 8 bits
                w.errie().clear_bit();
                w.txeie().set_bit(); //enable interupt flags   
                w.rxneie().set_bit();
                w.ssoe().clear_bit() //set to single master mode
            );

            spi.cr1.modify(|_,w| w.spe().set_bit()); // enable spi

            spi_func

        

        fn check_faults(&self, spi1: &stm32f3::stm32f303::SPI1) -> bool 
            if spi1.sr.read().ovr().bit_is_set() //checks through all the flags
                false
            else if spi1.sr.read().modf().bit_is_set()
                false
            else if spi1.sr.read().crcerr().bit_is_set()
                false
            else if spi1.sr.read().udr().bit_is_set()
                false
             else 
                true
            
        

        pub fn write(&self, spi1: &stm32f3::stm32f303::SPI1, data: u16) 
            if self.check_faults(&spi1)
                spi1.dr.modify(|_,w| w.dr().bits(data)); //write to the dr register
                while spi1.sr.read().bsy().bit_is_set()
            
        

        pub fn read(&self, spi1: &stm32f3::stm32f303::SPI1) -> u8 
            if self.check_faults(&spi1)
                while spi1.sr.read().bsy().bit_is_set()
                return (spi1.dr.read().dr().bits() >> 8) as u8 //read from the dr register
            
            0

        

        pub fn write_data(&self, spi1: &stm32f3::stm32f303::SPI1, reg_address: u8, data: u8) 
            let total_data: u16 = ((data as u16) << 8) + (reg_address as u16);
            self.write(&spi1, total_data);
        

        pub fn read_register(&self, spi1: &stm32f3::stm32f303::SPI1, reg_address: u8) -> u8
            self.write(&spi1, (reg_address | 0x80) as u16); //set the bit to read mode and send
            self.read(&spi1) //read the result
        

        pub fn read_multiple_register(&self, spi1: &stm32f3::stm32f303::SPI1, reg_address: u8, rx_data: &mut [u8])
            self.write(&spi1, (reg_address | 0x80 | 0x40) as u16);
            for d in rx_data.iter_mut()
                self.write(&spi1, 0x00);
                *d = self.read(&spi1);
            

        

    

senor.rs

    pub mod Gyro
    pub use crate::my_api::spi_mod;
    const WHO_AM_I: u8 = 0x0F;
    const CTRL_REG1: u8 = 0x20;
    const CTRL_REG4: u8 = 0x23;
    const OUT_TEMP: u8 = 0x26;
    const OUT_X_L: u8 = 0x28;
    const OUT_X_H: u8 = 0x29;
    const OUT_Y_L: u8 = 0x2A;
    const OUT_Y_H: u8 = 0x2B;
    const OUT_Z_L: u8 = 0x2C;
    const OUT_Z_H: u8 = 0x2D;

    pub struct gyro
        pub x: i16,
        pub y: i16,
        pub z: i16,
        offset_x: i32,
        offset_y: i32,
        offset_z: i32,
        pub temp: i8
    

    impl gyro
        pub fn new(my_spi_mod: &spi_mod::spi_func, spi1: &stm32f3::stm32f303::SPI1) -> Self 
            gyro
                x: 0,
                y: 0,
                z: 0,
                offset_x: 0,
                offset_y: 0,
                offset_z: 0,
                temp: 0,
            
        

        pub fn init(self, spi: &spi_mod::spi_func, spi1: &stm32f3::stm32f303::SPI1, gpioe: &stm32f3::stm32f303::GPIOE) -> Self
            self.cs_low(&gpioe);
            spi.write_data(&spi1, CTRL_REG1, 0x3F); //power on the gyro 
            self.cs_high(&gpioe);

            self.cs_low(&gpioe);
            spi.write_data(&spi1, CTRL_REG4, 0x10); //power on the gyro 
            self.cs_high(&gpioe);

            self
        

        pub fn who_am_i(&self, spi: &spi_mod::spi_func, spi1: &stm32f3::stm32f303::SPI1, gpioe: &stm32f3::stm32f303::GPIOE) -> u8 
            self.cs_low(&gpioe);
            let data = spi.read_register(&spi1, WHO_AM_I);
            self.cs_high(&gpioe);
            data
        

        pub fn read_temp(&mut self, spi: &spi_mod::spi_func, spi1: &stm32f3::stm32f303::SPI1, gpioe: &stm32f3::stm32f303::GPIOE) 
            self.cs_low(&gpioe);
            self.temp = spi.read_register(&spi1, OUT_TEMP) as i8;
            self.cs_high(&gpioe);

        


        pub fn read_data(&mut self, spi: &spi_mod::spi_func, spi1: &stm32f3::stm32f303::SPI1, gpioe: &stm32f3::stm32f303::GPIOE) -> [u8;6]
            let mut data: [u8;6] = [0,0,0,0,0,0];

            self.cs_low(&gpioe);
            spi.read_multiple_register(&spi1, OUT_X_L, &mut data);

            // data[0] = spi.read_register(&spi1, OUT_X_L);
            // data[1] = spi.read_register(&spi1, OUT_X_H);

            // data[2] = spi.read_register(&spi1, OUT_Y_L);
            // data[3] = spi.read_register(&spi1, OUT_Y_H);

            // data[4] = spi.read_register(&spi1, OUT_Z_L);
            // data[5] = spi.read_register(&spi1, OUT_Z_H);

            self.cs_high(&gpioe);

            self.x = ((data[0] as u16) + ((data[1] as u16) << 8)) as i16;
            self.y = ((data[2] as u16) + ((data[3] as u16) << 8)) as i16;
            self.z = ((data[4] as u16) + ((data[5] as u16) << 8)) as i16;

            data            

        

        fn cs_low(&self, gpioe: &stm32f3::stm32f303::GPIOE)
            gpioe.odr.modify(|_,w| w.odr3().clear_bit());
        

        fn cs_high(&self, gpioe: &stm32f3::stm32f303::GPIOE)
            gpioe.odr.modify(|_,w| w.odr3().set_bit());
        

    

这是使用时的结果 sensor.rs -> read_data() -> spi.read_multiple_register(&spi1, OUT_X_L, &mut 数据); return data from board with repeated 3 bytes

当我使用注释掉的位时,这就是我得到的 return data when all bytes are the same

【问题讨论】:

我不知道 Rust。我对您的 write() 功能感到怀疑/好奇。 write() 传输多少字节,一个,两个或其中一个?似乎它需要在第一次从read_multiple_register() 调用时传输两个字节,然后在后续调用中传输一个字节。真的会这样吗? ...或等待。我认为write()write_register()read_register() 调用时需要传输两个字节。但是write()read_multiple_register()调用时需要传输一个字节。也许你不应该在来自read_multiple_register() 的电话中使用那个as u16。我不知道 Rust。 感谢您的浏览。我想你可能会在那里做一些事情,因为这就是 write_register 函数所发生的事情。当我将数据左移 8 位并再次用 0、1 或数据填充其余字节时,您建议第二个字节是什么,它只是给了我重复的数字。当我在前面也只有一个 0 字节时也是如此。 【参考方案1】:

您是否尝试过在 0x27H 使用 STATUS_REG? Section 3.2 Page 10

【讨论】:

谢谢,我不介意数据是否被覆盖,我觉得这不应该意味着它正在给出它的结果。

以上是关于l3gd20 陀螺仪在 stm32f3discovery 上发回重复字节的主要内容,如果未能解决你的问题,请参考以下文章

如何将 stm32f3discovery API 传递给函数?

STM32 SPI 与 HAL 通信

STM32 SPI数据打包

如何将带有 SPL 的 STM32F3 代码移植到 STM32F7

STM32F3 DISCOVERY USART 不工作

stm32f3 'USER USB' 未检测到