Skip to content Skip to navigation

OpenStax-CNX

You are here: Home » Content » Multirate Filtering: Implementation on TI TMS320C54x (ECE 320 specific)

Navigation

Recently Viewed

This feature requires Javascript to be enabled.
 

Multirate Filtering: Implementation on TI TMS320C54x (ECE 320 specific)

Module by: Matthew Berry. E-mail the author

Summary: You will implement a multirate system that includes three fininte impulse response filters.

Implementation

As this is your first experience with the C environment, most of the programming for the assignment is to be done directly in assembly. A C skeleton will provide access to input samples and a way to output samples. From the C skeleton, an assembly module for implementing the complete multirate system (for a single sample) is called. In the assembly module, the downsampling and upsampling blocks are implemented by using a loop or counter to determine which samples to keep and when to insert zeros.

As there was a core file for working in the assembly environment (Labs 0-2), there is a core file for the C environment (V:\ece320\54x\dspclib\core.asm) which handles the interrupts from the CODEC (A/D and D/A) and the serial port. Here, we will describe the important aspects of the core code necessary to complete the assignment. The complete documentation on the core code developed for the C environment will be made available soon.

C Skeleton

Let's examine the following C main program lab3main.c which calls assembly FIR filter functions init_filter and filter.


          
	  1    #include "v:/ece320/54x/dspclib/core.h"  /* Declarations for core file */
	  2    void init_filter(void);			  /* Prototypes for assembly functions */
	  3    int filter(int sample);
	  4    extern int dec_rate;			  /* Default decimation rate is 4 */
	  5 
	  6    main()
	  7    {
	  8        int *Rcvptr,*Xmitptr;                 /* pointers to Xmit & Rcv Bufs   */
	  9        int i, sample1, sample2; 
	  10    
	  11        init_filter();			  /* Initialize the filter */
	  12        
	  13        while( 1 )
	  14        {   
	  15            /* Wait for a new block of samples */
	  16            WaitAudio(&Rcvptr,&Xmitptr);
	  17    	
	  18            /* Process a block of samples */
	  19            for( i = 0; i < BlockLen; i ++ )
	  20            {
	  21                sample1 = Rcvptr[4*i];		/* Ch1 input sample */
	  22                sample2 = Rcvptr[4*i+2];            /* Ch2 input sample  */
	  23            
	  24                Xmitptr[6*i]   = sample1;		/* First output is input */
	  25                Xmitptr[6*i+1] = filter(sample1);	/* Secound output is result */
	  26            }        
	  27
	  28            i = SerialRX();  	/* Check serial port */
	  29            if( i > 0 )
	  30              dec_rate = i;	/* Save new decimation rate if we got it */
	  31        }    
	  32    }
          
        

In the main program, an infinite loop operates over the input samples accessed by the pointer Rcvptr and writes the output samples via the pointer Xmitptr. In C, pointers may be used as array names so that Xmitptr[0] is the first word pointed to by Xmitptr. The function WaitAudio is a assembly function in the core code which handles the CODEC interrupts. It returns a block of BlockLen samples and writes BlockLen samples to each of the six channels. As in the assembly core, the input samples are not in consecutive order. The right and left inputs are offset from Rcvptr respectively by 4i 4 i and 4i+2 4 i 2 , i=0 i 0 , …, BlockLen1 BlockLen 1 . The six output channels are accessed consecutively as offsets from Xmitptr.

Assembly Functions

