Skip navigation
1523 Views 5 Replies Latest reply: Mar 1, 2013 7:32 PM by mjkirk12 RSS
chaosStrings Just Startin' 3 posts since
Apr 18, 2011
Currently Being Moderated

Jun 4, 2011 2:45 PM

FIR filter: how to use memory?

Hi all!

 

I recently bought a TCDDK, and I'm having a bit of trouble in programming ...

 

My goal is to implement a FIR filter (1024 tap) for acoustic guitar simulation. I could do something like this:

0. declare 1024 variables for the data at current and previous timesteps y(n), y(n-1), y(n-2) etc

and in the program

  1. set the accumulator to 0
  2. write 1024 times for each i=1 to n
  • store input value y(i) into y(i-1)
  • multiply y(i)*coefficient(i) and add to accumulator

 

 

It seems a pretty bulky thing to do ... I hope there is a more elegant and effective way. I thought it could be

  1. store all coefficient values in a 1024 table
  2. allocate a vector with 1024 values in which to store all the input values for the current and previous timesteps

and finally multiply member by member with a repeat instruction, something like

REP #1024

mac x0,y0,a x:(i),x0 y:(i),y0

and i should increment automatically ...

 

Still, I haven't understood yet how to deal with memory allocation and indexing with vectors or tables ... hence my questions:

- how do I allocate a vector with a specified length?

- how do I store some given coefficients in such vector? and, for the input data, how can I save both the current input and the previous values at each timestep?

- what index should I use in order to access the data?

 

I hope my questions are clear, thank you in advance for your answers!

 

Daniele

  • RedPandaCurt Just Startin' 23 posts since
    Oct 30, 2009
    Currently Being Moderated
    Jun 5, 2011 6:19 AM (in response to chaosStrings)
    Re: FIR filter: how to use memory?

    IIRC, you will only be able to 512 taps using MACs with X/Y memory and modulo addressing, because you need to store the coefficients in program memory for initialization.  I describe that approach below, but you also might want to read the coefficients directly from program memory in your FIR (see the "Pitch detection/octave effect" thread for ideas). 

     

    You can allocate arrays in X and Y memory like the following.  For modulo-1024 addressing, each array needs to start at a multiple of 1024 within its address space.  The simplest way to do that is to put them at the beginning of the section.

     

            org     x:$000

    fir_state     ds     1024


            org     y:$000

    fir_coeffs     ds     1024

     

     

    For initializing tables in X or Y memory from program memory, you can define a global data section after the rest of your code:

     

     

    section P_DATA_MEMORY global


    org p:


    ; Table values

    COEFF_0 dc $000000

    COEFF_1 dc $000001

    .....

     

    You need to be careful about using too much program memory - your global data section will get truncated without warning.  (Note that the DSP56k assembler allows you to initialize the coefficients directly in program memory (dc), but it won't work with the TCDDK.)
    Then in your initialization code, copy it to an address in Y memory:

    move #COEFF_0,r0         ; address in program memory

    move #fir_coeffs,r4      ; address in Y memory

    do #1024,init_coeffs_end ; repeat for number of entries

    move p:(r0)+,y0

    move y0,x:(r4)+

    init_coeffs_end:

     

    Also, don't forget to clear the filter state.

     

    Use post-increment addressing to increment the addresses in your FIR loop.  The DSP56K has a modulo addressing mode to implement the delay line; each Rn register has an Mn register that you can set to modulus-1.  See Section 4.5.3 of the DSP56300 Family Manual for more details.  You can find examples of DSP56K FIRs on the web, but the basic idea is something like this (I didn't assemble/test this):

     

    ; once during initialization:

    move    #fir_state,r0     ; state

    move    #1023,m0          ; mod(1024)

    move    #fir_coeffs,r4    ; coefficients

    move    #1023,m4          ; mod(1024)


    ; for each sample:

    move     y:LeftInput,x0     ; input sample


    ; FIR

    clr     a    x0,x:(r0)+  y:(r4)+,y0 

    rep     1023

    mac     x0,y0,a  x:(r0)+,x0  y:(r4)+,y0

    macr    x0,y0,a  (r0)-     ; round and shift input samples


    move     a,y:RightOutput   ; output sample

     

     

      • RedPandaCurt Just Startin' 23 posts since
        Oct 30, 2009
        Currently Being Moderated
        Jun 17, 2011 7:10 PM (in response to chaosStrings)
        Re: FIR filter: how to use memory?

        One problem I see is that fir_state is starting at $100.  For modulo 512 addressing, the base address needs to be a multiple of 2^k.  For 512 taps, k=9, so the starting address should be $000 or $200. (For 100 taps, k=7 so 2^k=128 and $100 (256 decimal) is a multiple of that).

         

        You can verify that all of your coefficients are loaded by copying the last coefficient from y memory to one of the read-from-DSP debug registers.

      • mjkirk12 Just Startin' 10 posts since
        Feb 22, 2009
        Currently Being Moderated
        Mar 1, 2013 7:32 PM (in response to chaosStrings)
        Re: FIR filter: how to use memory?

        If you are still working on this...

         

        For linear phase FIR filters (typical application), the impulse response (coefficients) must be

        symmetric:  h[n] = h[N-n-1]    e.g.    h[0] = h[1023], h[1] = h[1022], etc.

        or

        anti-symmetric: h[n] = -h[N-n-1]

         

        For a 1024 tap filter, you really only need to store 512 coefficients.   With proper addressing (modulo pointers), you can do 2 MAC operations with the same coefficient, looping 512 times.  When the # of coefficients is odd, you need to handle the middle coefficient as a special case, outside the filter loop at the end.

         

        With proper design, an IIR (recursive) filter can be used to approximate a long FIR filter, maybe only requiring 3 or 4 coefficients.

         

        Or the DSP could be used to compute the coefficients dynamically at boot time storing them in X or Y data memory. 

        Then you would not need to download them in the code image.

         

        Cheers,

        Mike

More Like This

  • Retrieving data ...

Bookmarked By (0)

Legend

  • Correct Answers - 5 points
  • Helpful Answers - 3 points