read EMG, IMU, encoder

Dependencies:   mbed

Fork of LSM9DS1_project by 曾 宗圓

Revision:
3:567765d3bcd1
diff -r c889fecf9afe -r 567765d3bcd1 LSM9DS1.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LSM9DS1.cpp	Wed Aug 01 01:01:13 2018 +0000
@@ -0,0 +1,401 @@
+#include "LSM9DS1.h"
+
+LSM9DS1::LSM9DS1(PinName sda, PinName scl, uint8_t xgAddr, uint8_t mAddr) : i2c(sda, scl)
+{
+    // xgAddress and mAddress will store the 7-bit I2C address, if using I2C.
+    xgAddress = xgAddr;
+    mAddress = mAddr;
+}
+
+uint16_t LSM9DS1::begin(gyro_scale gScl, accel_scale aScl, mag_scale mScl, 
+                        gyro_odr gODR, accel_odr aODR, mag_odr mODR)
+{
+    // Store the given scales in class variables. These scale variables
+    // are used throughout to calculate the actual g's, DPS,and Gs's.
+    gScale = gScl;
+    aScale = aScl;
+    mScale = mScl;
+    
+    // Once we have the scale values, we can calculate the resolution
+    // of each sensor. That's what these functions are for. One for each sensor
+    calcgRes(); // Calculate DPS / ADC tick, stored in gRes variable
+    calcmRes(); // Calculate Gs / ADC tick, stored in mRes variable
+    calcaRes(); // Calculate g / ADC tick, stored in aRes variable
+    
+    
+    // To verify communication, we can read from the WHO_AM_I register of
+    // each device. Store those in a variable so we can return them.
+    // The start of the addresses we want to read from
+    char cmd[2] = {
+        WHO_AM_I_XG,
+        0
+    };
+
+    // Write the address we are going to read from and don't end the transaction
+    i2c.write(xgAddress, cmd, 1, true);
+    // Read in all the 8 bits of data
+    i2c.read(xgAddress, cmd+1, 1);
+    uint8_t xgTest = cmd[1];                    // Read the accel/gyro WHO_AM_I
+    
+    // Reset to the address of the mag who am i
+    cmd[1] = WHO_AM_I_M;
+    // Write the address we are going to read from and don't end the transaction
+    i2c.write(mAddress, cmd, 1, true);
+    // Read in all the 8 bits of data
+    i2c.read(mAddress, cmd+1, 1);
+    uint8_t mTest = cmd[1];      // Read the mag WHO_AM_I
+    
+    // Gyro initialization stuff:
+    initGyro(); // This will "turn on" the gyro. Setting up interrupts, etc.
+    setGyroODR(gODR); // Set the gyro output data rate and bandwidth.
+    setGyroScale(gScale); // Set the gyro range
+    
+    // Accelerometer initialization stuff:
+    initAccel(); // "Turn on" all axes of the accel. Set up interrupts, etc.
+    setAccelODR(aODR); // Set the accel data rate.
+    setAccelScale(aScale); // Set the accel range.
+    
+    // Magnetometer initialization stuff:
+    initMag(); // "Turn on" all axes of the mag. Set up interrupts, etc.
+    setMagODR(mODR); // Set the magnetometer output data rate.
+    setMagScale(mScale); // Set the magnetometer's range.
+    
+    // Once everything is initialized, return the WHO_AM_I registers we read:
+    return (xgTest << 8) | mTest;
+}
+
+void LSM9DS1::initGyro()
+{
+    char cmd[4] = {
+        CTRL_REG1_G,
+        gScale | G_ODR_119_BW_14,
+        0,          // Default data out and int out
+        0           // Default power mode and high pass settings
+    };
+
+    // Write the data to the gyro control registers
+    i2c.write(xgAddress, cmd, 4);
+}
+
+void LSM9DS1::initAccel()
+{
+    char cmd[4] = {
+        CTRL_REG5_XL,
+        0x38,       // Enable all axis and don't decimate data in out Registers
+        (A_ODR_119 << 5) | (aScale << 3) | (A_BW_AUTO_SCALE),   // 119 Hz ODR, set scale, and auto BW
+        0           // Default resolution mode and filtering settings
+    };
+
+    // Write the data to the accel control registers
+    i2c.write(xgAddress, cmd, 4);
+}
+
+void LSM9DS1::initMag()
+{   
+    char cmd[4] = {
+        CTRL_REG1_M,
+        0x10,       // Default data rate, xy axes mode, and temp comp
+        mScale << 5, // Set mag scale
+        0           // Enable I2C, write only SPI, not LP mode, Continuous conversion mode
+    };
+
+    // Write the data to the mag control registers
+    i2c.write(mAddress, cmd, 4);
+}
+
+void LSM9DS1::readAccel()
+{
+    // The data we are going to read from the accel
+    char data[6];
+
+    // The start of the addresses we want to read from
+    char subAddress = OUT_X_L_XL;
+
+    // Write the address we are going to read from and don't end the transaction
+    i2c.write(xgAddress, &subAddress, 1, true);
+    // Read in all 8 bit registers containing the axes data
+    i2c.read(xgAddress, data, 6);
+
+    // Reassemble the data and convert to g
+    ax_raw = data[0] | (data[1] << 8);
+    ay_raw = data[2] | (data[3] << 8);
+    az_raw = data[4] | (data[5] << 8);
+    ax = ax_raw * aRes;
+    ay = ay_raw * aRes;
+    az = az_raw * aRes;
+}
+
+void LSM9DS1::readMag()
+{
+    // The data we are going to read from the mag
+    char data[6];
+
+    // The start of the addresses we want to read from
+    char subAddress = OUT_X_L_M;
+
+    // Write the address we are going to read from and don't end the transaction
+    i2c.write(mAddress, &subAddress, 1, true);
+    // Read in all 8 bit registers containing the axes data
+    i2c.read(mAddress, data, 6);
+
+    // Reassemble the data and convert to degrees
+    mx_raw = data[0] | (data[1] << 8);
+    my_raw = data[2] | (data[3] << 8);
+    mz_raw = data[4] | (data[5] << 8);
+    mx = mx_raw * mRes;
+    my = my_raw * mRes;
+    mz = mz_raw * mRes;
+}
+
+void LSM9DS1::readTemp()
+{
+    // The data we are going to read from the temp
+    char data[2];
+
+    // The start of the addresses we want to read from
+    char subAddress = OUT_TEMP_L;
+
+    // Write the address we are going to read from and don't end the transaction
+    i2c.write(xgAddress, &subAddress, 1, true);
+    // Read in all 8 bit registers containing the axes data
+    i2c.read(xgAddress, data, 2);
+
+    // Temperature is a 12-bit signed integer   
+    temperature_raw = data[0] | (data[1] << 8);
+
+    temperature_c = (float)temperature_raw / 8.0 + 25;
+    temperature_f = temperature_c * 1.8 + 32;
+}
+
+
+void LSM9DS1::readGyro()
+{
+    // The data we are going to read from the gyro
+    char data[6];
+
+    // The start of the addresses we want to read from
+    char subAddress = OUT_X_L_G;
+
+    // Write the address we are going to read from and don't end the transaction
+    i2c.write(xgAddress, &subAddress, 1, true);
+    // Read in all 8 bit registers containing the axes data
+    i2c.read(xgAddress, data, 6);
+
+    // Reassemble the data and convert to degrees/sec
+    gx_raw = data[0] | (data[1] << 8);
+    gy_raw = data[2] | (data[3] << 8);
+    gz_raw = data[4] | (data[5] << 8);
+    gx = gx_raw * gRes;
+    gy = gy_raw * gRes;
+    gz = gz_raw * gRes;
+}
+
+void LSM9DS1::setGyroScale(gyro_scale gScl)
+{
+    // The start of the addresses we want to read from
+    char cmd[2] = {
+        CTRL_REG1_G,
+        0
+    };
+
+    // Write the address we are going to read from and don't end the transaction
+    i2c.write(xgAddress, cmd, 1, true);
+    // Read in all the 8 bits of data
+    i2c.read(xgAddress, cmd+1, 1);
+
+    // Then mask out the gyro scale bits:
+    cmd[1] &= 0xFF^(0x3 << 3);
+    // Then shift in our new scale bits:
+    cmd[1] |= gScl << 3;
+
+    // Write the gyroscale out to the gyro
+    i2c.write(xgAddress, cmd, 2);
+    
+    // We've updated the sensor, but we also need to update our class variables
+    // First update gScale:
+    gScale = gScl;
+    // Then calculate a new gRes, which relies on gScale being set correctly:
+    calcgRes();
+}
+
+void LSM9DS1::setAccelScale(accel_scale aScl)
+{
+    // The start of the addresses we want to read from
+    char cmd[2] = {
+        CTRL_REG6_XL,
+        0
+    };
+
+    // Write the address we are going to read from and don't end the transaction
+    i2c.write(xgAddress, cmd, 1, true);
+    // Read in all the 8 bits of data
+    i2c.read(xgAddress, cmd+1, 1);
+
+    // Then mask out the accel scale bits:
+    cmd[1] &= 0xFF^(0x3 << 3);
+    // Then shift in our new scale bits:
+    cmd[1] |= aScl << 3;
+
+    // Write the accelscale out to the accel
+    i2c.write(xgAddress, cmd, 2);
+    
+    // We've updated the sensor, but we also need to update our class variables
+    // First update aScale:
+    aScale = aScl;
+    // Then calculate a new aRes, which relies on aScale being set correctly:
+    calcaRes();
+}
+
+void LSM9DS1::setMagScale(mag_scale mScl)
+{
+    // The start of the addresses we want to read from
+    char cmd[2] = {
+        CTRL_REG2_M,
+        0
+    };
+
+    // Write the address we are going to read from and don't end the transaction
+    i2c.write(mAddress, cmd, 1, true);
+    // Read in all the 8 bits of data
+    i2c.read(mAddress, cmd+1, 1);
+
+    // Then mask out the mag scale bits:
+    cmd[1] &= 0xFF^(0x3 << 5);
+    // Then shift in our new scale bits:
+    cmd[1] |= mScl << 5;
+
+    // Write the magscale out to the mag
+    i2c.write(mAddress, cmd, 2);
+    
+    // We've updated the sensor, but we also need to update our class variables
+    // First update mScale:
+    mScale = mScl;
+    // Then calculate a new mRes, which relies on mScale being set correctly:
+    calcmRes();
+}
+
+void LSM9DS1::setGyroODR(gyro_odr gRate)
+{
+    // The start of the addresses we want to read from
+    char cmd[2] = {
+        CTRL_REG1_G,
+        0
+    };
+
+    // Write the address we are going to read from and don't end the transaction
+    i2c.write(xgAddress, cmd, 1, true);
+    // Read in all the 8 bits of data
+    i2c.read(xgAddress, cmd+1, 1);
+
+    // Then mask out the gyro odr bits:
+    cmd[1] &= (0x3 << 3);
+    // Then shift in our new odr bits:
+    cmd[1] |= gRate;
+
+    // Write the gyroodr out to the gyro
+    i2c.write(xgAddress, cmd, 2);
+}
+
+void LSM9DS1::setAccelODR(accel_odr aRate)
+{
+    // The start of the addresses we want to read from
+    char cmd[2] = {
+        CTRL_REG6_XL,
+        0
+    };
+
+    // Write the address we are going to read from and don't end the transaction
+    i2c.write(xgAddress, cmd, 1, true);
+    // Read in all the 8 bits of data
+    i2c.read(xgAddress, cmd+1, 1);
+
+    // Then mask out the accel odr bits:
+    cmd[1] &= 0xFF^(0x7 << 5);
+    // Then shift in our new odr bits:
+    cmd[1] |= aRate << 5;
+
+    // Write the accelodr out to the accel
+    i2c.write(xgAddress, cmd, 2);
+}
+
+void LSM9DS1::setMagODR(mag_odr mRate)
+{
+    // The start of the addresses we want to read from
+    char cmd[2] = {
+        CTRL_REG1_M,
+        0
+    };
+
+    // Write the address we are going to read from and don't end the transaction
+    i2c.write(mAddress, cmd, 1, true);
+    // Read in all the 8 bits of data
+    i2c.read(mAddress, cmd+1, 1);
+
+    // Then mask out the mag odr bits:
+    cmd[1] &= 0xFF^(0x7 << 2);
+    // Then shift in our new odr bits:
+    cmd[1] |= mRate << 2;
+
+    // Write the magodr out to the mag
+    i2c.write(mAddress, cmd, 2);
+}
+
+void LSM9DS1::calcgRes()
+{
+    // Possible gyro scales (and their register bit settings) are:
+    // 245 DPS (00), 500 DPS (01), 2000 DPS (10).
+    switch (gScale)
+    {
+        case G_SCALE_245DPS:
+            gRes = 245.0 / 32768.0;
+            break;
+        case G_SCALE_500DPS:
+            gRes = 500.0 / 32768.0;
+            break;
+        case G_SCALE_2000DPS:
+            gRes = 2000.0 / 32768.0;
+            break;
+    }
+}
+
+void LSM9DS1::calcaRes()
+{
+    // Possible accelerometer scales (and their register bit settings) are:
+    // 2 g (000), 4g (001), 6g (010) 8g (011), 16g (100).
+    switch (aScale)
+    {
+        case A_SCALE_2G:
+            aRes = 2.0 / 32768.0;
+            break;
+        case A_SCALE_4G:
+            aRes = 4.0 / 32768.0;
+            break;
+        case A_SCALE_8G:
+            aRes = 8.0 / 32768.0;
+            break;
+        case A_SCALE_16G:
+            aRes = 16.0 / 32768.0;
+            break;
+    }
+}
+
+void LSM9DS1::calcmRes()
+{
+    // Possible magnetometer scales (and their register bit settings) are:
+    // 2 Gs (00), 4 Gs (01), 8 Gs (10) 12 Gs (11). 
+    switch (mScale)
+    {
+        case M_SCALE_4GS:
+            mRes = 4.0 / 32768.0;
+            break;
+        case M_SCALE_8GS:
+            mRes = 8.0 / 32768.0;
+            break;
+        case M_SCALE_12GS:
+            mRes = 12.0 / 32768.0;
+            break;
+        case M_SCALE_16GS:
+            mRes = 16.0 / 32768.0;
+            break;
+    }
+}
\ No newline at end of file