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.

C28x Fixed Point DSP Library, designing coefficients with matlab 7

Other Parts Discussed in Thread: TMS320F28035, TMS320F28335

Hello, can anyone help me,  I'm trying to use the C28x Fixed Point DSP library to desgin a new low pass filter for FIR16.  I'm looking at Module User’s Guide 

v1.01 January 10, 2011 page 31.  I've searched the DOCs and forums and haven't found answers.  I have Matlab 7 and I am tring to use FDATool GUI to make my coefficents.   
I have 4 general questions about the library. 
.  
1) First, I don't understand the part where it says The coefficient can directly port to ‘fft.h’.  
Why is it talking about the fft.h header file when I'm using the FIR header file?  What does port mean in this context?

2) Second, Matlab seems to generate too many coefficents for long dbuffer[(FIR_ORDER+3)/2];   
The compiler gives me an error that says there are too many coefficients  for my array. 
Why does Matlab seem to give the wrong number of coefficients or what do I not understand?

3) Do I have to scale the coefficients   from Matlab to any IQ value.
I know that the older IQ math filter library Matlab script scaled the values for you.  (ezfir16.m)
Is it OK to port the values directly or do I need to do something further, and if so is there an example?

4) What is the best way to input values from the ADC into the filter - is there any conversion that I need to do for the input?
So I want to read the ADC value and put it directly into the filter - how is it best to do this for these filters?

My goal is to input a ADC value 0-4095 and to output a filtered value from 0-4095 based upon a filter I design with matlab FDATOOL.

I seem to have no problem making filters for the floating point library and this version of Matlab generates filter coefficients without a problem that I directly use in my filter. 
I wish there was a better start to finish tutorial on this library - if there is one, please send me the link...