Let's examine the calls to the assembly functions init_filter and filter. The assembly file containing these functions is v:\ece320\54x\dspclib\lab3filt.asm


          
	  1    ; Lab 3 assembly module
	  2                        
	  3          .copy "v:\ece320\54x\dspclib\core.inc"
	  4    	                                ; Useful macros for C interfacing
	  5            
	  6          .global _dec_rate		; Decimation rate - in lab3main.c
	  7          .global _filter			; Filter code in this file
	  8          .global _init_filter
	  9
	  10    FIR_len	.set	13  
	  11
	  12          .sect ".data"
	  13
	  14          .align 16			; Align to a multiple of 16
	  15    firstate
	  16          .space 16*13			; Allocate 13 words of storage for
	  17					; filter state.	
	  18          .align 16
	  19    coef	.copy "coef1.asm" 
	  20
	  21    stateptr .word 0
	  22
	  23    _dec_rate .word 4
	  24
	  25          .sect ".text"    
	  26	
	  27    _init_filter 		; need the leading _ for a C name.
	  28          ENTER_ASM
	  29	
	  30          stm	#firstate, AR3
	  31          mvmd	AR3, stateptr		; Save AR3
	  32	
	  33          LEAVE_ASM
	  34          ret
	  35	
	  36    _filter                                          
	  37          ENTER_ASM
	  38          ; Input in low part of A accumulator
	  39	
	  40          mvdm	stateptr, AR3		; Restore state pointer
	  41	
	  42          stm 	#FIR_len,BK		; initialize circular buffer length
	  43          stm 	#coef,AR2    		; initialize coefficient pointer
	  44          stm 	#1,AR0			; initialize AR0 for pointer increment
	  45
	  46          stl   	A,*AR3+%		; store current input into state buffer
	  47          rptz  	A,(FIR_len-1)		; clear A and repeat
	  48          mac   	*AR2+0%,*AR3+0%,A	; multiply coefficient by state & accumulate
	  49
	  50          rnd	A			; Round off value in 'a' to 16 bits
	  51	
	  52          sfta 	a,-16			; Shift output to low part of accumulator
	  53        
	  54          mvmd	AR3, stateptr		; Save state pointer
	  55        
	  56          ; Output in low part of A accumulator
	  57
	  58          LEAVE_ASM
	  59          ret	                                        
          
        

The assembly file contains two main parts, the data section starting with .sect ".data" and the program section starting with .sect ".text". Every function and variable accessed in C must be preceded by a single underscore _ in assembly and a .global _name must be placed in the assembly file for linking. In this example, filter is an assembly function called from the C program with a label _filter in the text portion of the assembly file and a .global _filter declaration. In each assembly function, the macro ENTER_ASM is called upon entering and LEAVE_ASM is called upon exiting. These macros are defined in v:\ece320\54x\dspclib\core.inc. The ENTER_ASM macro saves the status registers and AR1, AR6, and AR7 when entering a function as required by the register use conventions. The ENTER_ASM macro also sets the status registers to the assembly conventions we have been using (i.e, FRCT=1 for fractional arithmetic and CPL=0 for DP referenced addressing). The LEAVE_ASM macro just restores the saved registers.

Parameter Passing

The parameter passing convention between assembly and C is simple for single input, single output assembly functions. From a C program, the input to an assembly program is in the low part of accumulator A with the output returned in the same place. In this example, the function filter takes the right input sample from A and returns a single output in A (note the left shift by 16 to put the result in the low part of A). When more than one parameter is passed to an assembly function, the parameters are passed on the stack (see the core file description for more information). We suggest that you avoid passing or returning more than one parameter. Instead, use global memory addresses to pass in or return more than one parameter. Another alternative is to pass a pointer to the start of a buffer intended for passing and returning parameters.

Registers Modified

When entering and leaving an assembly function, the ENTER_ASM and LEAVE_ASM macros ensure that certain registers are saved and restored. Since the C program may use any and all registers, the state of a register cannot be expected to remain the same between calls to assembly function(s). Therefore, any information that needs to be preserved across calls to an assembly function must be saved to memory! In this example, stateptr keeps track of the location of the current sample in the circular buffer firstate. Why don't we need to keep track of the location of the coefficient pointer (AR2 in this example) after every sample?

Compiling and Linking

A working program can be produced by compiling the C code and linking assembly modules and the core module. The compiler translates C code to a relocatable assembly form. The linker assigns physical addresses on the DSP to the relocatable data and code segments, resolves .global references and links runtime libraries.

