Fitness Wearable

Introduction
My goal is to create a Fitness Wearable gathering data from the BMI160 IMU. From the data collected I'm going to filter it to get linear movement using the Fourier Transform then save the data in the microSD and finally use the PAN136B module to connect wirelessly to an Android app in order to count the reps made by the user.

BOM
-MAX32630FTHR
-WRL-12577 Bluetooth Module

Schematics
-

Instructions
My first goal was to use the PAN136B module but after trying for several weeks I gave up on it and used the module listed in the BOM.
My attempt to use the PAN136B was the following:
Code:
     //Bluetooth Config
    DigitalOut bReset(P1_6,0); //First Low
    There are two bits that control whether the RTC timer and 32768Hz oscillator are enabled.
    The PWRSEQ_REG0.pwr_rtcen_run bit must be set to 1.
    set PWRSEQ_REG4.pwr_pseq_32k_en to 1
 
    uint32_t myPwrseqReg0 = MXC_PWRSEQ->reg0;
    myPwrseqReg0 &= ~(MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN);
    myPwrseqReg0 |= (1 << MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN_POS);
     MXC_PWRSEQ->reg0 = myPwrseqReg0;

    uint32_t myPwrseqReg4 = MXC_PWRSEQ->reg4;
    myPwrseqReg4 &= ~(MXC_F_PWRSEQ_REG4_PWR_PSEQ_32K_EN);
    myPwrseqReg4 |= (1 << MXC_F_PWRSEQ_REG4_PWR_PSEQ_32K_EN_POS);
    MXC_PWRSEQ->reg4 = myPwrseqReg4;
    wait(0.10);
    bReset.write(1); //Initiate
I managed to gather data from the IMU and saved it on the SDCard, also I already have the FFT. Currently I'm still filtering it in order to work properly with the workouts.
Android App

Here are screeshots of how the Android app looks right now:
1574644653188.png
1574644658345.png

Video
*Not yet*

Source Code
Code:
#include "mbed.h"
#include "max32630fthr.h"
#include "MAX14690.h"
#include "cmsis.h"          // register base address definitions
#include "pwrseq_regs.h"    // power sequence register definitions
#include "bmi160.h"
#include "SDFileSystem.h"
//Setup interrupt in from imu
InterruptIn imuIntIn(P3_6);
static const uint32_t N = 8000; //Samples
bool drdy = false;
void saveData(uint32_t numSamples, float * accX,
              float * accY, float * accZ, float * gyroX, float * gyroY, float * gyroZ);

void imuISR(){
    drdy = true;
}
struct TWIDDLE {  // Structure factor for calculate fft

