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:使用 MSPDSP 库进行浮点运算以精确测量 FFT (MSP430)

Guru**** 1630130 points
Other Parts Discussed in Thread: MSP430FR6889
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1138036/msp430fr6889-floating-point-operation-with-the-mspdsp-library-to-measure-fft-accurately-msp430

器件型号:MSP430FR6889

您好!

我正在使用基于 BMI160的传感器 Booster Pack 和 MSP430FR6889 Launchpad。 我正在尝试使用 MSPDSP 库对 BMI160加速计数据执行 FFT。 我正在使用一个在3.3至3.5 Hz 之间振动的平台。 不过、FFT 算法只会生成整数。 是否可以使用浮点数据类型来获得更精确的值? 在这种情况下、如何更改库或代码以获得更准确的结果?

谢谢你。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    MSP430内核没有 FPU 模块、因此我们不支持浮点运算。

    您可以使用 DSPLIB 运行 IQMath 格式的 FFT。

    谢谢!

    此致

    Johson

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Johson、

    感谢你的答复。 我正在使用"MSP_FFT_FIXED_Q15"函数来执行 FFT、但我仍会获取整数值作为输出。 我正在使用 CCS 的控制台串行打印数据。

    代码如下:

    #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和 IQ31的范围为-1至+1。 我不确定如何使用"int16_t"中的这两种数据类型。

    参考:

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

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    DSP 库 FFT 函数为低电平、不会以赫兹为单位输出频率。 由于函数不知道采样率、因此它将输出一个与采样率相关的值。  因此、要以赫兹为单位获取频率、您需要从函数中获取的值应为小于0.5的值、并乘以采样数据的速率。

    我建议阅读 IQmathLib 用户指南、尤其是第2节"使用 Qmath 和 IQmath 库"、其中介绍了如何在 int16_t 中表示浮点值 如果需要更高的分辨率、可以使用 int32_t/iq31。

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

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢你。 我已更改代码、但即使包含"QmathLib.h"库、它也会显示此错误:

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

    我仍然没有乘以采样率。 现在、我只是尝试将从"MSP_FFT_FIXED_Q15"函数接收的日期转换为 Q 值、并通过控制台打印这些值。 有什么建议吗?

    以下是我的代码:

    #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
    }
    
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您 需要在链接器文件搜索路径中包含 QMath 库。

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

    在"Include library file or command file as input"部分中、添加 QmathLib.a 文件的位置。 在我的机器上、它位于屏幕截图中的位置。 请注意、IQmathLib.a 和 QmathLib.a. 由于您使用的是 Qmath、请添加"QmathLib.a"文件。