<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE document PUBLIC "-//CNX//DTD CNXML 0.5 plus MathML//EN" "http://cnx.rice.edu/cnxml/0.5/DTD/cnxml_mathml.dtd">
<document xmlns="http://cnx.rice.edu/cnxml" xmlns:m="http://www.w3.org/1998/Math/MathML" xmlns:md="http://cnx.rice.edu/mdml/0.4" xmlns:bib="http://bibtexml.sf.net/" id="m10023">
  
  <name>FIR Filtering: Exercise for TI TMS320C55x</name>
  <metadata>
  <md:version>1.6</md:version>
  <md:created>2006/07/21 18:06:13 GMT-5</md:created>
  <md:revised>2008/01/23 15:33:53.953 US/Central</md:revised>
  <md:authorlist>
      <md:author id="tbshen">
      <md:firstname>Thomas</md:firstname>
      
      <md:surname>Shen</md:surname>
      <md:email>tbshen@uiuc.edu</md:email>
    </md:author>
  </md:authorlist>

  <md:maintainerlist>
    <md:maintainer id="tbshen">
      <md:firstname>Thomas</md:firstname>
      
      <md:surname>Shen</md:surname>
      <md:email>tbshen@uiuc.edu</md:email>
    </md:maintainer>
  </md:maintainerlist>
  
  <md:keywordlist>
    <md:keyword>assembly</md:keyword>
    <md:keyword>DSP</md:keyword>
    <md:keyword>FIR filter</md:keyword>
    <md:keyword>firs</md:keyword>
    <md:keyword>mac</md:keyword>
  </md:keywordlist>

  <md:abstract>You will implement band-pass finite impulse-response (FIR) filters with time-domain processing.</md:abstract>