    float cosval [N/2];
    float sinval [N/2];

};
void FFT(float datos[N], int n, TWIDDLE &w); //Declaration of functions
int main ()
{
    //Init board and set GPIO to 3.3V logic
    MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3);
    //Turn RGB LED off
    DigitalOut rLED(LED1, LED_OFF);
    DigitalOut gLED(LED2, LED_OFF);
    DigitalOut bLED(LED3, LED_OFF);

    Serial BlueCOM(P3_1,P3_0,9600); //UART to the Bluetooth Module, TX,RX
 
    //Setup I2C bus for IMU
    I2C i2cBus(P5_7, P6_0);
    i2cBus.frequency(400000);
    uint32_t failures = 0;
    //Get IMU instance and configure it
    BMI160_I2C imu(i2cBus, BMI160_I2C::I2C_ADRS_SDO_LO); //I2C_ADRS_SDO_LO = 0x68
 
    //Power up sensors in normal mode
    if(imu.setSensorPowerMode(BMI160::GYRO, BMI160::NORMAL) != BMI160::RTN_NO_ERROR) //Differente than success
    {
        BlueCOM.printf("Failed to set gyroscope power mode\n");
        failures++;
    }else{
        BlueCOM.printf("Success grysoscope");
    }  
    wait(0.1);
    if(imu.setSensorPowerMode(BMI160::ACC, BMI160::NORMAL) != BMI160::RTN_NO_ERROR){
        BlueCOM.printf("Failed to set accelerometer power mode\n");
        failures++;
    }else{
        BlueCOM.printf("Success Accelerometer");
    }
    wait(0.1);
    //Accelereometer configuration values
    BMI160::AccConfig accConfig;
    BMI160::AccConfig accConfigRead;
    accConfig.range = BMI160::SENS_2G;
    accConfig.us = BMI160::ACC_US_OFF;
    accConfig.bwp = BMI160::ACC_BWP_2;
    accConfig.odr = BMI160::ACC_ODR_11;
    if(imu.setSensorConfig(accConfig) == BMI160::RTN_NO_ERROR)
    {
        if(imu.getSensorConfig(accConfigRead) == BMI160::RTN_NO_ERROR)
        {
            if((accConfig.range != accConfigRead.range) ||
                    (accConfig.us != accConfigRead.us) ||
                    (accConfig.bwp != accConfigRead.bwp) ||
                    (accConfig.odr != accConfigRead.odr))
            {
                BlueCOM.printf("ACC read data desn't equal set data\n\n");
                BlueCOM.printf("ACC Set Range = %d\n", accConfig.range);
                BlueCOM.printf("ACC Set UnderSampling = %d\n", accConfig.us);
                BlueCOM.printf("ACC Set BandWidthParam = %d\n", accConfig.bwp);
                BlueCOM.printf("ACC Set OutputDataRate = %d\n\n", accConfig.odr);
                BlueCOM.printf("ACC Read Range = %d\n", accConfigRead.range);
                BlueCOM.printf("ACC Read UnderSampling = %d\n", accConfigRead.us);
                BlueCOM.printf("ACC Read BandWidthParam = %d\n", accConfigRead.bwp);
                BlueCOM.printf("ACC Read OutputDataRate = %d\n\n", accConfigRead.odr);
                failures++;
            }
           
        }
        else
        {
             BlueCOM.printf("Failed to read back accelerometer configuration\n");
             failures++;
        }
    }
    else
    {
        BlueCOM.printf("Failed to set accelerometer configuration\n");
        failures++;
    }
 
    BMI160::GyroConfig gyroConfig;
    BMI160::GyroConfig gyroConfigRead;
    gyroConfig.range = BMI160::DPS_2000;
    gyroConfig.bwp = BMI160::GYRO_BWP_2;
    gyroConfig.odr = BMI160::GYRO_ODR_11;
    if(imu.setSensorConfig(gyroConfig) == BMI160::RTN_NO_ERROR)
    {
        if(imu.getSensorConfig(gyroConfigRead) == BMI160::RTN_NO_ERROR)
        {
            if((gyroConfig.range != gyroConfigRead.range) ||
                    (gyroConfig.bwp != gyroConfigRead.bwp) ||
                    (gyroConfig.odr != gyroConfigRead.odr))
            {
                BlueCOM.printf("GYRO read data desn't equal set data\n\n");
                BlueCOM.printf("GYRO Set Range = %d\n", gyroConfig.range);
                BlueCOM.printf("GYRO Set BandWidthParam = %d\n", gyroConfig.bwp);
                BlueCOM.printf("GYRO Set OutputDataRate = %d\n\n", gyroConfig.odr);
                BlueCOM.printf("GYRO Read Range = %d\n", gyroConfigRead.range);
                BlueCOM.printf("GYRO Read BandWidthParam = %d\n", gyroConfigRead.bwp);
                BlueCOM.printf("GYRO Read OutputDataRate = %d\n\n", gyroConfigRead.odr);
                failures++;
            }
         
        }
        else
        {
            BlueCOM.printf("Failed to read back gyroscope configuration\n");
            failures++;
        }
    }
    else
    {
        BlueCOM.printf("Failed to set gyroscope configuration\n");
        failures++;
    }
 
 
    if(failures == 0)
    {
        BlueCOM.printf("ACC Range = %d\n", accConfig.range);
        BlueCOM.printf("ACC UnderSampling = %d\n", accConfig.us);
        BlueCOM.printf("ACC BandWidthParam = %d\n", accConfig.bwp);
        BlueCOM.printf("ACC OutputDataRate = %d\n\n", accConfig.odr);
        BlueCOM.printf("GYRO Range = %d\n", gyroConfig.range);
        BlueCOM.printf("GYRO BandWidthParam = %d\n", gyroConfig.bwp);
        BlueCOM.printf("GYRO OutputDataRate = %d\n\n", gyroConfig.odr);
        wait(1.0);
    }
    DigitalIn uSDdetect(P2_2, PullUp);
    uint32_t samples = 0;
    float accXaxisBuff[N];
    float accYaxisBuff[N];
    float accZaxisBuff[N];
    float gyroXaxisBuff[N];
    float gyroYaxisBuff[N];
    float gyroZaxisBuff[N];
    char c;
    //Sensor data vars
    BMI160::SensorData accData;
    BMI160::SensorData gyroData;
    BMI160::SensorTime sensorTime;
 
    //Enable data ready interrupt from imu for constant loop timming, low latency
    imu.writeRegister(BMI160::INT_EN_1, 0x10);
    //Active High PushPull output on INT1
    imu.writeRegister(BMI160::INT_OUT_CTRL, 0x0A);
    //Map data ready interrupt to INT1
    imu.writeRegister(BMI160::INT_MAP_1, 0x80);
 
     //Tie INT1 to callback fx
    imuIntIn.rise(&imuISR);
    while(1)
    {  
        if(BlueCOM.readable()){
            c = BlueCOM.getc();
            wait(0.25);
            if(c == 's'){ //Start from Bluetooth App
                if(drdy)
                {
                    //Clear data ready flag
                    drdy = false;      
                    //Read feedback sensors
                    imu.getGyroAccXYZandSensorTime(accData, gyroData, sensorTime, accConfig.range, gyroConfig.range);
                    if(samples < N)
                    {
                        accXaxisBuff[samples] = accData.xAxis.scaled;
                        accYaxisBuff[samples] = accData.yAxis.scaled;
                        accZaxisBuff[samples] = accData.zAxis.scaled;
                        gyroXaxisBuff[samples] = gyroData.xAxis.scaled;
                        gyroYaxisBuff[samples] = gyroData.yAxis.scaled;
                        gyroZaxisBuff[samples] = gyroData.zAxis.scaled;
                        samples++;
                    }
                    if(!uSDdetect && (samples > (N-1)))
                    {
                        bLED = LED_ON;
                        saveData(samples, accXaxisBuff, accYaxisBuff, accZaxisBuff, gyroXaxisBuff, gyroYaxisBuff, gyroZaxisBuff);
                        samples = 0;
                        bLED = LED_OFF;
                    }
                    wait(25);
                }
            }
        }
    }
}
//*****************************************************************************
void saveData(uint32_t numSamples,  float * accX, float * accY, float * accZ, float * gyroX, float * gyroY, float * gyroZ)
{
    SDFileSystem sd(P0_5, P0_6, P0_4, P0_7, "sd");  // mosi, miso, sclk, cs
    FILE *fp;
 
    fp = fopen("/sd/Acc&GyroData.txt", "a");
    if(fp != NULL)
    {
        fprintf(fp, "Samples,%d\n", numSamples);

        fprintf(fp, "X-Acc\ty-Acc\tZ-Acc\tX-Gyro\tY-Gyro\tZ-Gyro\n");
     
        for(uint32_t idx = 0; idx < numSamples; idx++)
        {
            fprintf(fp, "%5.4f\t", accX[idx]);
            fprintf(fp, "%5.4f\t", accY[idx]);
            fprintf(fp, "%5.4f\t", accZ[idx]);
            fprintf(fp, "%6.2f\t", gyroX[idx]);
            fprintf(fp, "%6.2f\t", gyroY[idx]);
            fprintf(fp, "%6.2f", gyroZ[idx]);
            fprintf(fp, "\n");
        }
        fprintf(fp, "\n");
        fclose(fp);
    }
    else
    {
        printf("Failed to open file\n");
    }
}
void FFT(float datos[N], int n,TWIDDLE &w) { //Fast Fourier Transform
    float temp1, temp2, temp3,temp4;   //variables needed to calculate FFT
    int i,j,k,p;
    int upper_leg, lower_leg;
    int leg_diff;
    int num_stages=0;
    int index, step;
    float datos_real[n], datos_imag[n]; //real and imaginary values
    for (p=0; p<n; p++) {
        datos_real[p]=datos[p];
        datos_imag[p]=0;
    }
    i=1;
    do {
        num_stages+=1;
        i=i*2;
    } while (i!=n);

    leg_diff=n/2;
    step=1;

    for (i=0; i<num_stages; i++) {
        index=0;
        for (j=0; j<leg_diff; j++) {
            for (upper_leg=j; upper_leg<n; upper_leg+=(2*leg_diff)) {
                lower_leg=upper_leg+leg_diff;

                temp1= (datos_real[upper_leg]+ datos_real[lower_leg]);
                temp2= (datos_real[upper_leg]- datos_real[lower_leg]);
                temp3= (datos_imag[upper_leg]+ datos_imag[lower_leg]);
                temp4= (datos_imag[upper_leg]- datos_imag[lower_leg]);
                datos_real[lower_leg]= (temp2*w.cosval[index])-(temp4*w.sinval[index]);
                datos_imag[lower_leg]= (temp2*w.sinval[index]+temp4*w.cosval[index]);
                datos_real[upper_leg]= temp1;
                datos_imag[upper_leg]= temp3;
            }
            index+=step;
        }
        leg_diff=leg_diff/2;
        step*=2;
    }
//bit reversal
    j=0;
    for (i=1; i<(N-2); i++) {
        k=n/2;
        while (k<=j) {
            j=j-k;
            k=k/2;
        }
        j=j+k;

        if (i<j) {
            temp1= datos_real[j];
            temp2= datos_imag[j];
            datos_real[j]=datos_real[i];
            datos_imag[j]=datos_imag[i];
            datos_real[i]=temp1;
            datos_imag[i]=temp2;
        }
    }

    for (i=0; i<n; i++) {

        datos[i]= pow(sqrt(pow(datos_real[i],2)+pow(datos_imag[i],2)),2); //Calculate the power fft
    };

}
CAD Files
Attach or link to any CAD files if relevant to your project.

Blog entry information

Author
Edumcg
Views
980
Last update

More entries in General

Share this entry

Top