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.

CCS/DK-TM4C129X: FFT of analog signal using CMSIS DSP library

Part Number: DK-TM4C129X

Tool/software: Code Composer Studio

Hey,

I am new with this CMSIS DSP library functions. I am currently working on a project that involves computing FFT of external analog signal by function generator. I have successfully sampled the analog signal using ADC triggered by TIMER and used DMA to store the values in an 1024 length array "g_ui8RxBufA". Now, I want to compute the FFT of this signal. I built the CMSIS DSP library successfully and ran the examples given there. I ran the FFT example given in there that calculates FFT of test data signal. I want to proceed like that only. So, the output "g_ui8RxBufA" array, I added 0 value at every odd index of array by using for loop as shown in code (as array indexing starts from 0) to form array " testInput_f32_10khz" (of length 2048) and followed same procedure as in example. But when I ran the code, all the values of " testInput_f32_10khz" array were 0. Somehow, the values are not transferring from "g_ui8RxBufA" array. Can anyone please point out the flaw in the code?

Main function:

 uint32_t sysclock;

        sysclock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |

                                              SYSCTL_OSC_MAIN |

                                              SYSCTL_USE_PLL |

                                              SYSCTL_CFG_VCO_480), 120000000);


     SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);

     while(!(SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA)));

     SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);

     IntMasterEnable();

      IntEnable(INT_UDMAERR);

      uDMAEnable();

      uDMAControlBaseSet(pui8ControlTable);

      InitUART1Transfer(sysclock);

      //FFT begins
      uint32_t i;

      for(i = 0; i < 1024; i++)
      {
    	  //if(i % 2 == 0)
    		  testInput_f32_10khz[2*i] = g_ui8RxBufA[i];
    	  //else
    	  	  testInput_f32_10khz[2*i + 1] = 0;
      }


      /* ----------------------------------------------------------------------
      * Max magnitude FFT Bin test
      * ------------------------------------------------------------------- */

      //int32_t main(void)
      //{

        arm_status status;
        float32_t maxValue;

        status = ARM_MATH_SUCCESS;

        /* Process the data through the CFFT/CIFFT module */
        arm_cfft_f32(&arm_cfft_sR_f32_len1024, testInput_f32_10khz, ifftFlag, doBitReverse);

        /* Process the data through the Complex Magnitude Module for
        calculating the magnitude at each bin */
        arm_cmplx_mag_f32(testInput_f32_10khz, testOutput, fftSize);

        /* Calculates maxValue and returns corresponding BIN value */
        arm_max_f32(testOutput, fftSize, &maxValue, &testIndex);

        if (testIndex !=  refIndex)
        {
          status = ARM_MATH_TEST_FAILURE;
        }

        /* ----------------------------------------------------------------------
        ** Loop here if the signals fail the PASS check.
        ** This denotes a test failure
        ** ------------------------------------------------------------------- */

        if ( status != ARM_MATH_SUCCESS)
        {
          while (1);
        }

        //FFT ends
     //   while (1);                             /* main function does not return */
    while(1)
    {

    }

