Skip to content
Snippets Groups Projects
Select Git revision
  • d17eff19cab87005f131958f9454a1ecad9ac8d9
  • master default protected
2 results

imu.rs

Blame
  • imu.rs 3.95 KiB
    //! Interfacing the LSM9DS1 3D accelerometer, gyroscope, and magnetometer
    //! using SPI3.
    //!
    //! Using the SparkFun LSM9DS1 breakout board, connect:
    //! PA_8 -> CS_AG            (Chip Select for accelerometer/gyro)
    //! PA_9 -> CS_M             (Chip Select for magnetometer)
    //! PB_3 -> SCL              (SPI clock)
    //! PB_4 -> SDO_M and SDO_AG (Combined SPI MISO)
    //! PB_5 -> SDA              (SPI MOSI)
    #![deny(unsafe_code)]
    #![deny(warnings)]
    #![feature(const_fn)]
    #![feature(proc_macro)]
    #![feature(lang_items)]
    #![no_std]
    
    extern crate cortex_m;
    extern crate cortex_m_rtfm as rtfm;
    #[macro_use]
    extern crate f4;
    extern crate heapless;
    extern crate stm32f40x;
    
    use cortex_m::peripheral::SystClkSource;
    use core::ops::Deref;
    use f4::lsm9ds1::{ImuSettings, Lsm9ds1};
    use f4::Serial;
    use f4::Spi;
    use f4::dma::{Buffer, Dma1Channel6};
    use f4::time::Hertz;
    use f4::clock;
    use rtfm::{app, Threshold};
    
    const BAUD_RATE: Hertz = Hertz(115_200);
    const FREQUENCY: u32 = 10;
    const MAX_TX_LEN: usize = 256;
    
    app! {
        device: f4::stm32f40x,
    
        resources: {
            static IMU_SETTINGS: ImuSettings = ImuSettings::new();
            static TX_BUFFER: Buffer<[u8; MAX_TX_LEN], Dma1Channel6> = Buffer::new([0; MAX_TX_LEN]);
        },
    
        tasks: {
            SYS_TICK: {
                path: sys_tick,
                priority: 1,
                resources: [TX_BUFFER, IMU_SETTINGS, DMA1, USART2, SPI3, GPIOA],
            },
            DMA1_STREAM6: {
                path: tx_done,
                priority: 2,
                resources: [TX_BUFFER, DMA1],
            },
        },
    }
    
    fn sys_tick(t: &mut Threshold, mut r: SYS_TICK::Resources) {
        let spi = Spi(&**r.SPI3);
        let imu = Lsm9ds1(&**r.SPI3);
        let g = imu.read_gyro(&spi, r.GPIOA, &r.IMU_SETTINGS);
        let a = imu.read_acc(&spi, r.GPIOA, &r.IMU_SETTINGS);
        let m = imu.read_mag(&spi, r.GPIOA, &r.IMU_SETTINGS);
    
        uprint!(
            t,
            r.USART2,
            r.DMA1,
            r.TX_BUFFER,
            "a=({0: <11}, {1: <11}, {2: <11}), g=({3: <11}, {4: <11}, {5: <11}), m=({6: <11}, {7: <11}, {8: <11})\r\n",
            a.x,a.y,a.z,g.x,g.y,g.z,m.x,m.y,m.z
        );
    }
    
    fn init(p: init::Peripherals, r: init::Resources) {
        let clk = clock::set_84_mhz(&p.RCC, &p.FLASH);
        p.SYST.set_clock_source(SystClkSource::Core);
        p.SYST.set_reload(clk / FREQUENCY);
        p.SYST.enable_interrupt();
        p.SYST.enable_counter();
    
        // Start the serial port
        let serial = Serial(p.USART2);
        serial.init(BAUD_RATE.invert(), Some(p.DMA1), p.GPIOA, p.RCC);
    
        // Setup CS pins
        {
            // Power on GPIOA
            p.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
            // Set PA_8 and PA_9 as outputs
            p.GPIOA
                .moder
                .modify(|_, w| w.moder8().bits(1).moder9().bits(1));
            // Highest output speed
            p.GPIOA
                .ospeedr
                .modify(|_, w| w.ospeedr8().bits(3).ospeedr9().bits(3));
            // Default to high (CS disabled)
            p.GPIOA
                .odr
                .modify(|_, w| w.odr8().bit(true).odr9().bit(true));
        }
    
        // Init the SPI peripheral
        let spi = Spi(p.SPI3);
        spi.init(p.GPIOA, p.GPIOB, p.RCC);
    
        // For the LSM9DS1, the second clock transition is
        // the first data capture edge
        // RM0368 20.5.1
        p.SPI3.cr1.modify(|_, w| w.cpha().set_bit());
        spi.enable();
    
        let imu = Lsm9ds1(p.SPI3);
        imu.init_gyro(&spi, &p.GPIOA, &r.IMU_SETTINGS);
        imu.init_acc(&spi, &p.GPIOA, &r.IMU_SETTINGS);
        imu.init_mag(&spi, &p.GPIOA, &r.IMU_SETTINGS);
    }
    
    // Interrupt for serial transmit DMA
    fn tx_done(t: &mut Threshold, r: DMA1_STREAM6::Resources) {
        use rtfm::Resource;
        // We need to unlock the DMA to use it again in the future
        r.TX_BUFFER.claim(t, |tx, t| {
            r.DMA1.claim(t, |dma, _| tx.release(dma).unwrap());
        });
        // Clear the transmit buffer so we do not retransmit old stuff
        r.TX_BUFFER.claim_mut(t, |tx, _| {
            let array = &**tx.deref();
            array.borrow_mut()[..MAX_TX_LEN].clone_from_slice(&[0; MAX_TX_LEN]);
        });
    }
    
    fn idle() -> ! {
        loop {
            rtfm::wfi();
        }
    }