Thanks
S.






  • I am about to head down this same path and found this post with all my same questions.

    Just wondering why there is no response. I would be interested in the answers to the above questions.

  • Not sure why I didnt respond to this earlier.

    1) First, I don't understand the part where it says The coefficient can directly port to ‘fft.h’.  
    Why is it talking about the fft.h header file when I'm using the FIR header file?  What does port mean in this context?
    This is a typo. It has been filed in our bug tracking system and will be fixed on the next rev. The original intent was to export the coeffs to a file and then copy over the standard arrays in fir.h.
    So if you are generating the coeffs for a 32 order LPF, you would export it to a C header file and then copy those coefficients to fir.h replacing the defualt contents of FIR16_LPF32_TEST
    2) Second, Matlab seems to generate too many coefficents for long dbuffer[(FIR_ORDER+3)/2];   
    The compiler gives me an error that says there are too many coefficients  for my array. 
    Why does Matlab seem to give the wrong number of coefficients or what do I not understand?
    Matlab gives you FIR_ORDER+1 coefficients. This goes back to the 1st question where you replace the original contents of FIR16_LPF32_TEST in fir.h. In the example code these
    coefficients are rearranged to fit in the coeff array. This is a little convoluted way of going about things. I will try and release a matlab script to do this automatically on the next revision

           //Reorganize coefficient table
           //If user would like to reorgainze the order of the coefficients outside this
           //project, for example, in matlab and stored the reorganized coefficients in
           //header file beforehand, this part is not necessarily.
           //More details, please refer to Fixed Point DSP library manual
           for(i=0;i<FIR_ORDER_REV;i=i+2)        
           {
                   *(p+FIR_ORDER_REV-i-2)=FIR16_LPF_TEST[i/2];
                   *(p+FIR_ORDER_REV-i-1)=FIR16_LPF_TEST[i/2+FIR_ORDER_REV/2];    
           }
    This reordering is explained in the guide on pg28: background info
    3) Do I have to scale the coefficients   from Matlab to any IQ value.
    I know that the older IQ math filter library Matlab script scaled the values for you.  (ezfir16.m)
    Is it OK to port the values directly or do I need to do something further, and if so is there an example?
    Matlab will put it in Q15 if you choose the signed 16 bit option and Q31 for the signed long, so you dont have to change format or scale the values.
    4) What is the best way to input values from the ADC into the filter - is there any conversion that I need to do for the input?
    Nope, ADC inputs go in as is.


  • Thanks,

    This helps clearify some things.

    I am finaly to the point in my code that I am going to give the FIR16 filter a try.

    I basically used Matlab to design a 96 order LPF with a Hamming window, Fs = 100Hz, Fc = 2Hz. I used signed 16 bit option to generate the coeffs.

    I assume I use the code below to rearrange the 97 coeff I copied from Matlab to the 96 coeff needed by fir16 array.

    I assume I just copy and paste the 97 coeffs from the Matlab .h file to the fir.h files FIR16_LPF_TEST[97] Or do I need to delete one of the coeffs before I copy in order to keep the number of coeffs to 96. If so which coeffs would I delete? would it be the center one 1306 below? If this is true, how does this affect the respons of my filter compared to the Matlab analysis?

    I also assume I just feed the input of the fir16 filter my raw adc values. The adc is sampling a sine wave signal that ranges from 0 to 4095 with  center of sine wave around 2048.

    Sorry if I am asking ignorant questions. Maybe it will all become more clear when I finally get the code running.

    for(i=0;i<FIR_ORDER_REV;i=i+2)        
           {
                   *(p+FIR_ORDER_REV-i-2)=FIR16_LPF_TEST[i/2];
                   *(p+FIR_ORDER_REV-i-1)=FIR16_LPF_TEST[i/2+FIR_ORDER_REV/2];    
           }

     

    Matlab generated coeff buffer.

    const int16_T B[97] = {

    -4, -7, -9, -12, -15, -19, -24, -29, -35,

    -41, -48, -54, -61, -67, -72, -76, -78, -77,

    -74, -68, -58, -43, -24, 0, 29, 64, 104,

    150, 201, 258, 319, 384, 453, 524, 598, 673,

    748, 822, 895, 964, 1029, 1090, 1144, 1192, 1232,

    1264, 1287, 1301, 1306, 1301, 1287, 1264, 1232, 1192,

    1144, 1090, 1029, 964, 895, 822, 748, 673, 598,

    524, 453, 384, 319, 258, 201, 150, 104, 64,

    29, 0, -24, -43, -58, -68, -74, -77, -78,

    -76, -72, -67, -61, -54, -48, -41, -35, -29,

    -24, -19, -15, -12, -9, -7, -4

    };

     

  • This reordering works with even number of taps. You could either pad the coefficients to an even number so add a trailing 0 to the list of coefficients and make it a 98 coefficient array. you'd have to increase FIR_ORDER by 1 or you could just set the order in matlab to 97 to generate a 98 coefficient filter.... there is an option in the fdatool to set the order.

    YOU DO NOT want  to be deleting any coefficients.

  • The adc input is used as is.

  • Ok, That makes sense.

    I had the filter working and everything looks great. However, When I tried to instance a second filter, the output of fir2 is the result of the input of fir and vise versa.

    I am sure it is the way I instanced the second filter. Maybe they are sharing some of the same memory. I am still learning about how to allocate momory in the 28035 so my understanding is limited at this point. If you could give my code a look and let me know if I am instancing the second filter (fir2) correclty, I would appreciate it.

    If I can get past this problem, I Should be able to leave you alone for awile and will owe you a big fruit basket for all your help.   

    /* Filter Symbolic Constants                        */

    #define FIR_ORDER   96                                      

                                           

    /* Create an Instance of FIRFILT_GEN module and place the object in "firfilt" section       */

    #pragma DATA_SECTION(fir, "firfilt");

    FIR16  fir= FIR16_DEFAULTS;

     

    #pragma DATA_SECTION(fir2, "firfilt2");

    FIR16  fir2= FIR16_DEFAULTS;

                                               

    /* Define the Delay buffer for the 50th order filterfilter and place it in "firldb" section */ 

    #pragma DATA_SECTION(dbuffer,"firldb");                                                                 // Delay buffer alignment

    long dbuffer[(FIR_ORDER+3)/2];   

     

    #pragma DATA_SECTION(dbuffer2,"firldb2");                                                                               // Delay buffer alignment

    long dbuffer2[(FIR_ORDER+3)/2];   

     

            

    /* Define Constant Co-efficient Array  and place the

    .constant section in ROM memory                                                   */

    #pragma DATA_SECTION(coeff, "coefffilt");                                                                // Coefficients buffer alignment

    long const coeff[(FIR_ORDER+3)/2]; 

    #pragma DATA_SECTION(coeff2, "coefffilt2");                                                              // Coefficients buffer alignment

    long const coeff2[(FIR_ORDER+3)/2];

    int FIR16_LPF_TEST[FIR_ORDER+1];                                                                                            // Temporary buffer for adjust odd order FIR

    main()

    { 

      MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart); 

                    unsigned long k;

                    int *p;

                    int *p2;                                  

                    int FIR_ORDER_REV;                                  

                    p=(int *)coeff;

                    p2=(int *)coeff2; 

                    FIR_ORDER_REV=FIR_ORDER;              

                    /* FIR Generic Filter Initialisation    */

           fir.order=FIR_ORDER_REV;       

           fir.dbuffer_ptr=dbuffer;

           fir.coeff_ptr=(long *)coeff;

           fir.init(&fir);

          

           fir2.order=FIR_ORDER_REV;       

           fir2.dbuffer_ptr=dbuffer2;

           fir2.coeff_ptr=(long *)coeff2;

           fir2.init(&fir2);

          

                       //Clean up coeff buffer

           for(k=0;k<FIR_ORDER_REV*2;k=k+2)   

           {       

                                                    *(p+k)=0;

                                                    *(p+k+1)=0; 

                                                    *(p2+k)=0;

                                                    *(p2+k+1)=0; 

           }

          

           //Clean up delay buffer

           for(k=0;k<FIR_ORDER_REV*2;k=k+1)   

           {       

                                                    dbuffer[k]=0;

                                                    dbuffer2[k]=0;

           }

          

                for(k=0;k<FIR_ORDER_REV;k=k+2)                       

           {

                                    *(p+FIR_ORDER_REV-k-2)=FIR16_LPF96_TEST[k/2];

                                    *(p+FIR_ORDER_REV-k-1)=FIR16_LPF96_TEST[k/2+FIR_ORDER_REV/2];                               

                                    *(p2+FIR_ORDER_REV-k-2)=FIR16_LPF96_TEST[k/2];

                                    *(p2+FIR_ORDER_REV-k-1)=FIR16_LPF96_TEST[k/2+FIR_ORDER_REV/2];                      

           }

         ............................My adc interupt runs the following call of the filter function

        fir.input=AvgSensorDriveADC;   

        fir.calc(&fir);

        DriveFiltered_sin = fir.output;                   

        fir2.input=AvgSensorOutADC;

         fir2.calc(&fir2);

         SensorOutFiltered_sin = fir2.output;              

            

  • The two filters seem to be working now. I allowed them to share the same coeff data section and removed the #pragma for the FIR16 instances. This allowed tjhe laocation of fir and fir2 to be controlled by the Linker Command File. It seems I would eventually want to create all these data sections in the Linker Command File to control where they go and get rid of all the pragma data sections. I am still learning just how to use the Linker Command File.

    If you see anything wrong with what I have done, let me know. If not, thanks for all your help.

     

    FIR16  fir= FIR16_DEFAULTS;  

    FIR16  fir2= FIR16_DEFAULTS;                                          

    #pragma DATA_SECTION(dbuffer,"firldb");                                                                 // Delay buffer alignment

    long dbuffer[(FIR_ORDER+3)/2];    

    #pragma DATA_SECTION(dbuffer2,"firldb2");                                                                               // Delay buffer alignment

    long dbuffer2[(FIR_ORDER+3)/2];            

    #pragma DATA_SECTION(coeff, "coefffilt");                                                                // Coefficients buffer alignment

    long const coeff[(FIR_ORDER+3)/2]; 

                  

  • Thanks for answering.

    This helps me out a lot.  I had moved on to the floating point FIR filters and they work well with MATLAB's FDA tool.  I agree with Gary for people new to TI processors, the memory stuff can really be confusing.  I was at first unsure on the floating point versions how to set the filter location to the right boundary.  A couple of different examples would really help.  It's hard to understand the cmd linker command files and difficult to make sure all your memory is correct. 

    The other thing I noticed was that many people may not have MATLAB so it would also be helpful to have MATLAB scripts because you can use Octave to design the filter with the MATLAB script.  I admit that I'm not great with the scripting language, and writing one myself would take some time.   I also saw the re-ordering stuff, but got pulled away before I could understand it.  Hoping to see a Matlab script like in the previous version of the library soon!

    I'm implementing FOC control on a PMSM motors and I use these software filters.  We may try to integrate the new library into our legacy product, because I think there is some issue with the first version of the library that I don't fully understand.

    Another bug/bad set of instructions I found but haven't had time to work with is the conversion of the conversion of projects from DSP/BIOS to SYS/BOIS - that really needs some help.......  I can't get the java scripts included there to work....

    Steve

  • Hay Steve and Vishal,

    Sorry for butting in on your thread Steve, but you seem to be asking the same questions I was getting ready to ask.

    I finally got my filters working and I got rid of the compiler warnings concerning the Data Section for the FIR16. I added the following lines to my RAM Linker command file

     

       firldb   align(0x100)> dataRAM     PAGE = 1

       firldb2  align(0x100)> dataRAM     PAGE = 1

       firfilt                : > RAMM0   PAGE = 1

       firfilt2               : > RAMM0   PAGE = 1

       coefffilt align(0x100)>RAMM1             PAGE = 1

    I think without specifying where these should go in the linker command file the linker can put them in locations that cause problems with the filters. You can look at the MAP output file to see where everything is going in memory. Before I did this the input of one filter was coming out of the output of the other. Since my coefficients are the same for both my filters I only need one coefffilt location. I also ran out of space in RAMM0 so I put the firldb and firldb2 arrays in dataRAM.

    By the way, I also completed a project about a year ago using the TMS320F28035 to implement FOC on a 200W 240V PMSM motor. I still do not consider myself a motor control expert, but it seems to be working OK.

    Unless Vishal or some other TI expert sees a problem with my memory allocation above, I should be done with this thread and can quietly disappear. Even if what I have done above is correct, it would be nice to hear some confirmation from someone that understands the 28035 memory allocation better than me. My hands shake every time I have to change the Linker Command File.  

  • Steve,

    The memory alignment looks correct to me. I dont recall if there is an alignment requirement for the memory spaces but it would'nt hurt things. 

    I just wanted to point out from one of your earlier threads that #pragma DATA_SECTION(var,"varspace") will place var in the section varspace, HOWEVER, if the linker command file

    does not define the section varspace it will issue a warning , something about how there is no definition for varspace. The linker will probably assign it to the first available RAM space it finds. This is OK, most of the time, but it can come back to bite you if the section needs alignment or something like that.....so......its always better to explicitly create the section in the linker command file, as you did, and then use the #pragma to push the variable to the section

    Gary and Steve, thank you both for your feedback. Ill be sure to update our documentation on the next rev and provide the scripts to run on Octave. I should point out that I dont think Octave has export functions similar to the fdatool, although, I havent explored it all that much. But I have scripts to go from float to IQx formats and vice versa so ill throw those in there as well.

  • Also , FYI the following app-note provides good insight into linker command files. It isn't C2000 specific but the ideas apply.

    http://e2e.ti.com/support/microcontrollers/tms320c2000_32-bit_real-time_mcus/f/171/t/153865.aspx#611163

  • Hi Gary,

    I am using your code for the coefficients adjustment but i am getting error for the following lines:

     *(p+FIR_ORDER_REV-k-2)=FIR16_LPF96_TEST[k/2];

     *(p+FIR_ORDER_REV-k-1)=FIR16_LPF96_TEST[k/2+FIR_ORDER_REV/2];         

    error is :

    "expected an expression"

    Can you help me resolve it.

    Thank You!

  • I Have attached the filter setup portion of my main.c file and also my linker command file which defines the memory location of the filter coefficients. Hopefully this helps.

    F28026.zip

  • Also, My code uses two low pass filters and two highpass filters. Each low pass filter and each high pass filter uses the same coefficients
  • Hi Gary, thank you for your help. I resolved the problem i was facing. i m working on tms320f28335 dsp processor. How can i see the modified coefficients when i intend to change the coefficients from 33 to 32. Also how can i see the filtering action of the program when i apply some input. I am not facing any memory problems but i want to know what does a linker file do and is it necessary for me to change the linker file.

    Thank You!

  • It’s been awhile since I used the filter library, so I am probably not your best source for answers, but I will give it a try.

     

    The command linker file is what sets up your memory sections for the compiler. If you see inside my cmd file, I have setup the locations for my filters which are needed by the filter library. If you do not understand the command linker file, I would suggest spending some time learning about its function. It is the key to implementing any embedded project for your processor, not just the filter library.

    Inside my main.c file you will see the filters instanced to use the data sections setup in the linker command file. I think all this is explained in the Filter library documentation.

     

    If you wish to see the results of your filter, you will need to provide some type of output of your calculated data. I typically send my data out the serial port and use a PC running my own C# program to display the data in a graphical format. If writing your own PC viewer is not an option, you can use code composer to graph data sections via the JTAG connection. I have never used this feature, but have seen it work on some of the motor control examples from TI.

     

    Sorry I am not much help, maybe someone from TI can jump in and offer more detailed help.

  • Gary thank you for replying. Though i have one doubt which is crucial. When we design filter in MATLAB, we get coefficients in numerator and denominator form. After that how to use that coefficients in fir.h and iir.h . In the code how did one fill that FIR32_LPF16_TEST similar structures with values. I am not getting how did TI got those values. It would be of great help if you make me understand.
    THANK YOU!