diff --git a/examples/imu.rs b/examples/imu.rs
new file mode 100644
index 0000000000000000000000000000000000000000..78bc15d99144918ae2aa02b45ab1af5b44f0a8a3
--- /dev/null
+++ b/examples/imu.rs
@@ -0,0 +1,140 @@
+//! 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();
+    }
+}
diff --git a/examples/spi1.rs b/examples/spi1.rs
index ba39e88cf64d44ca2ffc28cc546a4184ec5927ef..db24b7b50f9155b2e0e65696ff0c71991b3de8ac 100644
--- a/examples/spi1.rs
+++ b/examples/spi1.rs
@@ -82,11 +82,7 @@ fn disable_ag(gpioa: &mut GPIOA) {
 fn send_receive(spi: &f4::Spi<f4::stm32f40x::SPI3>, addr: u8) -> u8 {
     // Send and receive using the hal crate
     while spi.send(addr).is_err() {}
-    loop {
-        if let Ok(_) = spi.read() {
-            break;
-        }
-    }
+    while spi.read().is_err() {}
     while spi.send(0).is_err() {}
     loop {
         if let Ok(byte) = spi.read() {
diff --git a/src/led.rs b/src/led.rs
index bca68e662ee293ce0ca1672b989afcd22e681c2b..71be9a56ab9dd2e6f049e31319a43e5723ac56dd 100644
--- a/src/led.rs
+++ b/src/led.rs
@@ -31,4 +31,9 @@ impl PA5 {
             (*GPIOA.get()).odr.modify(|_, w| w.odr5().bit(false));
         }
     }
+
+    /// True if LED is ON, false otherwise.
+    pub fn is_on(&self) -> bool {
+        unsafe { (*GPIOA.get()).odr.read().odr5().bit_is_set() }
+    }
 }
diff --git a/src/lib.rs b/src/lib.rs
index 96a1ca9e362522fdfd2b39ebda537f588ae75d14..8974f0aef41ae62c2243c86cd5cfa715f8cf945d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -45,8 +45,9 @@ pub mod pwm;
 pub mod capture;
 pub mod clock;
 pub mod spi;
-
+pub mod lsm9ds1;
 pub mod frequency;
+
 use frequency::*;
 
 pub use hal::prelude;
@@ -56,6 +57,7 @@ pub use timer::{Channel, Timer};
 pub use pwm::Pwm;
 pub use capture::Capture;
 pub use spi::Spi;
+pub use lsm9ds1::{ImuSettings, Lsm9ds1, Vector3};
 
 /// println over semihosting
 #[macro_export]
diff --git a/src/lsm9ds1.rs b/src/lsm9ds1.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ae4aebe7bdcbd9d8fe7d8e69ebf440a54719df04
--- /dev/null
+++ b/src/lsm9ds1.rs
@@ -0,0 +1,695 @@
+//! Interfacing the LSM9DS1 3D accelerometer, gyroscope, and magnetometer
+//! using SPI.
+
+extern crate stm32f40x;
+use stm32f40x::{SPI1, SPI2, SPI3, GPIOA};
+use spi::Spi;
+use prelude::*;
+
+/////////////////////////////////////////
+// Lsm9ds1 Accel/Gyro (XL/G) Registers //
+/////////////////////////////////////////
+const ACT_THS: u8 = 0x04;
+const ACT_DUR: u8 = 0x05;
+const INT_GEN_CFG_XL: u8 = 0x06;
+const INT_GEN_THS_X_XL: u8 = 0x07;
+const INT_GEN_THS_Y_XL: u8 = 0x08;
+const INT_GEN_THS_Z_XL: u8 = 0x09;
+const INT_GEN_DUR_XL: u8 = 0x0A;
+const REFERENCE_G: u8 = 0x0B;
+const INT1_CTRL: u8 = 0x0C;
+const INT2_CTRL: u8 = 0x0D;
+const WHO_AM_I_XG: u8 = 0x0F;
+const CTRL_REG1_G: u8 = 0x10;
+const CTRL_REG2_G: u8 = 0x11;
+const CTRL_REG3_G: u8 = 0x12;
+const ORIENT_CFG_G: u8 = 0x13;
+const INT_GEN_SRC_G: u8 = 0x14;
+const OUT_TEMP_L: u8 = 0x15;
+const OUT_TEMP_H: u8 = 0x16;
+const STATUS_REG_0: u8 = 0x17;
+const OUT_X_L_G: u8 = 0x18;
+const OUT_X_H_G: u8 = 0x19;
+const OUT_Y_L_G: u8 = 0x1A;
+const OUT_Y_H_G: u8 = 0x1B;
+const OUT_Z_L_G: u8 = 0x1C;
+const OUT_Z_H_G: u8 = 0x1D;
+const CTRL_REG4: u8 = 0x1E;
+const CTRL_REG5_XL: u8 = 0x1F;
+const CTRL_REG6_XL: u8 = 0x20;
+const CTRL_REG7_XL: u8 = 0x21;
+const CTRL_REG8: u8 = 0x22;
+const CTRL_REG9: u8 = 0x23;
+const CTRL_REG10: u8 = 0x24;
+const INT_GEN_SRC_XL: u8 = 0x26;
+const STATUS_REG_1: u8 = 0x27;
+const OUT_X_L_XL: u8 = 0x28;
+const OUT_X_H_XL: u8 = 0x29;
+const OUT_Y_L_XL: u8 = 0x2A;
+const OUT_Y_H_XL: u8 = 0x2B;
+const OUT_Z_L_XL: u8 = 0x2C;
+const OUT_Z_H_XL: u8 = 0x2D;
+const FIFO_CTRL: u8 = 0x2E;
+const FIFO_SRC: u8 = 0x2F;
+const INT_GEN_CFG_G: u8 = 0x30;
+const INT_GEN_THS_XH_G: u8 = 0x31;
+const INT_GEN_THS_XL_G: u8 = 0x32;
+const INT_GEN_THS_YH_G: u8 = 0x33;
+const INT_GEN_THS_YL_G: u8 = 0x34;
+const INT_GEN_THS_ZH_G: u8 = 0x35;
+const INT_GEN_THS_ZL_G: u8 = 0x36;
+const INT_GEN_DUR_G: u8 = 0x37;
+
+///////////////////////////////
+// Lsm9ds1 Magneto Registers //
+///////////////////////////////
+const OFFSET_X_REG_L_M: u8 = 0x05;
+const OFFSET_X_REG_H_M: u8 = 0x06;
+const OFFSET_Y_REG_L_M: u8 = 0x07;
+const OFFSET_Y_REG_H_M: u8 = 0x08;
+const OFFSET_Z_REG_L_M: u8 = 0x09;
+const OFFSET_Z_REG_H_M: u8 = 0x0A;
+const WHO_AM_I_M: u8 = 0x0F;
+const CTRL_REG1_M: u8 = 0x20;
+const CTRL_REG2_M: u8 = 0x21;
+const CTRL_REG3_M: u8 = 0x22;
+const CTRL_REG4_M: u8 = 0x23;
+const CTRL_REG5_M: u8 = 0x24;
+const STATUS_REG_M: u8 = 0x27;
+const OUT_X_L_M: u8 = 0x28;
+const OUT_X_H_M: u8 = 0x29;
+const OUT_Y_L_M: u8 = 0x2A;
+const OUT_Y_H_M: u8 = 0x2B;
+const OUT_Z_L_M: u8 = 0x2C;
+const OUT_Z_H_M: u8 = 0x2D;
+const INT_CFG_M: u8 = 0x30;
+const INT_SRC_M: u8 = 0x31;
+const INT_THS_L_M: u8 = 0x32;
+const INT_THS_H_M: u8 = 0x33;
+
+////////////////////////////////
+// Lsm9ds1 WHO_AM_I Responses //
+////////////////////////////////
+const WHO_AM_I_AG_RSP: u8 = 0x68;
+const WHO_AM_I_M_RSP: u8 = 0x3D;
+
+/// Accelerometer settings
+pub struct AccelSettings {
+    ///
+    pub enabled: bool,
+    /// accel scale can be 2, 4, 8, or 16
+    pub scale: u16,
+    /// accel sample rate can be 1-6
+    /// 1 = 10 Hz    4 = 238 Hz
+    /// 2 = 50 Hz    5 = 476 Hz
+    /// 3 = 119 Hz   6 = 952 Hz
+    pub sample_rate: u8,
+    ///
+    pub enable_x: bool,
+    ///
+    pub enable_y: bool,
+    ///
+    pub enable_z: bool,
+    /// Accel cutoff freqeuncy can be any value between -1 - 3.
+    /// -1 = bandwidth determined by sample rate
+    /// 0 = 408 Hz   2 = 105 Hz
+    /// 1 = 211 Hz   3 = 50 Hz
+    pub bandwidth: i8,
+    ///
+    pub high_res_enable: bool,
+    /// accelHighResBandwidth can be any value between 0-3
+    /// LP cutoff is set to a factor of sample rate
+    /// 0 = ODR/50    2 = ODR/9
+    /// 1 = ODR/100   3 = ODR/400
+    pub high_res_bandwidth: u8,
+}
+
+/// Gyroscope settings
+pub struct GyroSettings {
+    ///
+    pub enabled: bool,
+    /// gyro scale can be 245, 500, or 2000
+    pub scale: u16,
+    /// gyro sample rate: value between 1-6
+    /// 1 = 14.9    4 = 238
+    /// 2 = 59.5    5 = 476
+    /// 3 = 119     6 = 952
+    pub sample_rate: u8,
+    /// gyro cutoff frequency: value between 0-3
+    /// Actual value of cutoff frequency depends
+    /// on sample rate.
+    pub bandwidth: u8,
+    ///
+    pub low_power_enable: bool,
+    ///
+    pub hpf_enable: bool,
+    ///  Gyro HPF cutoff frequency: value between 0-9
+    /// Actual value depends on sample rate. Only applies
+    /// if gyroHPFEnable is true.
+    pub hpf_cutoff: u8,
+    ///
+    pub flip_x: bool,
+    ///
+    pub flip_y: bool,
+    ///
+    pub flip_z: bool,
+    ///
+    pub orientation: u8,
+    ///
+    pub enable_x: bool,
+    ///
+    pub enable_y: bool,
+    ///
+    pub enable_z: bool,
+    ///
+    pub latch_interrupt: bool,
+}
+
+/// Magnetometer settings
+pub struct MagSettings {
+    ///
+    pub enabled: bool,
+    /// mag scale can be 4, 8, 12, or 16
+    pub scale: u8,
+    ///mag data rate can be 0-7
+    /// 0 = 0.625 Hz  4 = 10 Hz
+    /// 1 = 1.25 Hz   5 = 20 Hz
+    /// 2 = 2.5 Hz    6 = 40 Hz
+    /// 3 = 5 Hz      7 = 80 Hz
+    pub sample_rate: u8,
+    ///
+    pub temp_compensation_enable: bool,
+    /// magPerformance can be any value between 0-3
+    /// 0 = Low power mode      2 = high performance
+    /// 1 = medium performance  3 = ultra-high performance
+    pub xy_performance: u8,
+    ///
+    pub z_performance: u8,
+    ///
+    pub low_power_enable: bool,
+    /// magOperatingMode can be 0-2
+    /// 0 = continuous conversion
+    /// 1 = single-conversion
+    /// 2 = power down
+    pub operating_mode: u8,
+}
+
+/// Settings for lsm9ds1
+pub struct ImuSettings {
+    ///
+    pub mag: MagSettings,
+    ///
+    pub accel: AccelSettings,
+    ///
+    pub gyro: GyroSettings,
+}
+
+/// Generic 3D vector
+pub struct Vector3<T> {
+    /// X axis value
+    pub x: T,
+    /// Y axis value
+    pub y: T,
+    /// Z axis value
+    pub z: T,
+}
+
+/// Default settings for lsm9ds1
+impl ImuSettings {
+    ///
+    pub const fn new() -> Self {
+        ImuSettings {
+            accel: AccelSettings {
+                enabled: true,
+                scale: 2,
+                sample_rate: 6,
+                enable_x: true,
+                enable_y: true,
+                enable_z: true,
+                bandwidth: -1,
+                high_res_enable: false,
+                high_res_bandwidth: 0,
+            },
+            gyro: GyroSettings {
+                enabled: true,
+                scale: 245,
+                sample_rate: 6,
+                bandwidth: 0,
+                low_power_enable: false,
+                hpf_enable: false,
+                hpf_cutoff: 0,
+                flip_x: false,
+                flip_y: false,
+                flip_z: false,
+                orientation: 0,
+                enable_x: true,
+                enable_y: true,
+                enable_z: true,
+                latch_interrupt: true,
+            },
+            mag: MagSettings {
+                enabled: true,
+                scale: 4,
+                sample_rate: 7,
+                temp_compensation_enable: false,
+                xy_performance: 3,
+                z_performance: 3,
+                low_power_enable: false,
+                operating_mode: 0,
+            },
+        }
+    }
+}
+
+const SENSITIVITY_ACCELEROMETER_2: f32 = 0.000061;
+const SENSITIVITY_ACCELEROMETER_4: f32 = 0.000122;
+const SENSITIVITY_ACCELEROMETER_8: f32 = 0.000244;
+const SENSITIVITY_ACCELEROMETER_16: f32 = 0.000732;
+const SENSITIVITY_GYROSCOPE_245: f32 = 0.00875;
+const SENSITIVITY_GYROSCOPE_500: f32 = 0.0175;
+const SENSITIVITY_GYROSCOPE_2000: f32 = 0.07;
+const SENSITIVITY_MAGNETOMETER_4: f32 = 0.00014;
+const SENSITIVITY_MAGNETOMETER_8: f32 = 0.00029;
+const SENSITIVITY_MAGNETOMETER_12: f32 = 0.00043;
+const SENSITIVITY_MAGNETOMETER_16: f32 = 0.00058;
+
+
+/// LSM9DS1 for SPI communication
+pub struct Lsm9ds1<'a, T>(pub &'a T)
+where
+    T: 'a;
+
+macro_rules! impl_Lsm9ds1 {
+    ($SPI:ident) => {
+        impl<'a> Lsm9ds1<'a, $SPI> {
+
+            fn enable_m(&self, gpioa: &GPIOA) {
+                gpioa.odr.modify(|_, w| w.odr9().bit(false));
+            }
+
+            fn disable_m(&self, gpioa: &GPIOA) {
+                gpioa.odr.modify(|_, w| w.odr9().bit(true));
+            }
+
+            fn enable_ag(&self, gpioa: &GPIOA) {
+                gpioa.odr.modify(|_, w| w.odr8().bit(false));
+            }
+
+            fn disable_ag(&self, gpioa: &GPIOA) {
+                gpioa.odr.modify(|_, w| w.odr8().bit(true));
+            }
+
+            fn write_bytes(&self, spi: &Spi<$SPI>, addr: u8, data: [u8; 128], length: u8) {
+                let mut x: u8 = 0;
+                while spi.send(addr).is_err() {}
+                while spi.read().is_err() {}
+                while x < length {
+                    while spi.send(data[x as usize]).is_err() {}
+                    while spi.read().is_err() {}
+                    x = x + 1;
+                }
+            }
+
+            fn read_bytes(&self, spi: &Spi<$SPI>, addr: u8, length: u8) -> [u8; 128] {
+                let mut response: [u8; 128] = [0; 128];
+                let mut x: u8 = 0;
+                while spi.send(addr).is_err() {}
+                while spi.read().is_err() {}
+                while x < length {
+                    while spi.send(0).is_err() {}
+                    loop {
+                        if let Ok(byte) = spi.read() {
+                            response[x as usize] = byte;
+                            break;
+                        }
+                    }
+                    x = x + 1;
+                }
+                response
+            }
+
+            fn ag_read_bytes(&self, spi: &Spi<$SPI>, gpioa: &GPIOA, addr: u8, length: u8) -> [u8; 128] {
+                let addr = 0x80 | (addr & 0x7F);
+                self.enable_ag(&gpioa);
+                let ans = self.read_bytes(spi, addr, length);
+                self.disable_ag(&gpioa);
+                ans
+            }
+
+            fn ag_read_byte(&self, spi: &Spi<$SPI>, gpioa: &GPIOA, addr: u8) -> u8 {
+                self.ag_read_bytes(spi,gpioa,addr,1)[0]
+            }
+
+            fn ag_write_bytes(&self, spi: &Spi<$SPI>, gpioa: &GPIOA, addr: u8, data: [u8; 128], length: u8) {
+                let addr = !0x80 & (addr & 0x7F);
+                self.enable_ag(&gpioa);
+                self.write_bytes(spi, addr, data, length);
+                self.disable_ag(&gpioa);
+            }
+
+            fn ag_write_byte(&self, spi: &Spi<$SPI>, gpioa: &GPIOA, addr: u8, data: u8) {
+                self.ag_write_bytes(spi, gpioa, addr, [data; 128], 1);
+            }
+
+            fn m_read_bytes(&self, spi: &Spi<$SPI>, gpioa: &GPIOA, addr: u8, length: u8) -> [u8; 128] {
+                let addr = 0x80 | 0x40 | (addr & 0x3F);
+                self.enable_m(&gpioa);
+                let ans = self.read_bytes(spi, addr, length);
+                self.disable_m(&gpioa);
+                ans
+            }
+
+            fn m_read_byte(&self, spi: &Spi<$SPI>, gpioa: &GPIOA, addr: u8) -> u8 {
+                self.m_read_bytes(spi,gpioa,addr,1)[0]
+            }
+
+            fn m_write_bytes(&self, spi: &Spi<$SPI>, gpioa: &GPIOA, addr: u8, data: [u8; 128], length: u8) {
+                let addr = !0x80 & (0x40 | addr & 0x7F);
+                self.enable_m(&gpioa);
+                self.write_bytes(spi, addr, data, length);
+                self.disable_m(&gpioa);
+            }
+
+            fn m_write_byte(&self, spi: &Spi<$SPI>, gpioa: &GPIOA, addr: u8, data: u8) {
+                self.m_write_bytes(spi, gpioa, addr, [data; 128], 1);
+            }
+
+            /// Initalizes the gyroscope with given settings
+            pub fn init_gyro(&self, spi: &Spi<$SPI>, gpioa: &GPIOA, settings: &ImuSettings) {
+                // Check that we can read from acc/gyro
+                assert_eq!(WHO_AM_I_AG_RSP, self.ag_read_byte(&spi, &gpioa, WHO_AM_I_XG));
+
+                let mut temp: u8 = 0;
+                // CTRL_REG1_G (Default value: 0x00)
+                // [ODR_G2][ODR_G1][ODR_G0][FS_G1][FS_G0][0][BW_G1][BW_G0]
+                // ODR_G[2:0] - Output data rate selection
+                // FS_G[1:0] - Gyroscope full-scale selection
+                // BW_G[1:0] - Gyroscope bandwidth selection
+
+                // To disable gyro, set sample rate bits to 0. We'll only set sample
+                // rate if the gyro is enabled.
+                if settings.gyro.enabled {
+                    temp = (settings.gyro.sample_rate & 0x07) << 5;
+                }
+                temp |= match settings.gyro.scale {
+                    500 => (0x1 << 3),
+                    2000 => (0x3 << 3),
+                    _ => 0, // Otherwise we'll set it to 245 dps (0x0 << 4)
+                };
+                temp |= settings.gyro.bandwidth & 0x3;
+                self.ag_write_byte(&spi, &gpioa, CTRL_REG1_G, temp);
+
+                // Check that we can both read and write
+                assert_eq!(temp, self.ag_read_byte(&spi, &gpioa, CTRL_REG1_G));
+
+                // CTRL_REG2_G (Default value: 0x00)
+                // [0][0][0][0][INT_SEL1][INT_SEL0][OUT_SEL1][OUT_SEL0]
+                // INT_SEL[1:0] - INT selection configuration
+                // OUT_SEL[1:0] - Out selection configuration
+                self.ag_write_byte(&spi, &gpioa, CTRL_REG2_G, 0x00);
+                assert_eq!(0x00, self.ag_read_byte(&spi, &gpioa, CTRL_REG2_G));
+
+                // CTRL_REG3_G (Default value: 0x00)
+                // [LP_mode][HP_EN][0][0][HPCF3_G][HPCF2_G][HPCF1_G][HPCF0_G]
+                // LP_mode - Low-power mode enable (0: disabled, 1: enabled)
+                // HP_EN - HPF enable (0:disabled, 1: enabled)
+                // HPCF_G[3:0] - HPF cutoff frequency
+                temp = 0;
+                if settings.gyro.low_power_enable {
+                    temp = 1 << 7;
+                }
+                if settings.gyro.hpf_enable {
+                    temp |= (1 << 6) | (settings.gyro.hpf_cutoff & 0x0F);
+                }
+                self.ag_write_byte(&spi, &gpioa, CTRL_REG3_G, temp);
+                assert_eq!(temp, self.ag_read_byte(&spi, &gpioa, CTRL_REG3_G));
+
+                // CTRL_REG4 (Default value: 0x38)
+                // [0][0][Zen_G][Yen_G][Xen_G][0][LIR_XL1][4D_XL1]
+                // Zen_G - Z-axis output enable (0:disable, 1:enable)
+                // Yen_G - Y-axis output enable (0:disable, 1:enable)
+                // Xen_G - X-axis output enable (0:disable, 1:enable)
+                // LIR_XL1 - Latched interrupt (0:not latched, 1:latched)
+                // 4D_XL1 - 4D option on interrupt (0:6D used, 1:4D used)
+                temp = 0;
+                if settings.gyro.enable_z {
+                    temp |= 1 << 5
+                }
+                if settings.gyro.enable_y {
+                    temp |= 1 << 4
+                }
+                if settings.gyro.enable_x {
+                    temp |= 1 << 3
+                }
+                if settings.gyro.latch_interrupt {
+                    temp |= 1 << 1
+                }
+                self.ag_write_byte(&spi, &gpioa, CTRL_REG4, temp);
+                assert_eq!(temp, self.ag_read_byte(&spi, &gpioa, CTRL_REG4));
+
+                // ORIENT_CFG_G (Default value: 0x00)
+                // [0][0][SignX_G][SignY_G][SignZ_G][Orient_2][Orient_1][Orient_0]
+                // SignX_G - Pitch axis (X) angular rate sign (0: positive, 1: negative)
+                // Orient [2:0] - Directional user orientation selection
+                temp = 0;
+                if settings.gyro.flip_x {
+                    temp |= 1 << 5
+                }
+                if settings.gyro.flip_y {
+                    temp |= 1 << 4
+                }
+                if settings.gyro.flip_z {
+                    temp |= 1 << 3
+                }
+                self.ag_write_byte(&spi, &gpioa, ORIENT_CFG_G, temp);
+                assert_eq!(temp, self.ag_read_byte(&spi, &gpioa, ORIENT_CFG_G));
+            }
+
+            /// Reads the raw values from the gyro X/Y/Z axis
+            pub fn read_gyro_raw(&self,spi: &Spi<$SPI>, gpioa: &GPIOA) -> Vector3<i16> {
+                // Read 6 bytes, beginning at OUT_X_L_G
+                let temp = self.ag_read_bytes(&spi, &gpioa, OUT_X_L_G, 6);
+                Vector3 {
+                    x:(((temp[1] as u16) << 8) | temp[0] as u16) as i16,
+                    y:(((temp[3] as u16) << 8) | temp[2] as u16) as i16,
+                    z:(((temp[5] as u16) << 8) | temp[4] as u16) as i16,
+                }
+            }
+
+            /// Reads the values from the gyro X/Y/Z axis in DPS
+            pub fn read_gyro(&self,spi: &Spi<$SPI>, gpioa: &GPIOA, settings: &ImuSettings) -> Vector3<f32> {
+                let g_res = match settings.gyro.scale {
+                    245 => SENSITIVITY_GYROSCOPE_245,
+                    500 => SENSITIVITY_GYROSCOPE_500,
+                    2000 => SENSITIVITY_GYROSCOPE_2000,
+                    _ => panic!("Invalid sensitivity")
+                };
+                let g_raw = self.read_gyro_raw(&spi, &gpioa);
+                Vector3 {
+                    x:g_raw.x as f32 * g_res,
+                    y:g_raw.y as f32 * g_res,
+                    z:g_raw.z as f32 * g_res,
+                }
+            }
+
+            /// Initalizes the accelerometer with given settings
+            pub fn init_acc(&self, spi: &Spi<$SPI>, gpioa: &GPIOA, settings: &ImuSettings) {
+                // Check that we can read from acc/gyro
+                assert_eq!(WHO_AM_I_AG_RSP, self.ag_read_byte(&spi, &gpioa, WHO_AM_I_XG));
+
+                let mut temp: u8 = 0;
+
+                //	CTRL_REG5_XL (0x1F) (Default value: 0x38)
+                //	[DEC_1][DEC_0][Zen_XL][Yen_XL][Zen_XL][0][0][0]
+                //	DEC[0:1] - Decimation of accel data on OUT REG and FIFO.
+                //		00: None, 01: 2 samples, 10: 4 samples 11: 8 samples
+                //	Zen_XL - Z-axis output enabled
+                //	Yen_XL - Y-axis output enabled
+                //	Xen_XL - X-axis output enabled
+                if settings.accel.enable_z {temp |= 1<<5};
+                if settings.accel.enable_y {temp |= 1<<4};
+                if settings.accel.enable_x {temp |= 1<<3};
+
+                self.ag_write_byte(&spi, &gpioa, CTRL_REG5_XL, temp);
+                assert_eq!(temp, self.ag_read_byte(&spi, &gpioa, CTRL_REG5_XL));
+
+                // CTRL_REG6_XL (0x20) (Default value: 0x00)
+                // [ODR_XL2][ODR_XL1][ODR_XL0][FS1_XL][FS0_XL][BW_SCAL_ODR][BW_XL1][BW_XL0]
+                // ODR_XL[2:0] - Output data rate & power mode selection
+                // FS_XL[1:0] - Full-scale selection
+                // BW_SCAL_ODR - Bandwidth selection
+                // BW_XL[1:0] - Anti-aliasing filter bandwidth selection
+                temp = 0;
+                // To disable the accel, set the sampleRate bits to 0.
+                if settings.accel.enabled
+                {
+                    temp |= (settings.accel.sample_rate & 0x07) << 5;
+                }
+
+                temp |= match settings.accel.scale {
+                    4 => (0x2 << 3),
+                    8 => (0x3 << 3),
+                    16 => (0x1 << 3),
+                    _ => 0, // Otherwise it'll be set to 2g (0x0 << 3)
+                };
+
+                if settings.accel.bandwidth >= 0 {
+                    temp |= 1<<2; // Set BW_SCAL_ODR
+                    temp |= settings.accel.bandwidth as u8 & 0x03;
+                }
+                self.ag_write_byte(&spi, &gpioa, CTRL_REG6_XL, temp);
+                assert_eq!(temp, self.ag_read_byte(&spi, &gpioa, CTRL_REG6_XL));
+
+                // CTRL_REG7_XL (0x21) (Default value: 0x00)
+                // [HR][DCF1][DCF0][0][0][FDS][0][HPIS1]
+                // HR - High resolution mode (0: disable, 1: enable)
+                // DCF[1:0] - Digital filter cutoff frequency
+                // FDS - Filtered data selection
+                // HPIS1 - HPF enabled for interrupt function
+                temp = 0;
+                if settings.accel.high_res_enable
+                {
+                    temp |= 1<<7; // Set HR bit
+                    temp |= (settings.accel.high_res_bandwidth & 0x3) << 5;
+                }
+                self.ag_write_byte(&spi, &gpioa, CTRL_REG7_XL, temp);
+                assert_eq!(temp, self.ag_read_byte(&spi, &gpioa, CTRL_REG7_XL));
+            }
+
+            /// Reads the raw values from the accelerometer X/Y/Z axis
+            pub fn read_acc_raw(&self,spi: &Spi<$SPI>, gpioa: &GPIOA) -> Vector3<i16> {
+                // Read 6 bytes, beginning at OUT_X_L_XL
+                let temp = self.ag_read_bytes(&spi, &gpioa, OUT_X_L_XL, 6);
+                Vector3 {
+                    x:(((temp[1] as u16) << 8) | temp[0] as u16) as i16,
+                    y:(((temp[3] as u16) << 8) | temp[2] as u16) as i16,
+                    z:(((temp[5] as u16) << 8) | temp[4] as u16) as i16,
+                }
+            }
+
+            /// Reads the values from the accelerometer X/Y/Z axis in g's
+            pub fn read_acc(&self,spi: &Spi<$SPI>, gpioa: &GPIOA, settings: &ImuSettings) -> Vector3<f32> {
+                let a_res = match settings.accel.scale {
+                    2 => SENSITIVITY_ACCELEROMETER_2,
+                    4=> SENSITIVITY_ACCELEROMETER_4,
+                    8=> SENSITIVITY_ACCELEROMETER_8,
+                    16=> SENSITIVITY_ACCELEROMETER_16,
+                    _ => panic!("Invalid sensitivity"),
+                };
+                let a_raw = self.read_acc_raw(&spi, &gpioa);
+                Vector3 {
+                    x:a_raw.x as f32 * a_res,
+                    y:a_raw.y as f32 * a_res,
+                    z:a_raw.z as f32 * a_res,
+                }
+            }
+
+            /// Initalizes the magnetometer with given settings
+            pub fn init_mag(&self, spi: &Spi<$SPI>, gpioa: &GPIOA, settings: &ImuSettings) -> bool {
+                // Check that we can read from acc/gyro
+                assert_eq!(WHO_AM_I_M_RSP, self.m_read_byte(&spi, &gpioa, WHO_AM_I_M));
+
+                let mut temp: u8 = 0;
+
+                // CTRL_REG1_M (Default value: 0x10)
+                // [TEMP_COMP][OM1][OM0][DO2][DO1][DO0][0][ST]
+                // TEMP_COMP - Temperature compensation
+                // OM[1:0] - X & Y axes op mode selection
+                //	00:low-power, 01:medium performance
+                //	10: high performance, 11:ultra-high performance
+                // DO[2:0] - Output data rate selection
+                // ST - Self-test enable
+                if settings.mag.temp_compensation_enable {temp |= 1<<7};
+                temp |= (settings.mag.xy_performance & 0x3) << 5;
+                temp |= (settings.mag.sample_rate & 0x7) << 2;
+                self.m_write_byte(&spi, &gpioa, CTRL_REG1_M, temp);
+                assert_eq!(temp, self.m_read_byte(&spi, &gpioa, CTRL_REG1_M));
+
+                // CTRL_REG2_M (Default value 0x00)
+                // [0][FS1][FS0][0][REBOOT][SOFT_RST][0][0]
+                // FS[1:0] - Full-scale configuration
+                // REBOOT - Reboot memory content (0:normal, 1:reboot)
+                // SOFT_RST - Reset config and user registers (0:default, 1:reset)
+                temp = 0;
+                temp |= match settings.mag.scale
+                {
+                 8 => 0x1 << 5,
+                12 => 0x2 << 5,
+                16 => 0x3 << 5,
+                _ => 0,
+                // Otherwise we'll default to 4 gauss (00)
+                };
+                self.m_write_byte(&spi, &gpioa, CTRL_REG2_M, temp); // +/-4Gauss
+                assert_eq!(temp, self.m_read_byte(&spi, &gpioa, CTRL_REG2_M));
+
+                // CTRL_REG3_M (Default value: 0x03)
+                // [I2C_DISABLE][0][LP][0][0][SIM][MD1][MD0]
+                // I2C_DISABLE - Disable I2C interace (0:enable, 1:disable)
+                // LP - Low-power mode cofiguration (1:enable)
+                // SIM - SPI mode selection (0:write-only, 1:read/write enable)
+                // MD[1:0] - Operating mode
+                //	00:continuous conversion, 01:single-conversion,
+                //  10,11: Power-down
+                temp = 0;
+                if settings.mag.low_power_enable {temp |= 1<<5};
+                temp |= settings.mag.operating_mode & 0x3;
+                self.m_write_byte(&spi, &gpioa, CTRL_REG3_M, temp); // Continuous conversion mode
+                assert_eq!(temp, self.m_read_byte(&spi, &gpioa, CTRL_REG3_M));
+
+                // CTRL_REG4_M (Default value: 0x00)
+                // [0][0][0][0][OMZ1][OMZ0][BLE][0]
+                // OMZ[1:0] - Z-axis operative mode selection
+                //	00:low-power mode, 01:medium performance
+                //	10:high performance, 10:ultra-high performance
+                // BLE - Big/little endian data
+                temp = (settings.mag.z_performance & 0x3) << 2;
+                self.m_write_byte(&spi, &gpioa, CTRL_REG4_M, temp);
+                assert_eq!(temp, self.m_read_byte(&spi, &gpioa, CTRL_REG4_M));
+
+                // CTRL_REG5_M (Default value: 0x00)
+                // [0][BDU][0][0][0][0][0][0]
+                // BDU - Block data update for magnetic data
+                //	0:continuous, 1:not updated until MSB/LSB are read
+                temp = 0;
+                self.m_write_byte(&spi, &gpioa, CTRL_REG5_M, temp);
+                assert_eq!(temp, self.m_read_byte(&spi, &gpioa, CTRL_REG5_M));
+
+                true
+            }
+
+            /// Reads the raw values from the magnetometer X/Y/Z axis
+            pub fn read_mag_raw(&self,spi: &Spi<$SPI>, gpioa: &GPIOA) -> Vector3<i16> {
+
+                // Read 6 bytes, beginning at OUT_X_L_M
+                let temp = self.m_read_bytes(&spi, &gpioa, OUT_X_L_M, 6);
+                Vector3 {
+                    x:(((temp[1] as u16) << 8) | temp[0] as u16) as i16,
+                    y:(((temp[3] as u16) << 8) | temp[2] as u16) as i16,
+                    z:(((temp[5] as u16) << 8) | temp[4] as u16) as i16,
+                }
+            }
+
+            /// Reads the values from the magnetometer X/Y/Z axis in Gauss
+            pub fn read_mag(&self,spi: &Spi<$SPI>, gpioa: &GPIOA, settings: &ImuSettings) -> Vector3<f32> {
+                let m_res = match settings.mag.scale {
+                    4 => SENSITIVITY_MAGNETOMETER_4,
+                    8 => SENSITIVITY_MAGNETOMETER_8,
+                    12 => SENSITIVITY_MAGNETOMETER_12,
+                    16 => SENSITIVITY_MAGNETOMETER_16,
+                    _ => panic!("Invalid sensitivity")
+                };
+                let m_raw = self.read_mag_raw(&spi, &gpioa);
+                Vector3 {
+                    x:m_raw.x as f32 * m_res,
+                    y:m_raw.y as f32 * m_res,
+                    z:m_raw.z as f32 * m_res,
+                }
+            }
+
+        }
+    }
+}
+
+impl_Lsm9ds1!(SPI1);
+impl_Lsm9ds1!(SPI2);
+impl_Lsm9ds1!(SPI3);