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.

Most efficient implementation of FFT on TMS320F280025C

Part Number: TMS320F280025
Other Parts Discussed in Thread: C2000WARE,

I want to implement a 64 point FFT of grid voltage on TMS320F280025 controller. I plan to take 64 equally spaced samples in one cycle of a 50 Hz grid voltage and calculate its FFT. The process should run continuously on each new cycle data. I know that there are DSP libraries in the control suite. There is time critical control code running in the controller that is already occupying around 70% of controller bandwidth.
 In this regard, I have the following queries:
1-  Considering processing time as the main performance criteria, should I go for fixed point implementation or floating point. I am asking because this controller has a 32-bit FPU unit.
2- Should I use Complex FFT or Real FFT functions?. As all data is coming from ADC and is real so is there any reason to use Complex FFT?  
3- It will be nice to have a linker command file for this controller for FFT data blocks (for e.g. twiddle factors) mapping into FLASH. 
4- Is there any document besides the example projects to help understanding the use of FFT library functions.

  • Hi Asad,

    1-  Considering processing time as the main performance criteria, should I go for fixed point implementation or floating point. I am asking because this controller has a 32-bit FPU unit.

    64 point RFFT using fixed point takes 313 cycles and 64 bit RFFT using FPU takes 1281 cycles so for your use-case, I would recommend using the fixed point implementation. You can find detailed benchmarking information in the docs found in the fixed point and fpu dsp library within c2000ware.

    2- Should I use Complex FFT or Real FFT functions?. As all data is coming from ADC and is real so is there any reason to use Complex FFT?  

    Since you are not dealing with imaginary values, RFFT should suffice.

    3- It will be nice to have a linker command file for this controller for FFT data blocks (for e.g. twiddle factors) mapping into FLASH. 

    We do provide linker command files for both FLASH and RAM. Please check the respective libraries and the examples provided in c2000ware to know more.

    4- Is there any document besides the example projects to help understanding the use of FFT library functions.

    Please refer to the documentation provided within the library folder in c2000ware.

    Hope this helps.

    -Shantanu

  • Thank you very much for providing answer to each question. I have no more queries regarding points 1,2 &4. However for point number 3 it will be nice to have more details. The example folder contains implementation for 2833x series. I will try to take guide lines from the linker command files of this controller. However it will be much better if there is some reference linker command file for 28002x series that contains mapping for the IQMath sections as well as FFT sections.

  • You can refer to the IQMath examples as well. The linker cmd files are provided in the IQMath library. You only need to make sure that the tables and libraries are properly allocated for both FFT and IQMath. Let me know if you face any difficulty.

  • Dear Shanty thankyou very much for the continued support. The documentation has provided sample allocation as below:
    FFTipcb ALIGN(256) : { } > RAML4, PAGE 1
    FFTipcbsrc : { } > RAML5, PAGE 1
    FFTmag > RAML6, PAGE 1
    FFTtf > RAML7, PAGE 1

    The linker command file that I am using was modified from the example file for TMS320F280025C launchpad. In this linker command file the RAM sectors are combined to a single block and already associated to different sections. Please see below:

    MEMORY
    {
    BEGIN : origin = 0x080000, length = 0x000002
    BOOT_RSVD : origin = 0x00000002, length = 0x00000126
    RAMM0 : origin = 0x00000128, length = 0x000002D8
    RAMM1 : origin = 0x00000400, length = 0x000003F8 /* on-chip RAM block M1 */
    // RAMM1_RSVD : origin = 0x000007F8, length = 0x00000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */

    /* RAMLS4 : origin = 0x0000A000, length = 0x00000800
    RAMLS5 : origin = 0x0000A800, length = 0x00000800
    RAMLS6 : origin = 0x0000B000, length = 0x00000800
    RAMLS7 : origin = 0x0000B800, length = 0x00000800*/

    /* Combining all the LS RAMs */
    RAMLS4567 : origin = 0x0000A000, length = 0x00002000
    RAMGS0 : origin = 0x0000C000, length = 0x000007F8
    // RAMGS0_RSVD : origin = 0x0000C7F8, length = 0x00000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */


    // FLASHBANK1 : origin = 0x00080000, length = 0x0000FFF0
    // FLASH_BANK1_RSVD : origin = 0x0008FFF0, length = 0x00000010 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
    BOOTROM : origin = 0x003F0000, length = 0x00008000
    BOOTROM_EXT : origin = 0x003F8000, length = 0x00007FC0
    RESET : origin = 0x003FFFC0, length = 0x00000002
    /* Flash sectors */
    /* BANK 0 */
    FLASH_BANK0_SEC0 : origin = 0x080002, length = 0x000FFE /* on-chip Flash */
    FLASH_BANK0_SEC1 : origin = 0x081000, length = 0x001000 /* on-chip Flash */
    FLASH_BANK0_SEC2 : origin = 0x082000, length = 0x001000 /* on-chip Flash */
    FLASH_BANK0_SEC3 : origin = 0x083000, length = 0x001000 /* on-chip Flash */
    FLASH_BANK0_SEC4 : origin = 0x084000, length = 0x001000 /* on-chip Flash */
    FLASH_BANK0_SEC5 : origin = 0x085000, length = 0x001000 /* on-chip Flash */
    FLASH_BANK0_SEC6_7 : origin = 0x086000, length = 0x002000 /* on-chip Flash */
    FLASH_BANK0_SEC8 : origin = 0x088000, length = 0x001000 /* on-chip Flash */
    FLASH_BANK0_SEC9 : origin = 0x089000, length = 0x001000 /* on-chip Flash */
    FLASH_BANK0_SEC10 : origin = 0x08A000, length = 0x001000 /* on-chip Flash */
    FLASH_BANK0_SEC11 : origin = 0x08B000, length = 0x001000 /* on-chip Flash */
    FLASH_BANK0_SEC12 : origin = 0x08C000, length = 0x001000 /* on-chip Flash */
    FLASH_BANK0_SEC13 : origin = 0x08D000, length = 0x001000 /* on-chip Flash */
    FLASH_BANK0_SEC14 : origin = 0x08E000, length = 0x001000 /* on-chip Flash */
    FLASH_BANK0_SEC15 : origin = 0x08F000, length = 0x000FF0 /* on-chip Flash */
    // FLASH_BANK0_SEC15_RSVD : origin = 0x08FFF0, length = 0x000010 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */

    }


    SECTIONS
    {
    codestart : > BEGIN, ALIGN(8)
    .text : >> FLASH_BANK0_SEC2 | FLASH_BANK0_SEC3 | FLASH_BANK0_SEC4 | FLASH_BANK0_SEC5 , ALIGN(8)
    .cinit : > FLASH_BANK0_SEC1, ALIGN(8)
    .switch : > FLASH_BANK0_SEC1, ALIGN(8)
    .reset : > RESET, TYPE = DSECT /* not used, */

    .stack : > RAMM1

    .init_array : > FLASH_BANK0_SEC1, ALIGN(8)
    .bss : > RAMLS4567
    .bss:output : > RAMLS4567
    .bss:cio : > RAMGS0
    .const : > FLASH_BANK0_SEC6_7, ALIGN(8)
    .data : > RAMLS4567
    .sysmem : > RAMLS4567

    ramgs0 : > RAMGS0


    /* Allocate IQ math areas: */
    IQmath : > FLASH_BANK0_SEC1, PAGE = 0, ALIGN(4) /* Math Code */
    IQmathTables : > FLASH_BANK0_SEC2, PAGE = 0, ALIGN(4)

    .TI.ramfunc : LOAD = FLASH_BANK0_SEC1,
    RUN = RAMGS0,
    LOAD_START(RamfuncsLoadStart),
    LOAD_SIZE(RamfuncsLoadSize),
    LOAD_END(RamfuncsLoadEnd),
    RUN_START(RamfuncsRunStart),
    RUN_SIZE(RamfuncsRunSize),
    RUN_END(RamfuncsRunEnd),
    ALIGN(8)

    }
    /*
    //===========================================================================
    // End of file.
    //===========================================================================
    */

    I am not very much familiar with the modifications for the linker command files. Please give me guidelines on how to accommodate the FFT sections in the above linker command file. It will be very nice if you can edit the above linker file for same.

  • Hi,

    You are right. You can allocate the FPU FFT math tables to RAMLS4567 in F28002x the same way. 

    However, if you would like to allocate tables (IQMath or FFT) to FLASH, please make sure to memcpy them to RAM in your code as demonstrated by the examples. 

    -Shantanu

  • Why is it required to memcpy IQMath /FFT to RAM?. Is it for fast execution?. Secondly the FFT twiddle factors are taking three sectors of the FLASH. This is very costly for my project. I understand that this is due to 4096 point FFT twiddle factors. Can I reduce it  considering that I will be using only 64 points RFFT. It will be grateful if you can check if the following linker command has proper assignments

    MEMORY
    {
       BEGIN           	: origin = 0x080000, length = 0x000002
       BOOT_RSVD		: origin = 0x00000002, length = 0x00000126
       RAMM0           	: origin = 0x00000128, length = 0x000002D8
       RAMM1            : origin = 0x00000400, length = 0x000003F8     /* on-chip RAM block M1 */
    // RAMM1_RSVD       : origin = 0x000007F8, length = 0x00000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
    
    /* RAMLS4           : origin = 0x0000A000, length = 0x00000800
       RAMLS5           : origin = 0x0000A800, length = 0x00000800
       RAMLS6           : origin = 0x0000B000, length = 0x00000800
       RAMLS7           : origin = 0x0000B800, length = 0x00000800*/
    
       /* Combining all the LS RAMs */
       RAMLS4567        : origin = 0x0000A000, length = 0x00002000
       RAMGS0           : origin = 0x0000C000, length = 0x000007F8
    // RAMGS0_RSVD      : origin = 0x0000C7F8, length = 0x00000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
    
    
    //  FLASHBANK1       : origin = 0x00080000, length = 0x0000FFF0
    //  FLASH_BANK1_RSVD : origin = 0x0008FFF0, length = 0x00000010 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
       BOOTROM          : origin = 0x003F0000, length = 0x00008000
       BOOTROM_EXT      : origin = 0x003F8000, length = 0x00007FC0
       RESET            : origin = 0x003FFFC0, length = 0x00000002
       /* Flash sectors */
       /* BANK 0 */
       FLASH_BANK0_SEC0  : origin = 0x080002, length = 0x000FFE	/* on-chip Flash */
       FLASH_BANK0_SEC1  : origin = 0x081000, length = 0x001000	/* on-chip Flash */
       FLASH_BANK0_SEC2  : origin = 0x082000, length = 0x001000	/* on-chip Flash */
       FLASH_BANK0_SEC3_9  : origin = 0x083000, length = 0x007000	/* on-chip Flash */
       FLASH_BANK0_SEC10_11 : origin = 0x08A000, length = 0x002000	/* on-chip Flash */
       FLASH_BANK0_SEC12_15 : origin = 0x08C000, length = 0x003FF0	/* on-chip Flash */
       // FLASH_BANK0_SEC15_RSVD     : origin = 0x08FFF0, length = 0x000010  /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
    
    }
    
    
    SECTIONS
    {
       codestart        : > BEGIN, ALIGN(8)
       .text            : >> FLASH_BANK0_SEC2 | FLASH_BANK0_SEC3_9 ,   ALIGN(8)
       .cinit           : > FLASH_BANK0_SEC1,  ALIGN(8)
       .switch          : > FLASH_BANK0_SEC1,  ALIGN(8)
       .reset           : > RESET,                  TYPE = DSECT /* not used, */
    
       .stack           : > RAMM1
    
       .init_array      : > FLASH_BANK0_SEC1,  ALIGN(8)
       .bss             : > RAMLS4567
       .bss:output      : > RAMLS4567
       .bss:cio         : > RAMGS0
       .const           : > FLASH_BANK0_SEC10_11,  ALIGN(8)
       .data            : > RAMLS4567
       .sysmem          : > RAMLS4567
    
        ramgs0 : > RAMGS0
    
    
       /* Allocate IQ math areas: */
       IQmath : > FLASH_BANK0_SEC1, PAGE = 0, ALIGN(4) /* Math Code */
       IQmathTables : > FLASH_BANK0_SEC2, PAGE = 0, ALIGN(4)
    
       /* Allocating FFT areas: */
       FFTipcb 		: >> RAMGS0, ALIGN(256) //64 points FFT
       FFTipcbsrc	: >> RAMLS4567
       FFTtf        : > FLASH_BANK0_SEC12_15
    
      .TI.ramfunc      : LOAD = FLASH_BANK0_SEC1,
                      RUN = RAMGS0,
                      LOAD_START(RamfuncsLoadStart),
                      LOAD_SIZE(RamfuncsLoadSize),
                      LOAD_END(RamfuncsLoadEnd),
                      RUN_START(RamfuncsRunStart),
                      RUN_SIZE(RamfuncsRunSize),
                      RUN_END(RamfuncsRunEnd),
                      ALIGN(8)
    
    }
    /*
    //===========================================================================
    // End of file.
    //===========================================================================
    */
    

  • Hi,

    You can also use the FFT and IQMath tables from ROM. You do not need to actually load them if space is an issue. Please refer to the RAM_ROMTABLES configurations as well in the examples. You need to make sure that the symbols library is included. Refer to the documentation.

    It is not necessary to put tables in FLASH, but as specified in the examples, this is how the allocation to FLASH is to be done:

    FPU64fftTables : LOAD = FLASHB,
    RUN = RAMGS2,
    RUN_START(FPU64fftTablesRunStart),
    LOAD_START(FPU64fftTablesLoadStart),
    LOAD_SIZE(FPU64fftTablesLoadSize),
    PAGE = 1

    Since you are specifying that you are running from RAM, you need to memcpy because memory access times are lower. 

    Hope this helps.

    -Shantanu

  • Dear Shanty,

      I have used example code as a reference to make a small code for checking RFFT on TMS320F280025C. My linker command file is as below:

    MEMORY
    {
       BEGIN           	: origin = 0x080000, length = 0x000002
       BOOT_RSVD		: origin = 0x00000002, length = 0x00000126
       RAMM0           	: origin = 0x00000128, length = 0x000002D8
       RAMM1            : origin = 0x00000400, length = 0x000003F8     /* on-chip RAM block M1 */
    // RAMM1_RSVD       : origin = 0x000007F8, length = 0x00000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
    
    /* RAMLS4           : origin = 0x0000A000, length = 0x00000800
       RAMLS5           : origin = 0x0000A800, length = 0x00000800
       RAMLS6           : origin = 0x0000B000, length = 0x00000800
       RAMLS7           : origin = 0x0000B800, length = 0x00000800*/
    
       /* Combining all the LS RAMs */
       RAMLS4567        : origin = 0x0000A000, length = 0x00002000
       RAMGS0           : origin = 0x0000C000, length = 0x000007F8
    // RAMGS0_RSVD      : origin = 0x0000C7F8, length = 0x00000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
    
    
    //  FLASHBANK1       : origin = 0x00080000, length = 0x0000FFF0
    //  FLASH_BANK1_RSVD : origin = 0x0008FFF0, length = 0x00000010 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
       BOOTROM          : origin = 0x003F0000, length = 0x00008000
       BOOTROM_EXT      : origin = 0x003F8000, length = 0x00007FC0
       RESET            : origin = 0x003FFFC0, length = 0x00000002
       /*IQMath table already exists in the BOOTROM section*/
       //IQTABLES 		: origin = 0x3F1402, length = 0x0166D
       /* Flash sectors */
       /* BANK 0 */
       FLASH_BANK0_SEC0  : origin = 0x080002, length = 0x000FFE	/* on-chip Flash */
       FLASH_BANK0_SEC1  : origin = 0x081000, length = 0x001000	/* on-chip Flash */
       FLASH_BANK0_SEC2  : origin = 0x082000, length = 0x001000	/* on-chip Flash */
       FLASH_BANK0_SEC3_9  : origin = 0x083000, length = 0x007000	/* on-chip Flash */
       FLASH_BANK0_SEC10_11 : origin = 0x08A000, length = 0x002000	/* on-chip Flash */
       FLASH_BANK0_SEC12_15 : origin = 0x08C000, length = 0x003FF0	/* on-chip Flash */
       // FLASH_BANK0_SEC15_RSVD     : origin = 0x08FFF0, length = 0x000010  /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
    
    }
    
    
    SECTIONS
    {
       codestart        : > BEGIN, ALIGN(8)
       .text            : >> FLASH_BANK0_SEC2 | FLASH_BANK0_SEC3_9 ,   ALIGN(8)//executable code >> operator splits code
       .cinit           : > FLASH_BANK0_SEC1,  ALIGN(8)//table that initializes global variables
       .switch          : > FLASH_BANK0_SEC1,  ALIGN(8)
       .reset           : > RESET,                  TYPE = DSECT /* not used, Dummy Section*/
    
       .stack           : > RAMM1
    
       .init_array      : > FLASH_BANK0_SEC1,  ALIGN(8)
       .bss             : > RAMLS4567 //uninitialized global variables
       .bss:output      : > RAMLS4567
       .bss:cio         : > RAMGS0
       .const           : > FLASH_BANK0_SEC10_11,  ALIGN(8)
       .data            : > RAMLS4567 //initialized data
       .sysmem          : > RAMLS4567
    
        ramgs0 : > RAMGS0
    
    
       /* Allocate IQ math areas: */
       IQmath : > FLASH_BANK0_SEC1, PAGE = 0, ALIGN(4) /* Math Code */
       //IQmathTables : > FLASH_BANK0_SEC2, PAGE = 0, ALIGN(4)/*This was working*/
       IQmathTables : > FLASH_BANK0_SEC1, PAGE = 0, ALIGN(4)/*Moved to sector 1 to run from RAM.Need verification*/
    
       /* Allocating FFT areas: */
       FFTipcb 		: >> RAMGS0, ALIGN(256) //64 points FFT
       FFTipcbsrc	: >> RAMLS4567
       FFTtf        : > FLASH_BANK0_SEC12_15
    
      .TI.ramfunc      : LOAD = FLASH_BANK0_SEC1, //Flash bank0 sector 1 contaings time critical functions required to run from RAM
                      RUN = RAMGS0,
                      LOAD_START(RamfuncsLoadStart),
                      LOAD_SIZE(RamfuncsLoadSize),
                      LOAD_END(RamfuncsLoadEnd),
                      RUN_START(RamfuncsRunStart),
                      RUN_SIZE(RamfuncsRunSize),
                      RUN_END(RamfuncsRunEnd),
                      ALIGN(8)
    
    }
    /*
    //===========================================================================
    // End of file.
    //===========================================================================
    */
    

     There are two issues with the result.

    1- The values in ipcbsrc array should be large values but these are very much scaled down (printed as sample inputs). However it is still a one cycle sine wave.

    2- The FFT result is all zero.

    Kindly check if the linker command file is Okay. Also check the code if I am missing some calculation step.

    The snippets of the FFT code are as below (I have removed non FFT code for simplicity purposes).

    #define FFT_SIZE    64
    
    #include "fft.h"
    #include "fft_hamming_Q31.h"
    #include "math.h"
    
    //Defining FFT sections
    #pragma DATA_SECTION(ipcb, "FFTipcb");
    int32_t ipcb[FFT_SIZE+2];         //Calculations buffer
    #pragma DATA_SECTION(ipcbsrc, "FFTipcbsrc");
    int32_t ipcbsrc[FFT_SIZE];        //Sampled input signal
    //Defining real fft object for 64 point calculations
    RFFT32  rfft = RFFT32_64P_DEFAULTS;
    
    
    
    void main(void)
    {for (i=0;i<FFT_SIZE;i++)
        {
            ipcbsrc[i]=(long)(2147483648*sinf(Rad));//Q31 format
            Rad=Rad+0.09817;
        }
        printf("\r\nSample Input:\r\n");
        for (i = 0; i < FFT_SIZE; i++)
    
    
            printf("%ld\r\n", ipcbsrc[i]);
        }
        RFFT32_brev(ipcbsrc, ipcb, FFT_SIZE); // real FFT bit reversing
    
        rfft.ipcbptr = ipcb;                  // FFT computation buffer
        rfft.magptr  = ipcbsrc;               // Magnitude output buffer
        rfft.winptr  = (long *)win;           // Window coefficient array
        rfft.init(&rfft);                     // Twiddle factor pointer initialization
    
        rfft.calc(&rfft);                     // Compute the FFT
        rfft.split(&rfft);                    // Post processing to get the correct spectrum
        rfft.mag(&rfft);                      // Q31 format (abs(ipcbsrc)/2^16).^2
    
    
        printf("\r\nFFT Result:\r\n");
        for (i = 0; i < FFT_SIZE; i++)
        {
             printf("%ld\r\n", ipcbsrc[i]);
        }
    }

    Following is the output of the code as printed on serial terminal:

    Sample Input:
    0
    31
    63
    94
    123
    152
    179
    205
    229
    250
    269
    285
    299
    310
    317
    322
    324
    322
    317
    310
    299
    285
    269
    250
    229
    205
    180
    152
    124
    94
    63
    31
    0
    -31
    -63
    -94
    -123
    -152
    -179
    -205
    -229
    -250
    -269
    -285
    -299
    -310
    -317
    -322
    -324
    -322
    -317
    -310
    -299
    -285
    -269
    -250
    -229
    -205
    -180
    -152
    -124
    -94
    -63
    -31


    FFT Result:
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    -31
    -63
    -94
    -123
    -152
    -179
    -205
    -229
    -250
    -269
    -285
    -299
    -310
    -317
    -322
    -324
    -322
    -317
    -310
    -299
    -285
    -269
    -250
    -229
    -205
    -180
    -152
    -124
    -94
    -63
    -31



  • Hi,
    Sorry for the delay in response. If you look at the rfft example provided, the input and output buffers are interchanged. Please provide the ipcb buffer as well.

    IN addition, please do the following checks:

    1) In the map file, make sure all tables are allocated

    2) During runtime, make sure that all buffers have the appropriate values

    3) Try copying to RAM using the LOAD, RUN parameters. It should look similar to this in the cmd file:

    FPUmathTables : LOAD = FLASH,
    RUN = RAMGS3,
    RUN_START(FPUmathTablesRunStart),
    LOAD_START(FPUmathTablesLoadStart),
    LOAD_SIZE(FPUmathTablesLoadSize),

    IN the code, you will have to memcpy the tables by  MemCopy(&FPUmathTablesLoadStart, &FPUmathTablesLoadEnd, &FPUmathTablesRunStart);

    4) You can also use the tables already provided in the Boot ROM. You do not need to allocate them in FLASH or RAM. Consult the RAM-ROMTABLES config and the documentation/

    Hope this helps

    -Shantanu

  • Dear Shantanu,

       I am sorry that I missed your reply some how. I have created a new post in which I have provided more details. Let me mark this thread as resolved as the initial intention was to get advise regarding initial implementation queries that have been addressed in this thread. Please guide on the other thread regarding implementation issues.

  • Asad,

    You can mark this thread as resolved in that case. Please send the link of the new thread.

    -Shantanu