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:
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:
Video
*Not yet*
Source Code
CAD Files
Attach or link to any CAD files if relevant to your project.
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 (Text):
- //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
Android App
Here are screeshots of how the Android app looks right now:
Video
*Not yet*
Source Code
Code (Text):
- #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
- };
- }
Attach or link to any CAD files if relevant to your project.