The procedure for compiling C code and linking assembly modules has been automated for you in the batch file v:\ece320\54x\dsptools\C_ASM.bat. Copy the files lab3main.c, and lab3filt.asm from the v:\ece320\54x\dspclib\ directory into your own directory on the W: drive. Using Matlab, write the coefficients you created in the prelab into a coef1.asm file. Then, type c_asm lab3main lab3filt to produce a lab3main.out file to be loaded onto the DSP. Load the output file onto the DSP as usual and check that is the FIR filter you designed.

Cascade of FIR1 and FIR2

Modify the lab3filt.asm assembly module to implement a cascade of filters FIR1 and FIR2. Note that both _filter and _init_filter will need to be modified. Compile and link the new assembly module and confirm it has the frequency response which you expect from cascading FIR1 and FIR2.

Complete Multirate System

Once you have the cascaded system working, implement the multirate system composed of the three FIR filters by modifying the assembly modules in lab3filt.asm. In order to implement the sample rate converters, you will need to use a counter or a loop. The upsampling block and downsampling block are not implemented as seperate sections of code. Your counter or loop will determine when the decimated rate processing is to occur as well as when to insert zeros into FIR3 to implement the zero-filling up-sampler.

Some instructions that may be useful for implementing your multirate structure are the addm (add to memory) and bc (branch conditional) instructions. You may also find the banz (branch on auxiliary register not zero) instruction useful, depending on how you implement your code. As the counter is state information that needs to be preserved between calls to filter, the counter must be saved in memory.

In order to experiment with multirate effects in your system, make the downsampling factor ( D=U D U ) a constant which can be changed easily in your code. Is there a critical ( D=U D U ) associated with this system above which aliasing occurs?

It will be useful both for debugging and for experimentation to show the output of your system at various points in the block diagram. By modifying the C code in lab3main.c and the assembly modules in lab3filt.asm, send the following sequences to the DSP output

  • output of FIR1
  • input to FIR2 (after downsampling)
  • input to FIR3 (after upsampling)
You will have to pass these samples to the main C program by storing them in memory locations as described in Section 4. Note that the input to FIR2 is at the downsampled rate.

Grading and Oral Quiz

For the quiz, you should be prepared to change the decimation rate upon request, and explain the effects of changing the decimation rate on the system's output.

As usual, your grade will be split up into three sections:

  • 1 point: Prelab
  • 4 points: Code (Code which is complete and working at the beginning of the lab period gets full credit.)
  • 5 points: Oral Quiz
The oral quiz may cover various problems in multirate sampling theory, as well as the operation of your code itself and details about the instructions you've used in your code. Be prepared to explain, in detail, the operation of all of your code, even if your lab partner wrote it! You may also be asked to make changes to your code and to predict, and explain, the effects of these changes.

Extra Credit: 1 point

One of the main benefits of multirate systems is efficiency. Because of downsampling, the output of FIR1 is used only one of D D times. Make your assembly module more efficient by using this fact.

Similarly, at the input of FIR3, D1 D 1 of every D D samples is zero. So, for a fixed downsampling factor D D, it is possible to make use of this fact to create D D different filters (each a subset of the coefficients of FIR3) to be used at the D D time instances. This technique is referred to as polyphase filtering and can be found in most modern DSP textbooks. These filters are more efficient as the sum of the lengths of the filters is equal to the length of FIR3. Apply this fact for D=4 D 4 .

Content actions

Download module as:

Add module to:

My Favorites (?)

'My Favorites' is a special kind of lens which you can use to bookmark modules and collections. 'My Favorites' can only be seen by you, and collections saved in 'My Favorites' can remember the last module you were on. You need an account to use 'My Favorites'.

| A lens I own (?)

Definition of a lens

Lenses

A lens is a custom view of the content in the repository. You can think of it as a fancy kind of list that will let you see content through the eyes of organizations and people you trust.

What is in a lens?

Lens makers point to materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

Who can create a lens?

Any individual member, a community, or a respected organization.

What are tags? tag icon

Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

| External bookmarks