</metadata>





  <content>
    <section id="sec1">
      <name>Introduction</name>
      <para id="para1a">In this exercise, you will program in the DSP's assembly
	language to create FIR filters.  Begin by studying the
	assembly code for the basic FIR filter <link src="filtercode.asm">filtercode.asm</link>. For help with circular addressing, view <cnxn document="m14262">Addressing Modes for TI TMS320C55x</cnxn>.
      </para>
      <figure id="fig1"><name>filtercode.asm</name>
	<code type="block"><![CDATA[ 
	.ARMS_off						;enable assembler for ARMS=0
	.CPL_on							;enable assembler for CPL=1
	.mmregs							;enable mem mapped register names

	.global _filter
	.global _inPtr
	.global _outPtr

	.copy "macro.asm"				; Copy in macro declaration

	.sect ".data"

FIR_len1	.set 8					; This is a 8-tap filter

	.align 32						; Align to a multiple of 16
coef1								; assign label "coef1"
	.copy "coef.asm"				; Copy in coefficients


	.align 32			
firState1	.space 16*FIR_len1		; Allocate 8 words of storage for
									; filter state.

firState1Index						; Allocate storage to save index
	.word	0						; in firState

	.copy "testvect.asm"

	.sect ".text2"

_filter

	ENTER_ASM						; Call macro. Prepares registers for assembly
	
	MOV		#0, AC0					; Clears AC0 and XAR3
	MOV		AC0, XAR3				; XAR3 needs to be cleared due to a bug

	MOV		dbl (*(#_inPtr)), XAR6		; XAR6 contains address to input
	MOV		dbl (*(#_outPtr)), XAR7					; AR7 contains address to output

	BSET	AR2LC					; sets circular addressing for AR2

	MOV		#firState1, AR2			; State pointer is in AR2
	MOV		#firState1Index, AR4	; State index pointer is in AR4
	MOV		mmap(AR2), BSA23		; BSA23 contains address of firState1
	MOV		*AR4, AR2				; AR2 contains the index of oldest state
	
	MOV		#coef1, AR1				; initialize coefficient pointer
	MOV		#FIR_len1, BK03			; initialize circular buffer length for register 0-3

	MOV		*AR6+ << #16, AC0		; Receive ch1 into AC0 accumulator
	MOV		AC0, AC1				; Transfer AC0 into AC1 for safekeeping
	
	MOV		HI(AC0), *AR2+			; store current input into state buffer
	MOV		#0, AC0					; Clear AC0
	RPT		#FIR_len1-1				; Repeat next instruction FIR_len1 times
	MACM	*AR1+,*AR2+,AC0,AC0		; multiply coef. by state & accumulate
	round	AC0						; Round off value in 'AC0' to 16 bits  

	MOV		HI(AC0), *AR7+			; Store filter output (from AC0) into ch1
	MOV		HI(AC1), *AR7+			; Store saved input (from AC1) into ch2
	MOV		HI(AC0), *AR7+
	MOV		HI(AC1), *AR7+

	MOV		AR2, *AR4				; Save the index of the latest state back into firState1Index

	LEAVE_ASM						; Call macro to restore registers

	RET



]]>
	</code>
</figure>
      <para id="p1"><code>filtercode.asm</code> applies an FIR filter to the signal
	from input channel 1 and sends the resulting output to output
	channel 1.  It also sends the original signal to output
	channel 2.
      </para>
      <para id="p2">First, create a work directory on your network drive for the
	files in this exercise, and copy the filter folder from
	<code>v:\ece420\55x\filter</code> to your work directory.  Then, use MATLAB
	to generate two 20-tap FIR filters. The first filter should
	pass signals from 4 kHz to 8 kHz; the second filter should
	pass from 8 kHz to 12 kHz. For both filters, allow a 1 kHz
	transition band on each edge of the filter passband.  To
	create these filters, first convert these band edges to
	digital frequencies based on the 48 kHz sample rate of the
	system, then use the MATLAB command <code>firpm</code> to
	generate this filter; you can type <code>help firpm</code> for
	more information.  Use the <code>save_coef</code> command to
	save each of these filters into different files. (Make sure
	you reverse the vectors of filter coefficients before you save
	them.)  Also save your filters as a MATLAB matrix, since you
	will need them later to generate test vectors. This can be
	done using the MATLAB <code>save</code> command. Once this is
	done, use the <code>freqz</code> command to plot the frequency
	response of each filter.
      </para>
    </section>
    <section id="sec2">
      <name>Part 1: Single-Channel FIR Filter</name>
      <para id="p3">For now, you will implement only the filter with a 4 kHz to 8
	kHz passband. Edit <code>filtercode.asm</code> to use the
	coefficients for this filter by making several changes.
      </para>
      <para id="p4">First, the length of the FIR filter for this exercise is 20,
	not 8.  Therefore, you need to change <code>FIR_len1</code> to
	20. <code>FIR_len1</code> is set using the <code>.set</code>
	directive, which assigns a number to a symbolic name. You will
	need to change this to <code>FIR_len1 .set 20</code>.
      </para>
      <para id="p5">
	Second, you will need to ensure that the <code>.copy</code>
	directive brings in the correct coefficients. Change the
	filename to point to the file that contains the coefficients
	for your first filter.
      </para>
      <para id="p6">Third, you will need to modify the <code>.align</code> and
	<code>.space</code> directives appropriately. The TI
	TMS320C55x DSP requires that circular buffers, which are used
	for the FIR filter coefficient and state buffers, be aligned
	so that they begin at an address that is a multiple of a power
	of two greater than the length of the buffer. Since you are
	using a 20-tap filter (which uses 20-element state and
	coefficient buffers), the next greater power of two is 32.
	Therefore, you will need to align both the state and
	coefficient buffers to an address that is a multiple of 32.
	(16-element buffers would also require alignment to a multiple
	of 32.)  This is done with the <code>.align</code> command. In
	addition, memory must be reserved for the state buffer. This
	is done using the <code>.space</code> directive, which takes
	as its input the number of <emphasis>bits</emphasis> of space
	to allocate. Therefore, to allocate 20 words of storage, use
	the directive <code>.space 16*20</code> as shown below:
      </para>
      <code type="block"><![CDATA[
	1         .align 32             % Align to a multiple of 32
	2  coef1   .copy  "coef1.asm"  % Copy FIR filter coefficients
	3
	4         .align 32             % Align to a multiple of 32
	5  firState1  .space 16*20          % Allocate 20 words of data space]]>
      </code>
      <para id="p7">Assemble your code, load the output file, and run.  Ensure that it
	is has the correct frequency response. After you have verified
	that this code works properly, proceed to the next step.
      </para>
    </section>
    <section id="sec3">
      <name>Part 2: Dual-Channel FIR Filters</name>
      <para id="p9">First, make a copy of your modified <code>filtercode.asm</code>
	file from <cnxn target="sec2">Part 1</cnxn>. Work from this
	copy; do not modify your working filter from the previous
	part. You will use that code again later.
      </para>
      <para id="p10">
	Next, modify your code so that in addition to sending the
	output of your first filter (with a 4 kHz to 8 kHz passband)
	to output channel 1 and the unfiltered input to output channel
	2, it sends the output of your second filter (with a 8 kHz to
	12 kHz passband) to output channel 3. To do this, you will
	need to use the <code>.align</code> and <code>.copy</code>
	directives to load the second set of coefficients into data
	memory.  You will also need to add instructions to initialize
	a pointer to the second set of coefficients and to perform the
	calculations for the second filter.  
      </para>
      <exercise id="new0">
	<problem>
	  <name>Extra Credit Problem</name>
	  <para id="new1">
	    One extra credit point will be awarded to you and your
	    partner if you can implement the dual-channel system
	    without using the auxiliary registers <code>AR4</code> and
	    <code>AR5</code>?  Why is this more difficult?  Renaming
	    <code>AR4</code> and <code>AR5</code> using the
	    <code>.asg</code> directive does not count!
	  </para>
	</problem>
      </exercise>
      <para id="p11">Using the techniques introduced in <cnxn document="m13811">DSP
	Development Environment: Introductory Exercise for TI
	TMS320C55x</cnxn>, generate an appropriate test vector and
	expected outputs in MATLAB. Then, using the test-vector core
	file also introduced in <cnxn document="m13811">DSP
	Development Environment: Introductory Exercise for TI
	TMS320C55x</cnxn>, find the system's output given this test
	vector.  In MATLAB, plot the expected and actual outputs of
	the both filters and the difference between the expected and
	actual outputs. Why is the output from the DSP system not
	exactly the same as the output from MATLAB?
      </para>
    </section>
    <section id="sec5">
      <name>Part 3: Alternative Single-Channel FIR Implementation</name>
      <para id="p12">An alternative method of implementing symmetric FIR filters
	uses the <term><code>firsadd</code></term> instruction.  Modify
	your code from <cnxn target="sec2">Part 1</cnxn> to implement
	the filter with a 4 kHz to 8 kHz passband using the
	<code>firsadd</code>.
      </para>
      <para id="p13">Two differences in implementation between your code from <cnxn target="sec2">Part 1</cnxn> and the code you will write for
	this part are that <code>firsadd</code> requires the states
	to be broken up into two separate circular buffers.  Refer to
	the <code>firsadd</code> instruction on <cite>page 5-152</cite> in
	the <cite src="http://focus.ti.com/lit/ug/spru374g/spru374g.pdf">Mnemonic
	Instruction Set</cite> manual.
      </para>
      
      <code type="block"><![CDATA[ 
        1       mov     *AR1, *AR2-                     ; write x(-N/2) over x(-N)
        2       mov	HI(AC0), *AR1		        ; write x(0) over x(-N/2)
        3       add     *AR1-, *AR2-, AC0               ; add x(0) and x(-(N-1))
	4					        ;   (prepare for first multiply)
        5       rpt     #(FIR_len1/2-1)
	6       firsadd *AR1-, *AR2-, *CDP+, AC0, AC1
	7       round   AC1
	8       amar	????????????????		; Fill in these two instructions
	9       amar	?????				; They modify AR1 and AR2
        10                   
        11                                              ; note that the result is now in the
	12					        ;  AC1 accumulator]]>
      </code>
      <para id="p15">
	Because states and coefficients are now treated differently
	than in your previous FIR implementation, you will need to
	modify the pointer initializations to
      </para>
      <code type="block"><![CDATA[
        1       bset	AR1LC		              ; sets circular addressing for AR1
	2       bset	AR2LC		              ; sets circular addressing for AR2
	3       
        4 
	5       mov	#firState1, AR1
	6       mov	#firState1Index, AR4
	7       mov     mmap(AR1), BSA01
	8       mov    *AR4, AR1		      ; get pointer to oldest delayBuf in AR1
	9
	10      mov     #firState2, AR2
	11      mov     #firState2Index, AR5
	12      mov	mmap(AR2), BSA23
	13      mov	*AR5, AR2
        14
	15
	16      mov     #(FIR_len1/2), BKC
	17      mov     #(FIR_len1/2), BK03	      ; initialize circular buffer length for register 0-3
	18      mov     #coef1, CDP		      ; CDP contains address of coefficients
        19      mov     *AR6 << #16, AC0              ; copy input into AC0
	]]>
      </code>
      <para id="element-493">There are also a couple other changes that need to be made before the code will compile successfully. Read the comments carefully and understand how the <code>firsadd</code> instruction works to make the necessary changes. Hint: Make sure accumulator usage (AC0, AC1, AC2) and what is sent to output is correct.</para><para id="p16">
	Use the test-vector core file to find the output of this
	system given the same test vector you used to test the
	two-filter system. Compare the output of this code against the
	output of the same filter implemented using the
	<code>mac</code> instruction. Are the results the same? Why or
	why not?  Ensure that the filtered output is sent to output
	channel 1, and that the unmodified output is still sent to
	output channel 2.<note type="warning">You will lose credit if
	the unmodified output is not present or if the channels are
	reversed!</note>
      </para>
    </section>
    
    <section id="sec6">
      <name>Quiz Information</name>
      <para id="p17">
        The quiz for Lab 1 is broken down as follows:
      </para>
      
      <list id="point_list" type="bulleted">
        <item> 1 point: Prelab (must be ready to show the TA the week
	  before the quiz)</item> 
        
        <item> 4 points: Working code: you must demonstrate that your
	  code works using input from function generator and that it
	  works using input from appropriate test vectors.  Have an
	  <code>.asm</code> file <emphasis>ready</emphasis> to
	  demonstrate each.  Of the 4 points, you get 0.5 points for a
	  single 20-tap filter, 2 points for the two-filter system,
	  and 1.5 points for the system using the <code>firs</code>
	  opcode.</item>

        <item> 5 points: Oral quiz score.</item>

        <item> 1 extra credit point: As described <cnxn target="p10">above</cnxn>.</item>
      </list>

      <para id="p18">
        The oral quiz may cover signal processing material relating to
        FIR filters, including, but not limited to, the delay through
        FIR filters, generalized linear phase, and the differences
        between ideal FIR filters and realizable FIR filters.  You may
        also be asked questions about digital sampling theory,
        including, but not limited to, the Nyquist sampling theorem
        and the relationship between the analog frequency spectrum and
        the digital frequency spectrum of a continuous-time signal
        that has been sampled.
      </para>

      <para id="p19">
        The oral quiz <emphasis>will</emphasis> cover the code that
        you have written during the lab.  You are expected to
        understand, in detail, all of the code in the files you have
        worked on, even if your partner or a TA wrote it.  (You are
        not expected to understand the core file in detail).  The TA
        will ask you to explain various lines of code as part of the
        quiz.  The TAs may also ask questions about 2's complement
        fractional arithmetic, circular buffers, alignment, and the
        mechanics of either of the two FIR filter implementations.
        You could be ready to trace through any of the code on paper
        and explain what each line of code does.
      </para>

      <para id="p20">Use the TI documentation, specifically the <cite src="http://focus.ti.com/lit/ug/spru374g/spru374g.pdf">Mnemonic
	Instruction Set</cite> manual. Also, feel free to ask the TAs to
	help explain the code that you have been given.
      </para>
    </section>
  </content>
</document>