InitUART1Transfer() function:

	uint32_t ui32Period;
    //uint32_t div;

    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    while(!(SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0)));

    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_ADC0);

    //ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);
   // ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 30);
    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 24);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

    while(!(SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE)));

    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);

    //ADCSequenceConfigure(ADC0_BASE, 0 /*SS0*/, ADC_TRIGGER_ALWAYS, 3 /*priority*/);  // SS0-SS3 priorities must always be different
    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);

    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 | ADC_CTL_IE |
                             ADC_CTL_END);

    ADCSequenceEnable(ADC0_BASE, 0);

    ADCIntClear(ADC0_BASE, 0);

    // Enable the Timer peripheral
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

    // Timer should run periodically
    TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);

    // Set the value that is loaded into the timer everytime it finishes
    //   it's the number of clock cycles it takes till the timer triggers the ADC
    //#define F_SAMPLE    1000
    ui32Period = 120000000/1024000;
    TimerLoadSet(TIMER0_BASE, TIMER_A, ui32Period-1);

    // Enable triggering
    TimerControlTrigger(TIMER0_BASE, TIMER_A, true);

    ADCIntEnable(ADC0_BASE, 0);

    // Enable the timer
    TimerEnable(TIMER0_BASE, TIMER_A);

    ADCSequenceDMAEnable(ADC0_BASE, 0);

    uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0,

                                    UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |

                                    UDMA_ATTR_HIGH_PRIORITY |

                                    UDMA_ATTR_REQMASK);

    uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,

                            UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_NEXT_USEBURST |

                              UDMA_ARB_1024);

    uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT,

                            UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_NEXT_USEBURST |

                            UDMA_ARB_1024);

    uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,

                               UDMA_MODE_PINGPONG,

                               (void *)(ADC0_BASE + ADC_O_SSFIFO0),

                               g_ui8RxBufA, MEM_BUFFER_SIZE);


    uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT,

                                UDMA_MODE_PINGPONG,

                                (void *)(ADC0_BASE + ADC_O_SSFIFO0),

                                g_ui8RxBufB, MEM_BUFFER_SIZE);

    uDMAChannelEnable(UDMA_CHANNEL_ADC0);

    ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS0);

    IntEnable(INT_ADC0SS0);

 

 

  • Is your array "testInput_f32_10khz" of type "float" and you are doing an implicit conversion from unsigned char to float in the assignment:

     testInput_f32_10khz[2*i] = g_ui8RxBufA[i];

  • Hey Bob,

    Yes, you are right. Those two arrays are defined as:

    static uint32_t g_ui8RxBufA[MEM_BUFFER_SIZE];
    static float32_t testInput_f32_10khz[TEST_LENGTH_SAMPLES];

    My values that are coming from uDMA in array "g_ui8RxBufA" are in unsigned int. I saw in the FFT function documentation of CMSIS DSP library that those functions take float32 as input data. So, now to convert uint32_t to float32_t array, I first tried with type cast:



    testInput_f32_10khz[2*i] = (float32_t) g_ui8RxBufA[i];

    But this didnt work. So, I searched in CMSIS library. and used there arm_q31_to_float() function to convert 32bit integer to float32. That didnt work either. I am attaching my whole code below. Can you suggest what to do to convert uint32 to float32 or maybe some other way by which fft can be calculated?

    Regards,

    Harshul

  • Hey, I tried something else that I found on internet about this conversion thing. I first changes uint32_t to q31_t and then by arm function converted q31_t to float32_t and then generated the array for fft calculation. But, when I ran the code, still all the values in buffer were 0.The values were 0 and also when I pause after some seconds, the code goes to ADCseq0handler defined in coded and from there steps into udma.c file and goes back and forth. Never reaches the for loop in main. But I tried a different approach after this. I manually step over into main file in each function and when it came to for loop, I stepped into it and kept stepping on 1024 times (time consuming) and did this for all loops, after this atleast the buffers had some values (testInput_f32_10khz had correct values; i think). Why is ths happening that when I run the code it goes in ADC interrupt handler rather than in for loop? Can you please point out any errors in code and suggest solution to that?

    Here is my whole code:

    2021.single_ended.c
    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_adc.h"
    #include "inc/hw_types.h"
    #include "inc/hw_udma.h"
    #include "inc/hw_emac.h"
    #include "driverlib/debug.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "driverlib/adc.h"
    #include "driverlib/udma.h"
    #include "driverlib/emac.h"
    #include "driverlib/timer.h"
    #include "arm_math.h"
    #include "arm_const_structs.h"
    uint32_t gui32ADC0Value[2];
    uint32_t gui32ADC1Value[2];
    volatile uint32_t gui32ADCIntDone[2];
    #pragma DATA_ALIGN(pui8ControlTable, 1024)
    uint8_t pui8ControlTable[1024];
    #define MEM_BUFFER_SIZE 1024
    static uint32_t g_ui8RxBufA[MEM_BUFFER_SIZE];
    static float32_t g_ui8RxBufAf32[MEM_BUFFER_SIZE];
    static uint32_t g_ui8RxBufB[MEM_BUFFER_SIZE];
    static q31_t BufferQ31[MEM_BUFFER_SIZE];
    #define TEST_LENGTH_SAMPLES 2048
    /* -------------------------------------------------------------------
    * External Input and Output buffer Declarations for FFT Bin Example
    * ------------------------------------------------------------------- */
    static float32_t testInput_f32_10khz[TEST_LENGTH_SAMPLES];
    static float32_t testOutput[TEST_LENGTH_SAMPLES/2];
    /* ------------------------------------------------------------------
    * Global variables for FFT Bin Example
    * ------------------------------------------------------------------- */
    uint32_t fftSize = 1024;
    uint32_t ifftFlag = 0;
    uint32_t doBitReverse = 1;
    /* Reference index at which max energy of bin ocuurs */
    uint32_t refIndex = 213, testIndex = 0;
    //*****************************************************************************
    //
    //! <h1>Single Ended ADC (single_ended)</h1>
    //
    //*****************************************************************************
    void uDMAErrorHandler(void)
    {
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Regards,

    Harshul

  • I have sampled the external signal correctly using the code attached below. I want to calculate the FFT of that buffer by CMSIS DSP library function, I tried exporting the sampled data to dat file and then inporting dat file into another project that computes fft of that data. That worked out pretty well. But I want to incorporate the FFT algorithm in ADC project, how to do that? I mean the buffers are filling and emptying at a fast rate (1024khz sample rate and 1024 samples, so 1ms time to fill the buffer), so,  I have to compute FFT of the buffer just when it is filled completely (any of the 2 buffers). Can someone please help with this stuff and suggest as to where do I have to change in code for FFT?

    8306.single_ended.c
    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_adc.h"
    #include "inc/hw_types.h"
    #include "inc/hw_udma.h"
    #include "inc/hw_emac.h"
    #include "driverlib/debug.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "driverlib/adc.h"
    #include "driverlib/udma.h"
    #include "driverlib/emac.h"
    #include "driverlib/timer.h"
    #include "arm_math.h"
    #include "arm_const_structs.h"
    uint32_t gui32ADC0Value[2];
    uint32_t gui32ADC1Value[2];
    volatile uint32_t gui32ADCIntDone[2];
    #pragma DATA_ALIGN(pui8ControlTable, 1024)
    uint8_t pui8ControlTable[1024];
    #define MEM_BUFFER_SIZE 1024
    static uint32_t g_ui8RxBufA[MEM_BUFFER_SIZE];
    static float32_t fftout[MEM_BUFFER_SIZE];
    static float32_t fftin[MEM_BUFFER_SIZE];
    static uint32_t g_ui8RxBufB[MEM_BUFFER_SIZE];
    static q31_t BufferQ31[MEM_BUFFER_SIZE];
    //#define TEST_LENGTH_SAMPLES 2048
    /* -------------------------------------------------------------------
    * External Input and Output buffer Declarations for FFT Bin Example
    * ------------------------------------------------------------------- */
    //static float32_t testInput_f32_10khz[TEST_LENGTH_SAMPLES];
    //static float32_t testOutput[TEST_LENGTH_SAMPLES/2];
    ///* ------------------------------------------------------------------
    //* Global variables for FFT Bin Example
    //* ------------------------------------------------------------------- */
    //uint32_t fftSize = 1024;
    //uint32_t ifftFlag = 0;
    //uint32_t doBitReverse = 1;
    //
    ///* Reference index at which max energy of bin ocuurs */
    //uint32_t refIndex = 213, testIndex = 0;
    ////*****************************************************************************
    //
    //! <h1>Single Ended ADC (single_ended)</h1>
    //
    uint32_t g_ui32uDMAErrCount = 0;
    //*****************************************************************************
    void uDMAErrorHandler(void)
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX