This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430FR6889: Floating point operation with the MSPDSP library to measure FFT accurately (MSP430)

Part Number: MSP430FR6889

Hello,

I am utilizing the BMI160-based Sensor Booster Pack and the MSP430FR6889 Launchpad. I'm attempting to do FFT on the BMI160 Accelerometer data using the MSPDSP library. I'm utilizing a platform that vibrates between 3.3 and 3.5 Hz. The FFT algorithm, however, only produces integer numbers. Is it feasible to use a floating point data type to obtain a more precise value? How can the library or code be changed in that situation to get a more accurate result?

Thank you.

  • Hi,

    MSP430 core don't have FPU module, thus we don't support float operation.

    You can use DSPLib to run FFT with IQMATH format.

    Thanks!

    Best Regards

    Johson

  • Hello Johson,

    Thank you for your reply. I am using the "msp_fft_fixed_q15" function to perform the FFT, but I am still getting integer values as output. I am using the console of CCS to serial print the data.

    Here is the code:

    #include <msp430.h> 
    #include "driverlib.h"
    #include "DSPLib.h"
    #include <gpio.h>
    #include <intrinsics.h>
    #include <msp430fr5xx_6xxgeneric.h>
    #include <stdint.h>
    #include <stdio.h>
    
    //new
    //#include "myClocks.h"
    //new
    
    //******************************************************************************
    // Defines *********************************************************************
    //******************************************************************************
    //Address if the BMI160
    #define SLAVE_ADDR 0x69
    //Maximum I2C buffer size
    #define MAX_BUFFER_SIZE 20
    
    //Number of FFT samples
    #define SAMPLES 1024
    #define TimeStampSample 10
    /* Declare as persistent to move variable from RAM to FRAM */
    #pragma PERSISTENT(input)
    int16_t input[SAMPLES] = {0}; //Store samples
    
    #pragma PERSISTENT(max)
    int16_t max[SAMPLES] = {0}; //Store frequencies with maximum amplitudes
    
    #pragma PERSISTENT(amp)
    int16_t amp[SAMPLES] = {0}; //Store the maximum amplitudes
    
    /* Temporary data array for processing */
    DSPLIB_DATA(temp,4)
    /* Declare as persistent to move variable to FRAM */
    #pragma PERSISTENT(temp)
    int16_t temp[3*SAMPLES/2] = {0};
    
    //Global flags for sensor interrupts to avoid interrupt nesting
    volatile int motion_trigger = 0;
    
    /* Benchmark cycle counts */
    volatile uint32_t cycleCount;
    
    //#pragma PERSISTENT(SENSORTIME)
    //volatile int32_t SENSORTIME[SAMPLES] = {0}; //Store samples
    
    
    //new
    
    #define UP              0x0010                          // Timer_A Up mode
    #define CONTINUOUS      0x0020                          // Timer_A Continuous mode
    #define ACLK            0x0100                          // Timer_A SMCLK source
    #define DEVELOPMENT     0x5A80                          // Stop the watchdog timer
    #define BOUNCE_DELAY    0xA000                          // Delay for Button Bounce
    #define MS_10           400                             // Approximate value to count for 10ms
    #define SMCLK           0x0200                          // Timer_A SMCLK source
    
    //new
    
    
    
    //******************************************************************************
    // Frequency Functions *********************************************************
    //******************************************************************************
    
    void bubbleSort(int amp[], int max[], int n)
    {
       int i, j, temp;
       for (i = 0; i < n-1; i++)
       {
           // Last i elements are already in place
           for (j = 0; j < n-i-1; j++)
           {
               if (amp[j] < amp[j+1])
               {
                  temp = max[j];
                  max[j] = max[j+1];
                  max[j+1] = temp;
    
                  temp = amp[j];
                  amp[j] = amp[j+1];
                  amp[j+1] = temp;
               }
           }
       }
    }
    
    void getMaximums(int16_t input[], int samples, int16_t max[], int16_t amp[])
    {
        int i,j = 0;
        for(i=1; i<samples-1; i++)
            {
                if((input[i-1] < input[i]) && (input[i] > input[i+1]))
                {
                    amp[j] = input[i];
                    max[j++] = i;
                }
            }
        bubbleSort(amp, max, samples);
    }
    
    //******************************************************************************
    // Timer Functions *************************************************************
    //******************************************************************************
    
    int delay(int count)
    {
        if(TA1CTL & TAIFG)                                  // If Timer_1 is done counting
        {
            count = count-1;                                        // Decrement count
            TA1CTL = TA1CTL & (~TAIFG);                             // Reset Timer_1
        }
        return count;                                       // Return the value of count
    } // end delay
    //******************************************************************************
    // UART Functions **************************************************************
    //******************************************************************************
    void UART_transmitString( char *pStr ) //Transmits a string over UART0
    {
        while( *pStr )
        {
            while(!(UCA0IFG&UCTXIFG));
            UCA0TXBUF = *pStr;
            pStr++;
        }
    }
    
    //******************************************************************************
    // I2C Functions ***************************************************************
    //******************************************************************************
    typedef enum I2C_ModeEnum{
        IDLE_MODE,
        NACK_MODE,
        TX_REG_ADDRESS_MODE,
        RX_REG_ADDRESS_MODE,
        TX_DATA_MODE,
        RX_DATA_MODE,
        SWITCH_TO_RX_MODE,
        SWITHC_TO_TX_MODE,
        TIMEOUT_MODE
    } I2C_Mode;
    
    /* Used to track the state of the software state machine*/
    I2C_Mode MasterMode = IDLE_MODE;
    
    uint8_t TransmitRegAddr = 0; //Register address for transmission
    uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0}; //Buffer for received values
    uint8_t RXByteCtr = 0; //Count received bytes
    uint8_t ReceiveIndex = 0; //Index of received data
    uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0}; //Buffer for transmitted values
    uint8_t TXByteCtr = 0; //Count transmitted bytes
    uint8_t TransmitIndex = 0; //Index of transmitted data
    
    void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
    {
        uint8_t copyIndex = 0;
        for (copyIndex = 0; copyIndex < count; copyIndex++)
        {
            dest[copyIndex] = source[copyIndex];
        }
    }
    
    I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count)
    {
        //printf("R\n");
        /* Initialize state machine */
        MasterMode = TX_REG_ADDRESS_MODE;
        TransmitRegAddr = reg_addr;
        RXByteCtr = count;
        TXByteCtr = 0;
        ReceiveIndex = 0;
        TransmitIndex = 0;
    
        /* Initialize slave address and interrupts */
        UCB1I2CSA = dev_addr;
        UCB1IFG &= ~(UCTXIFG + UCRXIFG);       // Clear any pending interrupts
        UCB1IE &= ~UCRXIE;                       // Disable RX interrupt
        UCB1IE |= UCTXIE;                        // Enable TX interrupt
    
        UCB1CTLW0 |= UCTR + UCTXSTT;             // I2C TX, start condition
        __bis_SR_register(LPM0_bits + GIE);              // Enter LPM0 w/ interrupts
     //   UCB1IE &= ~UCRXIE;                       // Disable RX interrupt
    
    
        return MasterMode;
    
    }
    
    I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
    {
        /* Initialize state machine */
        MasterMode = TX_REG_ADDRESS_MODE;
        TransmitRegAddr = reg_addr;
    
        //Copy register data to TransmitBuffer
        CopyArray(reg_data, TransmitBuffer, count);
    
        TXByteCtr = count;
        RXByteCtr = 0;
        ReceiveIndex = 0;
        TransmitIndex = 0;
    
        /* Initialize slave address and interrupts */
        UCB1I2CSA = dev_addr;
        UCB1IFG &= ~(UCTXIFG + UCRXIFG);       // Clear any pending interrupts
        UCB1IE &= ~UCRXIE;                       // Disable RX interrupt
        UCB1IE |= UCTXIE;                        // Enable TX interrupt
    
        UCB1CTLW0 |= UCTR + UCTXSTT;             // I2C TX, start condition
        __bis_SR_register(LPM0_bits + GIE);              // Enter LPM0 w/ interrupts
        //printf("W\n");
        return MasterMode;
    }
    
    //******************************************************************************
    // BMI160 Functions ************************************************************
    //******************************************************************************
    void bmi160_init(char FOC_axis)
    {
        uint8_t writeData[1];
        //Read Chip ID, which is D1
        I2C_Master_ReadReg(SLAVE_ADDR, 0x00, 1);
        if(ReceiveBuffer[0] != 0xD1)
        {
            UART_transmitString(" Incorrect sensor chip ID ");
            printf("Incorrect sensor chip ID\n");
        }
    
    
    
    
        //Configure the accelerometer
        writeData[0]=0b00101100; //Set acc_us to 0 for off, and acc_bwp must then be 010. Set acc_odr to 1011(800Hz),1100(1600Hz),1000(100Hz),0001(25/32Hz)
        I2C_Master_WriteReg(SLAVE_ADDR, 0x40, writeData, 1);
        //Check if configuration worked
        I2C_Master_ReadReg(SLAVE_ADDR, 0x40, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Accelerometer config failed ");
            printf("Accelerometer config failed\n");
        }
        //Set the range of the accelerometer
        writeData[0]=0b1000; //0b0011 for 2g, 0b0101 for 4g, 0b1000 for 8g
        I2C_Master_WriteReg(SLAVE_ADDR, 0x41, writeData, 1);
        //Check if range is set
        I2C_Master_ReadReg(SLAVE_ADDR, 0x41, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Accelerometer range set failed ");
            printf("Accelerometer range set failed\n");
        }
    
        //Any motion setup
    
        //Set the successive slope threshold
        writeData[0]=0b00000001; //0b00000001 + 1 so two successive slopes
        I2C_Master_WriteReg(SLAVE_ADDR, 0x5F, writeData, 1);
        //Check if slope threshold is set
        I2C_Master_ReadReg(SLAVE_ADDR, 0x5F, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Slope threshold not set ");
            printf("Slope threshold not set\n");
        }
        //Set trigger level
        writeData[0]=0b01001101; //15.63mg*value for 8g range, 0b00000000 gives 7.81mg
        I2C_Master_WriteReg(SLAVE_ADDR, 0x60, writeData, 1);
        //Check trigger is set
        I2C_Master_ReadReg(SLAVE_ADDR, 0x60, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Trigger not set ");
            printf("Trigger not set\n");
        }
    
        //Double tap setup
    
        //Set single and double tap timings
        writeData[0] = 0b00000110; //Quiet of 30ms, shock of 50ms, double tap within 500ms
        I2C_Master_WriteReg(SLAVE_ADDR, 0x63, writeData, 1);
        //Read the timings
        I2C_Master_ReadReg(SLAVE_ADDR, 0x63, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Tap timings not set ");
            printf("Tap timings not set\n");
        }
        //Set tap threshold
        writeData[0] = 0b0000; //125mg threshold
        I2C_Master_WriteReg(SLAVE_ADDR, 0x64, writeData, 1);
        //Read the threshold
        I2C_Master_ReadReg(SLAVE_ADDR, 0x64, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Tap timings not set ");
            printf("Tap timings not set\n");
        }
    
        //Interrupt setup
    
        //Enable any-motion and double tap interrupts
        writeData[0] = 0b00010100; //Enables double tap and any-motion z interrupt
        I2C_Master_WriteReg(SLAVE_ADDR, 0x50, writeData, 1);
        //Read interrupt enable status
        I2C_Master_ReadReg(SLAVE_ADDR, 0x50, 1);
        if(ReceiveBuffer[0] != 0b00010100)
        {
            UART_transmitString("Interrupts not enabled");
            printf("Interrupts not enabled\n");
        }
        //Set pins
        writeData[0] = 0b10001000; //Output, push-pull, active low for int1 and int2
        I2C_Master_WriteReg(SLAVE_ADDR, 0x53, writeData, 1);
        //Read pin status
        I2C_Master_ReadReg(SLAVE_ADDR, 0x53, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Pins not set ");
            printf("Pins not set\n");
        }
        //Set interrupts to temporary instead of latched (permanent till cleared)
        writeData[0] = 0b1101; //Temp for 1.28s
        I2C_Master_WriteReg(SLAVE_ADDR, 0x54, writeData, 1);
        //Check interrupts
        I2C_Master_ReadReg(SLAVE_ADDR, 0x54, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Interrupts not temp ");
            printf("Interrupts not temp");
        }
        //Map any motion detection to Int1
        writeData[0] = 0b00000100; //Mapped any motion to int1
        I2C_Master_WriteReg(SLAVE_ADDR, 0x55, writeData, 1);
        //Check interrupt
        I2C_Master_ReadReg(SLAVE_ADDR, 0x55, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Any motion not mapped ");
            printf("Any motion not mapped\n");
        }
        //Map double tap to Int2
        writeData[0] = 0b00010000; //Mapped double tap to int2
        I2C_Master_WriteReg(SLAVE_ADDR, 0x57, writeData, 1);
        //Check interrupt
        I2C_Master_ReadReg(SLAVE_ADDR, 0x57, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Double tap not mapped ");
            printf("Double tap not mapped\n");
        }
        //Set tap data filtering
        writeData[0] = 0b1000; //Filtered data instead of pre-filtered
        I2C_Master_WriteReg(SLAVE_ADDR, 0x58, writeData, 1);
        //Check filtering
        I2C_Master_ReadReg(SLAVE_ADDR, 0x58, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Filter not set ");
            printf("Filter not set\n");
        }
        //Set the Accelerometer to normal power mode
        writeData[0] = 0x11;
        I2C_Master_WriteReg(SLAVE_ADDR, 0x7E, writeData, 1);
        //Read power mode status of sensors
        I2C_Master_ReadReg(SLAVE_ADDR, 0x03, 1);
        if(ReceiveBuffer[0] != 0x10)
        {
            UART_transmitString(" Accelerometer not on ");
            printf("Accelerometer not on\n");
        }
    
        //Fast Offset Compensation (FOC) setup
    
        //0 for reserved, 0 for gyroscope, 00 for x, 00 for y, 0 for z (10 = -1g, 00 = 0g, 01 = 1g)
        switch(FOC_axis)
        {
            case 'X':
                writeData[0] = 0b00100000;
                break;
            case 'Y':
                writeData[0] = 0b00001000;
                break;
            case 'Z':
                writeData[0] = 0b00000010;
                break;
            default:
                writeData[0] = 0b00000000; //Default of all 0g
                break;
        }
        I2C_Master_WriteReg(SLAVE_ADDR, 0x69, writeData, 1);
        //Check FOC
        I2C_Master_ReadReg(SLAVE_ADDR, 0x69, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" FOC not set ");
            printf("Incorrect sensor chip ID\n");
        }
        //Start FOC
        writeData[0] = 0x03;
        I2C_Master_WriteReg(SLAVE_ADDR, 0x7E, writeData, 1);
        //Wait until FOC is finished
        int finish = 0;
        while(finish==0)
        {
            I2C_Master_ReadReg(SLAVE_ADDR, 0x1B, 1);
            if((ReceiveBuffer[0] & 0b00001000) == 0b00001000)
            {
                finish = 1;
            }
        }
        //Enable offset compensation
        writeData[0] = 0b01000000; //Enable accelerometer offset compensation
        I2C_Master_WriteReg(SLAVE_ADDR, 0x77, writeData, 1);
        //Check offset compensation
        I2C_Master_ReadReg(SLAVE_ADDR, 0x77, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Offset not enabled ");
            printf("Incorrect sensor chip ID\n");
        }
        //UART_transmitString(" BMI160 Initialized \n");
    }
    
    
    
    //******************************************************************************
    // Device Initialization *******************************************************
    //******************************************************************************
    void initGPIO()
    {
        /* Terminate all GPIO pins to Output LOW to minimize power consumption */
        GPIO_setAsOutputPin(GPIO_PORT_PA, GPIO_PIN_ALL16);
        GPIO_setAsOutputPin(GPIO_PORT_PB, GPIO_PIN_ALL16);
        GPIO_setAsOutputPin(GPIO_PORT_PC, GPIO_PIN_ALL16);
        GPIO_setAsOutputPin(GPIO_PORT_PD, GPIO_PIN_ALL16);
        GPIO_setAsOutputPin(GPIO_PORT_PE, GPIO_PIN_ALL16);
        GPIO_setAsOutputPin(GPIO_PORT_PF, GPIO_PIN_ALL16);
        GPIO_setOutputLowOnPin(GPIO_PORT_PA, GPIO_PIN_ALL16);
        GPIO_setOutputLowOnPin(GPIO_PORT_PB, GPIO_PIN_ALL16);
        GPIO_setOutputLowOnPin(GPIO_PORT_PC, GPIO_PIN_ALL16);
        GPIO_setOutputLowOnPin(GPIO_PORT_PD, GPIO_PIN_ALL16);
        GPIO_setOutputLowOnPin(GPIO_PORT_PE, GPIO_PIN_ALL16);
        GPIO_setOutputLowOnPin(GPIO_PORT_PF, GPIO_PIN_ALL16);
    
        // I2C pins (P4.0 is SDA, P4.1 is SCL)
        P4SEL1 |= BIT0 | BIT1;
        P4SEL0 &= ~(BIT0 | BIT1);
    
        // Configure P3.4 and P3.5 to UART (Primary, TX and RX respectively) for NeoCortec
        P3SEL0 |= BIT4 | BIT5;                    // USCI_A1 UART operation
        P3SEL1 &= ~(BIT4 | BIT5);                 // SEL1 is 0 and SEL0 is 1 for primary operation, inverse for secondary
    
        // Configure P2.0 and P2.1 to UART (Primary, TX and RX respectively) for PC
        P2SEL0 |= BIT0 | BIT1;                    // USCI_A0 UART operation
        P2SEL1 &= ~(BIT0 | BIT1);                 // SEL1 is 0 and SEL0 is 1 for primary operation, inverse for secondary
    
        // Configure button S1 (P1.1) interrupt
        GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN1, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1);
        GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN1);
        GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1);
    
        // Configure button S2 (P1.2) interrupt
        GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN2);
        GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN2);
        GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN2);
    
        // Configure CTS active (P1.3) interrupt
        GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN3, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN3);
        GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN3);
        GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN3);
    
        // Configure Nwu (P1.4) interrupt
        GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN4);
        GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN4);
        GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN4);
    
        // Configure INT1 (P3.2) interrupt
        GPIO_selectInterruptEdge(GPIO_PORT_P3, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P3, GPIO_PIN2);
        GPIO_clearInterrupt(GPIO_PORT_P3, GPIO_PIN2);
        GPIO_enableInterrupt(GPIO_PORT_P3, GPIO_PIN2);
    
        // Configure INT2 (P2.5) interrupt
        GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN5, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN5);
        GPIO_clearInterrupt(GPIO_PORT_P2, GPIO_PIN5);
        GPIO_enableInterrupt(GPIO_PORT_P2, GPIO_PIN5);
    
        // Disable the GPIO power-on default high-impedance mode to activate
        // previously configured port settings
        PM5CTL0 &= ~LOCKLPM5;
        __bis_SR_register(GIE);
    }
    
    void initClockTo16MHz()
    {
        // Configure one FRAM waitstate as required by the device datasheet for MCLK
        // operation beyond 8MHz _before_ configuring the clock system.
        FRCTL0 = FRCTLPW | NWAITS_1;
    
        // Clock System Setup
        CSCTL0_H = CSKEY_H;                     // Unlock CS registers
        CSCTL1 = DCOFSEL_0;                     // Set DCO to 1MHz
    
        // Set SMCLK = MCLK = DCO, ACLK = VLOCLK (9.4kHz)
        CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
    
        // Per Device Errata set divider to 4 before changing frequency to
        // prevent out of spec operation from overshoot transient
        CSCTL3 = DIVA__4 | DIVS__4 | DIVM__4;   // Set all corresponding clk sources to divide by 4 for errata
        CSCTL1 = DCOFSEL_4 | DCORSEL;           // Set DCO to 16MHz
    
        // Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz))
        __delay_cycles(60);
        CSCTL3 = DIVA__32 | DIVS__1 | DIVM__1;  // Set ACLK to 239.75Hz, SMCLK to 16MHz, and MCLK to 16MHz
        CSCTL0_H = 0;                           // Lock CS registers
    }
    
    void initI2C()
    {
        UCB1CTLW0 = UCSWRST;                      // Enable SW reset
        UCB1CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSYNC; // I2C master mode, SMCLK
        UCB1BRW = 160;                            // fSCL = ACLK/160 = ~100kHz
        UCB1I2CSA = SLAVE_ADDR;                   // Slave Address
        UCB1CTLW0 &= ~UCSWRST;                    // Clear SW reset, resume operation
        UCB1IE |= UCNACKIE;
    }
    
    void UART_init(void)
    {
        // Configure USCI_A1 for UART mode
        UCA1CTLW0 = UCSWRST;                      // Put eUSCI in reset
        UCA1CTLW0 |= UCSSEL__SMCLK;               // CLK = SMCLK
        UCA1BR0 = 8;                              // Clock prescaler set to 8
        UCA1BR1 = 0x00;                           // High byte empty, low byte is 8
        UCA1MCTLW |= UCOS16 | UCBRF_10 | 0xF700;  // Over-sampling on, first modulation register set to 10, second modulation register set to 0xF7 (247) for high byte, 0 for low byte
        UCA1CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
        UCA1IE |= UCRXIE;                         // Enable USCI_A1 RX interrupt
    
        // Configure USCI_A0 for UART mode
        UCA0CTLW0 = UCSWRST;                      // Put eUSCI in reset
        UCA0CTLW0 |= UCSSEL__SMCLK;               // CLK = SMCLK
        UCA0BR0 = 8;                              // Clock prescaler set to 8
        UCA0BR1 = 0x00;                           // High byte empty, low byte is 8
        UCA0MCTLW |= UCOS16 | UCBRF_10 | 0xF700;  // Over-sampling on, first modulation register set to 10, second modulation register set to 0xF7 (247) for high byte, 0 for low byte
        UCA0CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
        UCA0IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt
    }
    
    
    
    //******************************************************************************
    // Main ************************************************************************
    //******************************************************************************
    
     int main(void)
     {
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
        //Initialize all peripherals
        initClockTo16MHz();
        initGPIO();
        UART_init();
        initI2C();
    
        bmi160_init('Z');
    
        // Initialize the FFT parameters
        msp_status status;
        msp_fft_q15_params fftParams;
    
        /* Initialize the fft parameter structure. */
        fftParams.length = SAMPLES;
        fftParams.bitReverse = true;
        fftParams.twiddleTable = msp_cmplx_twiddle_table_4096_q15; //Twiddle table for 4096 values
    
    
        int i = 0;
    
        //new
        TA0CTL   = TA0CTL | (SMCLK + CONTINUOUS);           // SMCLK:  Counts faster than ACLK
                                                            // CONTINUOUS:  Count 0 to 0xFFFF
        TA0CCTL0 = CCIE;                                    // Timer_0 interrupt
    
        TA1CTL   = TA1CTL | (ACLK  + UP         );          // Count up from 0 with ACLK
        TA1CCR0  = MS_10;                                   // Duration approximatley 10ms
    
        _BIS_SR(GIE);                                       // Activate all interrupts
    
        //new
    
        while(1)
        {
               printf("Reading samples\n");
               //Read SAMPLES amount of data from the BMI160
               for(i=0;i<SAMPLES;i++)
               {
                   I2C_Master_ReadReg(SLAVE_ADDR, 0x16, 2); //Read the acceleration value from the BMI160 registers
                   input[i]= ReceiveBuffer[0] | (ReceiveBuffer[1] << 8); //Store the value in an array
               }
               printf("Samples read\n");
    
    
               msp_benchmarkStart(MSP_BENCHMARK_BASE, 16);
               status = msp_fft_fixed_q15(&fftParams, input); //Perform FFT
               cycleCount = msp_benchmarkStop(MSP_BENCHMARK_BASE);
               msp_checkStatus(status);
               printf("FFT completed\n");
    
               //Transmit all output values to PC
    
    
           //Calculate and transmit frequencies with maximum amplitudes
           getMaximums(input, SAMPLES, max, amp);
           printf("Max amp frequencies found\n");
    
    
           // Transmit all frequencies via NeoCortec
           printf("Sent freq: \n");
           for(i=0; i<SAMPLES/2; i++)
           {
               printf("%f\n", (float)max[i]);
           }
    
    
           GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);
           // Transmit matching amplitudes
           printf("Sent amp: \n");
           for(i=0; i<SAMPLES/2; i++)
           {
               printf("%f\n", (float)amp[i]);
           }
        }
    }
    
    
    //******************************************************************************
    // Interrupts ******************************************************************
    //******************************************************************************
    
    //I2C Interrupt
    #pragma vector = USCI_B1_VECTOR
    __interrupt void USCI_B1_ISR(void)
    {
      //Must read from UCB1RXBUF
      uint8_t rx_val = 0;
      switch(__even_in_range(UCB1IV, USCI_I2C_UCBIT9IFG))
      {
        case USCI_NONE:          break;         // Vector 0: No interrupts
        case USCI_I2C_UCALIFG:   break;         // Vector 2: ALIFG
        case USCI_I2C_UCNACKIFG:                // Vector 4: NACKIFG
          UCB1CTLW0 |= UCTXSTT;                 // Re-send start if NACK
          break;
        case USCI_I2C_UCSTTIFG:  break;         // Vector 6: STTIFG
        case USCI_I2C_UCSTPIFG:  break;         // Vector 8: STPIFG
        case USCI_I2C_UCRXIFG3:  break;         // Vector 10: RXIFG3
        case USCI_I2C_UCTXIFG3:  break;         // Vector 12: TXIFG3
        case USCI_I2C_UCRXIFG2:  break;         // Vector 14: RXIFG2
        case USCI_I2C_UCTXIFG2:  break;         // Vector 16: TXIFG2
        case USCI_I2C_UCRXIFG1:  break;         // Vector 18: RXIFG1
        case USCI_I2C_UCTXIFG1:  break;         // Vector 20: TXIFG1
        case USCI_I2C_UCRXIFG0:                 // Vector 22: RXIFG0
            rx_val = UCB1RXBUF;
            if (RXByteCtr)
            {
              ReceiveBuffer[ReceiveIndex++] = rx_val;
              RXByteCtr--;
            }
    
            if (RXByteCtr == 1)
            {
              UCB1CTLW0 |= UCTXSTP;
            }
            else if (RXByteCtr == 0)
            {
              UCB1IE &= ~UCRXIE;
              MasterMode = IDLE_MODE;
              __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
            }
            break;
        case USCI_I2C_UCTXIFG0:                 // Vector 24: TXIFG0
            switch (MasterMode)
            {
              case TX_REG_ADDRESS_MODE:
                  UCB1TXBUF = TransmitRegAddr;
                  if (RXByteCtr)
                      MasterMode = SWITCH_TO_RX_MODE;   // Need to start receiving now
                  else
                      MasterMode = TX_DATA_MODE;        // Continue to transmision with the data in Transmit Buffer
                  break;
    
              case SWITCH_TO_RX_MODE:
                  UCB1IE |= UCRXIE;              // Enable RX interrupt
                  UCB1IE &= ~UCTXIE;             // Disable TX interrupt
                  UCB1CTLW0 &= ~UCTR;            // Switch to receiver
                  MasterMode = RX_DATA_MODE;    // State state is to receive data
                  UCB1CTLW0 |= UCTXSTT;          // Send repeated start
                  if (RXByteCtr == 1)
                  {
                      //Must send stop since this is the N-1 byte
                      while((UCB1CTLW0 & UCTXSTT));
                      UCB1CTLW0 |= UCTXSTP;      // Send stop condition
                  }
                  break;
    
              case TX_DATA_MODE:
                  if (TXByteCtr)
                  {
                      UCB1TXBUF = TransmitBuffer[TransmitIndex++];
                      TXByteCtr--;
                  }
                  else
                  {
                      //Done with transmission
                      UCB1CTLW0 |= UCTXSTP;     // Send stop condition
                      MasterMode = IDLE_MODE;
                      UCB1IE &= ~UCTXIE;                       // disable TX interrupt
                      __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
                  }
                  break;
    
              default:
                  __no_operation();
                  break;
            }
            break;
        default: break;
      }
    }
    
    
    #pragma vector = PORT2_VECTOR
    __interrupt void PORT2_ISR(void)
    {
        switch(__even_in_range(P2IV, P2IV_P2IFG7))
           {
               case P2IV_NONE : break;
               case P2IV_P2IFG0 : break;
               case P2IV_P2IFG1 : break;
               case P2IV_P2IFG2 : break;
               case P2IV_P2IFG3 : break;
               case P2IV_P2IFG4 : break;
               case P2IV_P2IFG5 :       //Int2 sensor interrupt
                   P2IFG = P2IFG & ~(BIT2);
                   break;
               case P2IV_P2IFG6 : break;
               case P2IV_P2IFG7 : break;
               default : _never_executed();
           }
    }
    
    
    // Timer_0 Interrupt Service Routine
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void Timer_A0 (void)
    {
        TA0CTL = TA0CTL & (~TAIFG);       // Reset Timer_0 so it keeps counting
    }
    

  • IQmathLibry: q15 and iq31 has a range of -1 to +1. I am not sure how to use these two data types insted of "int16_t".

    Reference:

    software-dl.ti.com/.../usage.html

  • The DSP library FFT function is low level and will not output a frequency in Hertz. It will output a value relative to your sample rate since the sample rate is not known to the function. So to get the frequency in Hertz, you would take the value you get from the function which should be a value < 0.5 and multiply by the rate which you're sampling the data at.

    I'd recommend reading the IQmathLib Users Guide, especially section 2, "Using the Qmath and IQmath Libraries" which explains how floating values are represented in int16_t. int32_t/iq31 can be used if you need more resolution.

    https://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/IQmathLib/01_10_00_05/exports/MSP430-IQmathLib-UsersGuide.pdf

  • Thank you. I have changed the code but even though I have the "QmathLib.h" library included, it is showing me this error:

    Description	Resource	Path	Location	Type
    unresolved symbol _Q15toF, first referenced in ./main.obj	One hour delay4_IQLibrary		 	C/C++ Problem
    

    I still have not multiplied with the sampling rate. Right now, I'm just trying to convert the date received from the "msp_fft_fixed_q15" function to  Q values and print them through the console. Any suggestions?

    Here is my code:

    #define GLOBAL_Q    15
    #include "QmathLib.h"
    #include <msp430.h> 
    #include "driverlib.h"
    #include "DSPLib.h"
    #include <gpio.h>
    #include <intrinsics.h>
    #include <msp430fr5xx_6xxgeneric.h>
    #include <stdint.h>
    #include <stdio.h>
    
    
    //#define GLOBAL_Q    15
    //#include "QmathLib.h"
    _q15 q15FFT;
    _q15 q15Amp;        // Q variables using Q15 type
    volatile float qFFT_out;
    volatile float qAmp_out;
    
    //new
    //#include "myClocks.h"
    //new
    
    //******************************************************************************
    // Defines *********************************************************************
    //******************************************************************************
    //Address if the BMI160
    #define SLAVE_ADDR 0x69
    //Maximum I2C buffer size
    #define MAX_BUFFER_SIZE 20
    
    //Number of FFT samples
    #define SAMPLES 1024
    #define TimeStampSample 10
    /* Declare as persistent to move variable from RAM to FRAM */
    #pragma PERSISTENT(input)
    int16_t input[SAMPLES] = {0}; //Store samples
    
    #pragma PERSISTENT(max)
    int16_t max[SAMPLES] = {0}; //Store frequencies with maximum amplitudes
    
    
    #pragma PERSISTENT(amp)
    int16_t amp[SAMPLES] = {0}; //Store the maximum amplitudes
    
    
    /* Temporary data array for processing */
    DSPLIB_DATA(temp,4)
    /* Declare as persistent to move variable to FRAM */
    #pragma PERSISTENT(temp)
    int16_t temp[3*SAMPLES/2] = {0};
    
    //Global flags for sensor interrupts to avoid interrupt nesting
    volatile int motion_trigger = 0;
    
    /* Benchmark cycle counts */
    volatile uint32_t cycleCount;
    
    //#pragma PERSISTENT(SENSORTIME)
    //volatile int32_t SENSORTIME[SAMPLES] = {0}; //Store samples
    
    
    //new
    
    #define UP              0x0010                          // Timer_A Up mode
    #define CONTINUOUS      0x0020                          // Timer_A Continuous mode
    #define ACLK            0x0100                          // Timer_A SMCLK source
    #define DEVELOPMENT     0x5A80                          // Stop the watchdog timer
    #define BOUNCE_DELAY    0xA000                          // Delay for Button Bounce
    #define MS_10           400                             // Approximate value to count for 10ms
    #define SMCLK           0x0200                          // Timer_A SMCLK source
    
    //new
    
    
    
    //******************************************************************************
    // Frequency Functions *********************************************************
    //******************************************************************************
    
    void bubbleSort(int amp[], int max[], int n)
    {
       int i, j, temp;
       for (i = 0; i < n-1; i++)
       {
           // Last i elements are already in place
           for (j = 0; j < n-i-1; j++)
           {
               if (amp[j] < amp[j+1])
               {
                  temp = max[j];
                  max[j] = max[j+1];
                  max[j+1] = temp;
    
                  temp = amp[j];
                  amp[j] = amp[j+1];
                  amp[j+1] = temp;
               }
           }
       }
    }
    
    void getMaximums(int16_t input[], int samples, int16_t max[], int16_t amp[])
    {
        int i,j = 0;
        for(i=1; i<samples-1; i++)
            {
                if((input[i-1] < input[i]) && (input[i] > input[i+1]))
                {
                    amp[j] = input[i];
                    max[j++] = i;
                }
            }
        bubbleSort(amp, max, samples);
    }
    
    //******************************************************************************
    // Timer Functions *************************************************************
    //******************************************************************************
    
    int delay(int count)
    {
        if(TA1CTL & TAIFG)                                  // If Timer_1 is done counting
        {
            count = count-1;                                        // Decrement count
            TA1CTL = TA1CTL & (~TAIFG);                             // Reset Timer_1
        }
        return count;                                       // Return the value of count
    } // end delay
    //******************************************************************************
    // UART Functions **************************************************************
    //******************************************************************************
    void UART_transmitString( char *pStr ) //Transmits a string over UART0
    {
        while( *pStr )
        {
            while(!(UCA0IFG&UCTXIFG));
            UCA0TXBUF = *pStr;
            pStr++;
        }
    }
    
    //******************************************************************************
    // I2C Functions ***************************************************************
    //******************************************************************************
    typedef enum I2C_ModeEnum{
        IDLE_MODE,
        NACK_MODE,
        TX_REG_ADDRESS_MODE,
        RX_REG_ADDRESS_MODE,
        TX_DATA_MODE,
        RX_DATA_MODE,
        SWITCH_TO_RX_MODE,
        SWITHC_TO_TX_MODE,
        TIMEOUT_MODE
    } I2C_Mode;
    
    /* Used to track the state of the software state machine*/
    I2C_Mode MasterMode = IDLE_MODE;
    
    uint8_t TransmitRegAddr = 0; //Register address for transmission
    uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0}; //Buffer for received values
    uint8_t RXByteCtr = 0; //Count received bytes
    uint8_t ReceiveIndex = 0; //Index of received data
    uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0}; //Buffer for transmitted values
    uint8_t TXByteCtr = 0; //Count transmitted bytes
    uint8_t TransmitIndex = 0; //Index of transmitted data
    
    void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
    {
        uint8_t copyIndex = 0;
        for (copyIndex = 0; copyIndex < count; copyIndex++)
        {
            dest[copyIndex] = source[copyIndex];
        }
    }
    
    I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count)
    {
        //printf("R\n");
        /* Initialize state machine */
        MasterMode = TX_REG_ADDRESS_MODE;
        TransmitRegAddr = reg_addr;
        RXByteCtr = count;
        TXByteCtr = 0;
        ReceiveIndex = 0;
        TransmitIndex = 0;
    
        /* Initialize slave address and interrupts */
        UCB1I2CSA = dev_addr;
        UCB1IFG &= ~(UCTXIFG + UCRXIFG);       // Clear any pending interrupts
        UCB1IE &= ~UCRXIE;                       // Disable RX interrupt
        UCB1IE |= UCTXIE;                        // Enable TX interrupt
    
        UCB1CTLW0 |= UCTR + UCTXSTT;             // I2C TX, start condition
        __bis_SR_register(LPM0_bits + GIE);              // Enter LPM0 w/ interrupts
     //   UCB1IE &= ~UCRXIE;                       // Disable RX interrupt
    
    
        return MasterMode;
    
    }
    
    I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
    {
        /* Initialize state machine */
        MasterMode = TX_REG_ADDRESS_MODE;
        TransmitRegAddr = reg_addr;
    
        //Copy register data to TransmitBuffer
        CopyArray(reg_data, TransmitBuffer, count);
    
        TXByteCtr = count;
        RXByteCtr = 0;
        ReceiveIndex = 0;
        TransmitIndex = 0;
    
        /* Initialize slave address and interrupts */
        UCB1I2CSA = dev_addr;
        UCB1IFG &= ~(UCTXIFG + UCRXIFG);       // Clear any pending interrupts
        UCB1IE &= ~UCRXIE;                       // Disable RX interrupt
        UCB1IE |= UCTXIE;                        // Enable TX interrupt
    
        UCB1CTLW0 |= UCTR + UCTXSTT;             // I2C TX, start condition
        __bis_SR_register(LPM0_bits + GIE);              // Enter LPM0 w/ interrupts
        //printf("W\n");
        return MasterMode;
    }
    
    //******************************************************************************
    // BMI160 Functions ************************************************************
    //******************************************************************************
    void bmi160_init(char FOC_axis)
    {
        uint8_t writeData[1];
        //Read Chip ID, which is D1
        I2C_Master_ReadReg(SLAVE_ADDR, 0x00, 1);
        if(ReceiveBuffer[0] != 0xD1)
        {
            UART_transmitString(" Incorrect sensor chip ID ");
            printf("Incorrect sensor chip ID\n");
        }
    
    
    
    
        //Configure the accelerometer
        writeData[0]=0b00101100; //Set acc_us to 0 for off, and acc_bwp must then be 010. Set acc_odr to 1011(800Hz),1100(1600Hz),1000(100Hz),0001(25/32Hz)
        I2C_Master_WriteReg(SLAVE_ADDR, 0x40, writeData, 1);
        //Check if configuration worked
        I2C_Master_ReadReg(SLAVE_ADDR, 0x40, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Accelerometer config failed ");
            printf("Accelerometer config failed\n");
        }
        //Set the range of the accelerometer
        writeData[0]=0b1000; //0b0011 for 2g, 0b0101 for 4g, 0b1000 for 8g
        I2C_Master_WriteReg(SLAVE_ADDR, 0x41, writeData, 1);
        //Check if range is set
        I2C_Master_ReadReg(SLAVE_ADDR, 0x41, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Accelerometer range set failed ");
            printf("Accelerometer range set failed\n");
        }
    
        //Any motion setup
    
        //Set the successive slope threshold
        writeData[0]=0b00000001; //0b00000001 + 1 so two successive slopes
        I2C_Master_WriteReg(SLAVE_ADDR, 0x5F, writeData, 1);
        //Check if slope threshold is set
        I2C_Master_ReadReg(SLAVE_ADDR, 0x5F, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Slope threshold not set ");
            printf("Slope threshold not set\n");
        }
        //Set trigger level
        writeData[0]=0b01001101; //15.63mg*value for 8g range, 0b00000000 gives 7.81mg
        I2C_Master_WriteReg(SLAVE_ADDR, 0x60, writeData, 1);
        //Check trigger is set
        I2C_Master_ReadReg(SLAVE_ADDR, 0x60, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Trigger not set ");
            printf("Trigger not set\n");
        }
    
        //Double tap setup
    
        //Set single and double tap timings
        writeData[0] = 0b00000110; //Quiet of 30ms, shock of 50ms, double tap within 500ms
        I2C_Master_WriteReg(SLAVE_ADDR, 0x63, writeData, 1);
        //Read the timings
        I2C_Master_ReadReg(SLAVE_ADDR, 0x63, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Tap timings not set ");
            printf("Tap timings not set\n");
        }
        //Set tap threshold
        writeData[0] = 0b0000; //125mg threshold
        I2C_Master_WriteReg(SLAVE_ADDR, 0x64, writeData, 1);
        //Read the threshold
        I2C_Master_ReadReg(SLAVE_ADDR, 0x64, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Tap timings not set ");
            printf("Tap timings not set\n");
        }
    
        //Interrupt setup
    
        //Enable any-motion and double tap interrupts
        writeData[0] = 0b00010100; //Enables double tap and any-motion z interrupt
        I2C_Master_WriteReg(SLAVE_ADDR, 0x50, writeData, 1);
        //Read interrupt enable status
        I2C_Master_ReadReg(SLAVE_ADDR, 0x50, 1);
        if(ReceiveBuffer[0] != 0b00010100)
        {
            UART_transmitString("Interrupts not enabled");
            printf("Interrupts not enabled\n");
        }
        //Set pins
        writeData[0] = 0b10001000; //Output, push-pull, active low for int1 and int2
        I2C_Master_WriteReg(SLAVE_ADDR, 0x53, writeData, 1);
        //Read pin status
        I2C_Master_ReadReg(SLAVE_ADDR, 0x53, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Pins not set ");
            printf("Pins not set\n");
        }
        //Set interrupts to temporary instead of latched (permanent till cleared)
        writeData[0] = 0b1101; //Temp for 1.28s
        I2C_Master_WriteReg(SLAVE_ADDR, 0x54, writeData, 1);
        //Check interrupts
        I2C_Master_ReadReg(SLAVE_ADDR, 0x54, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Interrupts not temp ");
            printf("Interrupts not temp");
        }
        //Map any motion detection to Int1
        writeData[0] = 0b00000100; //Mapped any motion to int1
        I2C_Master_WriteReg(SLAVE_ADDR, 0x55, writeData, 1);
        //Check interrupt
        I2C_Master_ReadReg(SLAVE_ADDR, 0x55, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Any motion not mapped ");
            printf("Any motion not mapped\n");
        }
        //Map double tap to Int2
        writeData[0] = 0b00010000; //Mapped double tap to int2
        I2C_Master_WriteReg(SLAVE_ADDR, 0x57, writeData, 1);
        //Check interrupt
        I2C_Master_ReadReg(SLAVE_ADDR, 0x57, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Double tap not mapped ");
            printf("Double tap not mapped\n");
        }
        //Set tap data filtering
        writeData[0] = 0b1000; //Filtered data instead of pre-filtered
        I2C_Master_WriteReg(SLAVE_ADDR, 0x58, writeData, 1);
        //Check filtering
        I2C_Master_ReadReg(SLAVE_ADDR, 0x58, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Filter not set ");
            printf("Filter not set\n");
        }
        //Set the Accelerometer to normal power mode
        writeData[0] = 0x11;
        I2C_Master_WriteReg(SLAVE_ADDR, 0x7E, writeData, 1);
        //Read power mode status of sensors
        I2C_Master_ReadReg(SLAVE_ADDR, 0x03, 1);
        if(ReceiveBuffer[0] != 0x10)
        {
            UART_transmitString(" Accelerometer not on ");
            printf("Accelerometer not on\n");
        }
    
        //Fast Offset Compensation (FOC) setup
    
        //0 for reserved, 0 for gyroscope, 00 for x, 00 for y, 0 for z (10 = -1g, 00 = 0g, 01 = 1g)
        switch(FOC_axis)
        {
            case 'X':
                writeData[0] = 0b00100000;
                break;
            case 'Y':
                writeData[0] = 0b00001000;
                break;
            case 'Z':
                writeData[0] = 0b00000010;
                break;
            default:
                writeData[0] = 0b00000000; //Default of all 0g
                break;
        }
        I2C_Master_WriteReg(SLAVE_ADDR, 0x69, writeData, 1);
        //Check FOC
        I2C_Master_ReadReg(SLAVE_ADDR, 0x69, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" FOC not set ");
            printf("Incorrect sensor chip ID\n");
        }
        //Start FOC
        writeData[0] = 0x03;
        I2C_Master_WriteReg(SLAVE_ADDR, 0x7E, writeData, 1);
        //Wait until FOC is finished
        int finish = 0;
        while(finish==0)
        {
            I2C_Master_ReadReg(SLAVE_ADDR, 0x1B, 1);
            if((ReceiveBuffer[0] & 0b00001000) == 0b00001000)
            {
                finish = 1;
            }
        }
        //Enable offset compensation
        writeData[0] = 0b01000000; //Enable accelerometer offset compensation
        I2C_Master_WriteReg(SLAVE_ADDR, 0x77, writeData, 1);
        //Check offset compensation
        I2C_Master_ReadReg(SLAVE_ADDR, 0x77, 1);
        if(ReceiveBuffer[0] != writeData[0])
        {
            UART_transmitString(" Offset not enabled ");
            printf("Incorrect sensor chip ID\n");
        }
        //UART_transmitString(" BMI160 Initialized \n");
    }
    
    
    
    //******************************************************************************
    // Device Initialization *******************************************************
    //******************************************************************************
    void initGPIO()
    {
        /* Terminate all GPIO pins to Output LOW to minimize power consumption */
        GPIO_setAsOutputPin(GPIO_PORT_PA, GPIO_PIN_ALL16);
        GPIO_setAsOutputPin(GPIO_PORT_PB, GPIO_PIN_ALL16);
        GPIO_setAsOutputPin(GPIO_PORT_PC, GPIO_PIN_ALL16);
        GPIO_setAsOutputPin(GPIO_PORT_PD, GPIO_PIN_ALL16);
        GPIO_setAsOutputPin(GPIO_PORT_PE, GPIO_PIN_ALL16);
        GPIO_setAsOutputPin(GPIO_PORT_PF, GPIO_PIN_ALL16);
        GPIO_setOutputLowOnPin(GPIO_PORT_PA, GPIO_PIN_ALL16);
        GPIO_setOutputLowOnPin(GPIO_PORT_PB, GPIO_PIN_ALL16);
        GPIO_setOutputLowOnPin(GPIO_PORT_PC, GPIO_PIN_ALL16);
        GPIO_setOutputLowOnPin(GPIO_PORT_PD, GPIO_PIN_ALL16);
        GPIO_setOutputLowOnPin(GPIO_PORT_PE, GPIO_PIN_ALL16);
        GPIO_setOutputLowOnPin(GPIO_PORT_PF, GPIO_PIN_ALL16);
    
        // I2C pins (P4.0 is SDA, P4.1 is SCL)
        P4SEL1 |= BIT0 | BIT1;
        P4SEL0 &= ~(BIT0 | BIT1);
    
        // Configure P3.4 and P3.5 to UART (Primary, TX and RX respectively) for NeoCortec
        P3SEL0 |= BIT4 | BIT5;                    // USCI_A1 UART operation
        P3SEL1 &= ~(BIT4 | BIT5);                 // SEL1 is 0 and SEL0 is 1 for primary operation, inverse for secondary
    
        // Configure P2.0 and P2.1 to UART (Primary, TX and RX respectively) for PC
        P2SEL0 |= BIT0 | BIT1;                    // USCI_A0 UART operation
        P2SEL1 &= ~(BIT0 | BIT1);                 // SEL1 is 0 and SEL0 is 1 for primary operation, inverse for secondary
    
        // Configure button S1 (P1.1) interrupt
        GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN1, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1);
        GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN1);
        GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1);
    
        // Configure button S2 (P1.2) interrupt
        GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN2);
        GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN2);
        GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN2);
    
        // Configure CTS active (P1.3) interrupt
        GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN3, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN3);
        GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN3);
        GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN3);
    
        // Configure Nwu (P1.4) interrupt
        GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN4);
        GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN4);
        GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN4);
    
        // Configure INT1 (P3.2) interrupt
        GPIO_selectInterruptEdge(GPIO_PORT_P3, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P3, GPIO_PIN2);
        GPIO_clearInterrupt(GPIO_PORT_P3, GPIO_PIN2);
        GPIO_enableInterrupt(GPIO_PORT_P3, GPIO_PIN2);
    
        // Configure INT2 (P2.5) interrupt
        GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN5, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN5);
        GPIO_clearInterrupt(GPIO_PORT_P2, GPIO_PIN5);
        GPIO_enableInterrupt(GPIO_PORT_P2, GPIO_PIN5);
    
        // Disable the GPIO power-on default high-impedance mode to activate
        // previously configured port settings
        PM5CTL0 &= ~LOCKLPM5;
        __bis_SR_register(GIE);
    }
    
    void initClockTo16MHz()
    {
        // Configure one FRAM waitstate as required by the device datasheet for MCLK
        // operation beyond 8MHz _before_ configuring the clock system.
        FRCTL0 = FRCTLPW | NWAITS_1;
    
        // Clock System Setup
        CSCTL0_H = CSKEY_H;                     // Unlock CS registers
        CSCTL1 = DCOFSEL_0;                     // Set DCO to 1MHz
    
        // Set SMCLK = MCLK = DCO, ACLK = VLOCLK (9.4kHz)
        CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
    
        // Per Device Errata set divider to 4 before changing frequency to
        // prevent out of spec operation from overshoot transient
        CSCTL3 = DIVA__4 | DIVS__4 | DIVM__4;   // Set all corresponding clk sources to divide by 4 for errata
        CSCTL1 = DCOFSEL_4 | DCORSEL;           // Set DCO to 16MHz
    
        // Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz))
        __delay_cycles(60);
        CSCTL3 = DIVA__32 | DIVS__1 | DIVM__1;  // Set ACLK to 239.75Hz, SMCLK to 16MHz, and MCLK to 16MHz
        CSCTL0_H = 0;                           // Lock CS registers
    }
    
    void initI2C()
    {
        UCB1CTLW0 = UCSWRST;                      // Enable SW reset
        UCB1CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSYNC; // I2C master mode, SMCLK
        UCB1BRW = 160;                            // fSCL = ACLK/160 = ~100kHz
        UCB1I2CSA = SLAVE_ADDR;                   // Slave Address
        UCB1CTLW0 &= ~UCSWRST;                    // Clear SW reset, resume operation
        UCB1IE |= UCNACKIE;
    }
    
    void UART_init(void)
    {
        // Configure USCI_A1 for UART mode
        UCA1CTLW0 = UCSWRST;                      // Put eUSCI in reset
        UCA1CTLW0 |= UCSSEL__SMCLK;               // CLK = SMCLK
        UCA1BR0 = 8;                              // Clock prescaler set to 8
        UCA1BR1 = 0x00;                           // High byte empty, low byte is 8
        UCA1MCTLW |= UCOS16 | UCBRF_10 | 0xF700;  // Over-sampling on, first modulation register set to 10, second modulation register set to 0xF7 (247) for high byte, 0 for low byte
        UCA1CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
        UCA1IE |= UCRXIE;                         // Enable USCI_A1 RX interrupt
    
        // Configure USCI_A0 for UART mode
        UCA0CTLW0 = UCSWRST;                      // Put eUSCI in reset
        UCA0CTLW0 |= UCSSEL__SMCLK;               // CLK = SMCLK
        UCA0BR0 = 8;                              // Clock prescaler set to 8
        UCA0BR1 = 0x00;                           // High byte empty, low byte is 8
        UCA0MCTLW |= UCOS16 | UCBRF_10 | 0xF700;  // Over-sampling on, first modulation register set to 10, second modulation register set to 0xF7 (247) for high byte, 0 for low byte
        UCA0CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
        UCA0IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt
    }
    
    
    
    //******************************************************************************
    // Main ************************************************************************
    //******************************************************************************
    
     int main(void)
     {
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
        //Initialize all peripherals
        initClockTo16MHz();
        initGPIO();
        UART_init();
        initI2C();
    
        bmi160_init('Z');
    
        // Initialize the FFT parameters
        msp_status status;
        msp_fft_q15_params fftParams;
    
        /* Initialize the fft parameter structure. */
        fftParams.length = SAMPLES;
        fftParams.bitReverse = true;
        fftParams.twiddleTable = msp_cmplx_twiddle_table_4096_q15; //Twiddle table for 4096 values
    
    
        int i = 0;
    
        //new
        TA0CTL   = TA0CTL | (SMCLK + CONTINUOUS);           // SMCLK:  Counts faster than ACLK
                                                            // CONTINUOUS:  Count 0 to 0xFFFF
        TA0CCTL0 = CCIE;                                    // Timer_0 interrupt
    
        TA1CTL   = TA1CTL | (ACLK  + UP         );          // Count up from 0 with ACLK
        TA1CCR0  = MS_10;                                   // Duration approximatley 10ms
    
        _BIS_SR(GIE);                                       // Activate all interrupts
    
        //new
    
        while(1)
        {
               printf("Reading samples\n");
               //Read SAMPLES amount of data from the BMI160
               for(i=0;i<SAMPLES;i++)
               {
                   I2C_Master_ReadReg(SLAVE_ADDR, 0x16, 2); //Read the acceleration value from the BMI160 registers
                   input[i]= ReceiveBuffer[0] | (ReceiveBuffer[1] << 8); //Store the value in an array
                   //I2C_Master_ReadReg(SLAVE_ADDR, 0x18, 3); //Read the acceleration value from the BMI160 registers
                   //SENSORTIME[i] = ((uint32_t)ReceiveBuffer[2] << 16) | ((uint32_t)ReceiveBuffer[1] << 8) | ((uint32_t)ReceiveBuffer[0] << 0);
                   //delay_ms(1); //Determines sampling frequency, up to 10kHz
                   //__delay_cycles(4500);
                   //printf("Sent acc: %u\n",input[i]);
               }
               printf("Samples read\n");
    
    
               msp_benchmarkStart(MSP_BENCHMARK_BASE, 16);
               status = msp_fft_fixed_q15(&fftParams, input); //Perform FFT
               cycleCount = msp_benchmarkStop(MSP_BENCHMARK_BASE);
               msp_checkStatus(status);
               printf("FFT completed\n");
    
               //Transmit all output values to PC
    
    
           //Calculate and transmit frequencies with maximum amplitudes
           getMaximums(input, SAMPLES, max, amp);
           printf("Max amp frequencies found\n");
    
    
           ////Print timestamp to calculate the accurate sampling frequency
           //printf("Sent SENSORTIME: \n");
           //for(i=0; i<SAMPLES/2; i++)
           //{
           //    printf("%u\n", (unsigned int)SENSORTIME[i]);
           //}
    
    
    
           // Transmit all frequencies via NeoCortec
           printf("Sent freq: \n");
           for(i=0; i<6; i++)
           {
    
               q15FFT =  _Q(max[i]);
               qFFT_out =_Q15toF(q15FFT);
               printf("%f\n", qFFT_out);
           }
    
    
           GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);
           // Transmit matching amplitudes
           printf("Sent amp: \n");
           for(i=0; i<6; i++)
           {
    
               q15Amp =  _Q(amp[i]);
               qAmp_out =_Q15toF(q15Amp);
               printf("%f\n", qAmp_out);
           }
        }
    }
    
    
    //******************************************************************************
    // Interrupts ******************************************************************
    //******************************************************************************
    
    //I2C Interrupt
    #pragma vector = USCI_B1_VECTOR
    __interrupt void USCI_B1_ISR(void)
    {
      //Must read from UCB1RXBUF
      uint8_t rx_val = 0;
      switch(__even_in_range(UCB1IV, USCI_I2C_UCBIT9IFG))
      {
        case USCI_NONE:          break;         // Vector 0: No interrupts
        case USCI_I2C_UCALIFG:   break;         // Vector 2: ALIFG
        case USCI_I2C_UCNACKIFG:                // Vector 4: NACKIFG
          UCB1CTLW0 |= UCTXSTT;                 // Re-send start if NACK
          break;
        case USCI_I2C_UCSTTIFG:  break;         // Vector 6: STTIFG
        case USCI_I2C_UCSTPIFG:  break;         // Vector 8: STPIFG
        case USCI_I2C_UCRXIFG3:  break;         // Vector 10: RXIFG3
        case USCI_I2C_UCTXIFG3:  break;         // Vector 12: TXIFG3
        case USCI_I2C_UCRXIFG2:  break;         // Vector 14: RXIFG2
        case USCI_I2C_UCTXIFG2:  break;         // Vector 16: TXIFG2
        case USCI_I2C_UCRXIFG1:  break;         // Vector 18: RXIFG1
        case USCI_I2C_UCTXIFG1:  break;         // Vector 20: TXIFG1
        case USCI_I2C_UCRXIFG0:                 // Vector 22: RXIFG0
            rx_val = UCB1RXBUF;
            if (RXByteCtr)
            {
              ReceiveBuffer[ReceiveIndex++] = rx_val;
              RXByteCtr--;
            }
    
            if (RXByteCtr == 1)
            {
              UCB1CTLW0 |= UCTXSTP;
            }
            else if (RXByteCtr == 0)
            {
              UCB1IE &= ~UCRXIE;
              MasterMode = IDLE_MODE;
              __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
            }
            break;
        case USCI_I2C_UCTXIFG0:                 // Vector 24: TXIFG0
            switch (MasterMode)
            {
              case TX_REG_ADDRESS_MODE:
                  UCB1TXBUF = TransmitRegAddr;
                  if (RXByteCtr)
                      MasterMode = SWITCH_TO_RX_MODE;   // Need to start receiving now
                  else
                      MasterMode = TX_DATA_MODE;        // Continue to transmision with the data in Transmit Buffer
                  break;
    
              case SWITCH_TO_RX_MODE:
                  UCB1IE |= UCRXIE;              // Enable RX interrupt
                  UCB1IE &= ~UCTXIE;             // Disable TX interrupt
                  UCB1CTLW0 &= ~UCTR;            // Switch to receiver
                  MasterMode = RX_DATA_MODE;    // State state is to receive data
                  UCB1CTLW0 |= UCTXSTT;          // Send repeated start
                  if (RXByteCtr == 1)
                  {
                      //Must send stop since this is the N-1 byte
                      while((UCB1CTLW0 & UCTXSTT));
                      UCB1CTLW0 |= UCTXSTP;      // Send stop condition
                  }
                  break;
    
              case TX_DATA_MODE:
                  if (TXByteCtr)
                  {
                      UCB1TXBUF = TransmitBuffer[TransmitIndex++];
                      TXByteCtr--;
                  }
                  else
                  {
                      //Done with transmission
                      UCB1CTLW0 |= UCTXSTP;     // Send stop condition
                      MasterMode = IDLE_MODE;
                      UCB1IE &= ~UCTXIE;                       // disable TX interrupt
                      __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
                  }
                  break;
    
              default:
                  __no_operation();
                  break;
            }
            break;
        default: break;
      }
    }
    
    
    #pragma vector = PORT2_VECTOR
    __interrupt void PORT2_ISR(void)
    {
        switch(__even_in_range(P2IV, P2IV_P2IFG7))
           {
               case P2IV_NONE : break;
               case P2IV_P2IFG0 : break;
               case P2IV_P2IFG1 : break;
               case P2IV_P2IFG2 : break;
               case P2IV_P2IFG3 : break;
               case P2IV_P2IFG4 : break;
               case P2IV_P2IFG5 :       //Int2 sensor interrupt
                   P2IFG = P2IFG & ~(BIT2);
                   break;
               case P2IV_P2IFG6 : break;
               case P2IV_P2IFG7 : break;
               default : _never_executed();
           }
    }
    
    
    // Timer_0 Interrupt Service Routine
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void Timer_A0 (void)
    {
        TA0CTL = TA0CTL & (~TAIFG);       // Reset Timer_0 so it keeps counting
    }
    
    

  • You need to include the QMath library in your linker File Search Path.

    Project Properties -> CCS Build -> MSP430 Linker -> File Search Path

    In the "Include library file or command file as input" section, add the location of your QmathLib.a file. On my machine, it is located in the location in the screenshot. Note that there is both an IQmathLib.a and a QmathLib.a. Since you are using Qmath, add the "QmathLib.a" file.

**Attention** This is a public forum