

         /***********************************************\

         |**                                           **|

         |**   DSP56200 CHIP DRIVER -DUAL FIR FILTERS  **|

         |**                        -INTERRUPT DRIVEN  **|

         |**                                           **|

         \***********************************************/







/************************************************************************\

*                                                                        *

*   This is an example of a program located in a host processor, used    *

*   to setup and service a single DSP56200 as two real-time FIR filters. *

*   In this example, the host processor is interrupted at the beginning  *

*   of every new sample period, signified by the reception of a rising   *

*   edge on the DSP56200's START pin.  The host processor's interrupt    *

*   pin is tied to the START pin of the DSP56200 through an inverter.    *

*                                                                        *

*   This program, written in the language "C", is provided only as an    *

*   example, and will be much faster if translated by the user into the  *

*   assembly language of the host processor.                             *

*                                                                        *

*                                                                        *

*   The example system is configured as shown below:                     *

*                                                                        *

*                                                                        *

*                            ------------                                *

*                            | DSP56200 |                                *

*                            ------------                                *

*                                  ^                                     *

*                                  |                                     *

*                                  v                                     *

*               -------    ------------------    -------                 *

*      x1(t) -->| A/D |--->| Host Processor |--->| D/A |--> out1(t)      *

*               -------    |                |    -------                 *

*                          | (contains code |                            *

*               -------    |  found in this |    -------                 *

*      x2(t) -->| A/D |--->|     file)      |--->| D/A |--> out2(t)      *

*               -------    ------------------    -------                 *

*                                                                        *

*                                                                        *

*                   Figure 1. Dual FIR Filtering System                  *

*                                                                        *

*                                                                        *

*                                                                        *

*   There is only one DSP56200 in this example (i.e., not multiple       *

*   DSP56200s in cascade), and it is configured in the Dual FIR filter   *

*   mode (Figure 2) by writing the DSP56200's Configuration register.    *

*   Since only 16 bit  results  are sent to each D/A Converter, the      *

*   outputs are rounded to 16 bits by the DSP56200.                      * 

*                                                                        *

*                                                                        *

*                                                                        *

*                                                                        *

*                           --------------                               *

*                           |  1st  FIR  |                               *

*               x1(n) ----->|   Filter   |-----> out1(n)                 *

*                           |  (7 taps)  |                               *

*                           --------------                               *

*                                                                        *

*                           --------------                               *

*                           |  2nd  FIR  |                               *

*               x2(n) ----->|   Filter   |-----> out2(n)                 *

*                           |  (7 taps)  |                               *

*                           --------------                               *

*                                                                        *

*                                                                        *

*                   Figure 2. DSP56200 Configuration                     *

*                                                                        *

*                                                                        *

*      ************************************************************      *

*      *                                                          *      *

*      *   This program originally available on the Motorola DSP  *      *

*      *   bulletin board.  It is provided under a DISCLAMER OF   *      *

*      *   WARRANTY available from  Motorola DSP Operation,       *      *

*      *     6501 Wm. Cannon Drive W., Austin, Tx., 78735.        *      *

*      *                                                          *      *

*      ************************************************************      *

*                                                                        *

*                                                                        *

*                                                                        *

*      ************************************************************      *

*      * Note on the Representation of the Hex Numbers:           *      *

*      *                                                          *      *

*      *    In the programming language  "C",  hex numbers are    *      *

*      *    represented by preceding the number with "0x". For    *      *

*      *    example, e4 (hex) is represented in "C" as 0xe4.      *      *

*      *                                                          *      *

*      ************************************************************      *

*                                                                        *

\************************************************************************/







        /*** CONSTANTS ***/



#define   PASS_CONFIG   2       /* Pass for Configuring the DSP56200 */

#define   PASS_RAMINIT  1       /* Pass for Initializing the RAMs    */

#define   PASS_REALTIM  0       /* Pass for Realtime Filtering       */







#define   X1_HI     0x0         /* Addresses (hex) of DSP56200 regs, bank 0 */

#define   X1_LO     0x1

#define   D_HI      0x2                     /* unused -Adaptive mode only */

#define   D_LO      0x3                     /* unused -Adaptive mode only */

#define   K_HI      0x4                     /* unused -Adaptive mode only */

#define   K_LO      0x5                     /* unused -Adaptive mode only */

#define   X2_HI     0x6

#define   X2_LO     0x7

#define   DATA_HI   0x8                     /* unused */

#define   DATA_LO   0x9                     /* unused */

#define   COEFF_HI  0xa

#define   COEFF_MD  0xb

#define   COEFF_LO  0xc

#define   RAM_ADR   0xd

#define   CONFIG    0xf



#define   OUTPUT3   0x0              /* Most  significant byte of 1st result */

#define   OUTPUT2   0x1              /* Least significant byte of 1st result */

#define   OUTPUT1   0x2              /* Most  significant byte of 2nd result */

#define   OUTPUT0   0x3              /* Least significant byte of 2nd result */

#define   LTAP1_HI  0x4

#define   LTAP1_LO  0x5

#define   LTAP2_HI  0x6

#define   LTAP2_LO  0x7



#define   LEAKAGE   0x0         /* Addresses (hex) of DSP56200 regs, bank 1 */

#define   FTL       0x1







                                /* Values (hex) written to the DSP56200 regs */

#define   CNFIG_0   0x50              /* Config reg: Selects bank 0 */

#define   CNFIG_1   0x51              /* Config reg: Selects bank 1 */

#define   FTL_VAL   0x06              /* Two filters, each with 7 taps */





        /*** GLOBAL VARS ***/



int  tap;                         /* Filter tap number, used to load coeffs */

int  passnum;                     /* Determines action taken by the

                                     interrupt service routine when

                                     a START interrupt is received.  */

static int coeff[14][3] = {

   { 0x08, 0x00, 0x00 },            /* 1st coeff of 1st filter (3 bytes) */

   { 0x10, 0x00, 0x00 },            /* 2nd coeff ...                     */

   { 0x18, 0x00, 0x00 },            /* 3rd coeff ...                     */

   { 0x20, 0x00, 0x00 },            /* 4th coeff ...                     */

   { 0x18, 0x00, 0x00 },            /* 5th coeff ...                     */

   { 0x10, 0x00, 0x00 },            /* 6th coeff ...                     */

   { 0x08, 0x00, 0x00 },            /* 7th coeff ...                     */

   { 0x08, 0x00, 0x00 },            /* 1st coeff of 2nd filter (3 bytes) */

   { 0x10, 0x00, 0x00 },            /* 2nd coeff ...                     */

   { 0x18, 0x00, 0x00 },            /* 3rd coeff ...                     */

   { 0x20, 0x00, 0x00 },            /* 4th coeff ...                     */

   { 0x18, 0x00, 0x00 },            /* 5th coeff ...                     */

   { 0x10, 0x00, 0x00 },            /* 6th coeff ...                     */

   { 0x08, 0x00, 0x00 }             /* 7th coeff ...                     */

};                           /*  This two-dimensional array holds the 14    */

                             /*  coefficients required for the two FIR      */

                             /*  filters (each coeff is three bytes long).  */

                             /*  Note that the coeffs of the 1st filter     */

                             /*  don't have to be the same as those of the  */

                             /*  2nd filter, but in this case they are the  */

                             /*  same. The coefficients would typically be  */

                             /*  stored in a ROM in an actual setup.        */







        /*** MAIN PROGRAM ***/



main()   {



        /********************************************************************\

        *                                                                    *

        *   This program is an example of the software used by a host        *

        *   processor to service a DSP56200 configured in the Dual FIR       *

        *   Filter mode.  Three functions are performed:                     *

        *                                                                    *

        *         1. Initialize User's System and Configure the DSP56200.    *

        *         2. Initialize the Coeff and Data RAMs of the DSP56200.     *

        *         3. Run the Dual FIR Filters in a real-time environment.    *

        *                                                                    *

        *   Things to watch for when setting up the filtering system:        *

        *                                                                    *

        *         - There must be NO GLITCHES on the DSP56200's START pin.   *

        *         - If codecs are used for the A/D or D/A conversion, see    *

        *              comments in the routines "send_da()"and "get_ad()".   *

        *         - If offset binary A/Ds or D/As are used, see comments     *

        *              in the subroutines "send_da()" and "get_ad()".        *

        *         - Coefficients must be correctly selected so that there    *

        *              is no overflow (see box below).                       *

        *                                                                    *

        *      ********************************************************      *

        *      * Preventing Overflow:                                 *      *

        *      *                                                      *      *

        *      *    All FIR filters are subject to overflow, and it   *      *

        *      *    is important that the filter coefficients are     *      *

        *      *    carefully selected to prevent overflow.  For the  *      *

        *      *    DSP56200, overflow occurs when the right side of  *      *

        *      *    equation (1) has a magnitude greater than 1.0:    *      *

        *      *                                                      *      *

        *      *                    N-1                               *      *

        *      *                    __                                *      *

        *      *                    \                                 *      *

        *      *          y(n)  =   /_   h(i) * x(n-i)        (1)     *      *

        *      *                   i = 0                              *      *

        *      *                                                      *      *

        *      *    N represents the number of filter taps (N = 7     *      *

        *      *    in this program), and h(i) represents the "ith"   *      *

        *      *    filter coefficient.  Both h(i) and x(n-i) are     *      *

        *      *    signed, fractional numbers  in the DSP56200's     *      *

        *      *    data format.                                      *      *

        *      *                                                      *      *

        *      *    If there is a possibility of overflow with a set  *      *

        *      *    of filter coefficients, then all coefficients     *      *

        *      *    must be scaled by a constant.  The DSP56200's     *      *

        *      *    24 bit coefficients allow plenty of room for      *      *

        *      *    scaling. If 12 bit input data samples are used in *      *

        *      *    a system, the potential for overflow is greatly   *      *

        *      *    reduced if the samples are sign-extended by four  *      *

        *      *    bits before sending them to the DSP56200.         *      *

        *      *                                                      *      *

        *      ********************************************************      *

        *                                                                    *

        *                                                                    *

        *   Note: The program assumes that the variable type "int" is at     *

        *         least 16 bits wide.                                        *

        *                                                                    *

        \********************************************************************/







        /* Program Setup */



           /* The host must disable the START Interrupt */



           /* Then, global vars are set up for the routine "irealtime()" */

              passnum = PASS_CONFIG;

              tap = 0;







        /* Initialize System */



           /*   Here the user first initializes any other components of     */

           /*   the filtering system which require initialization.  The     */

           /*   DSP56200 is then initialized using the program code below.  */







        /* The host must now enable the START Interrupt */







        /* Run the Filters in Real-time */



           /*  At this point the program can either start executing some     */

           /*  other task or it can idle.  Upon reception of a START signal  */

           /*  (i.e. when interrupted), the host calls the interrupt service */

           /*  routine "irealtime()".  Upon completion of "irealtime()",     */

           /*  the host either continues its other processing or idles.      */

}







        /*** SUBROUTINES ***/







        /* IREALTIME */



irealtime()

{

        /****************************************************************\

        *                                                                *

        *   This interrupt service routine will perform one of the       *

        *   following three tasks when executed:                         *

        *                                                                *

        *         Task 1. Configure the DSP56200.                        *

        *                                                                *

        *         Task 2. Clear one location in the Data RAM and         *

        *                 load one location in the Coefficient RAM.      *

        *                                                                *

        *         Task 3. Send two new data samples to the DSP56200      *

        *                 and read out two FIR results from the chip.    *

        *                                                                *

        *   When the user's system comes out of reset, the DSP56200 is   *  

        *   first configured (Task 1).  Then, the host processor will    *

        *   execute Task 2 when interrupted so that the DSP56200 RAMs    *

        *   get initialized.  Upon receiving each new interrupt, Task 2  *

        *   is executed until the RAM initialization is completed.  The  *

        *   host processor then executes Task 3 with each new interrupt  *

        *   it receives.                                                 *

        *                                                                *

        *   This routine is used only in interrupt driven systems.       *

        *   Since this is an interrupt service routine, it may be        *

        *   necessary to save the status of the host processor upon      *

        *   entering this routine, and to restore the processor's        *

        *   status upon exiting this routine.  It may also be important  *

        *   to disable any interrupts of lower priority when entering    *

        *   this routine, and to reenable these interrupts upon exiting. *

        *                                                                *

        *   Note: The routine assumes that the variable type "int" is    *

        *         at least 16 bits wide.                                 *

        *                                                                *

        *   Also: It is important that execution of this routine         *

        *         completes before the next START interrupt arrives,     *

        *         i.e., it must complete in one sample period.   If      *

        *         Task 1 will not complete in one sample period, it      *

        *         can be broken into two shorter tasks, requiring        *

        *         two sample periods.                                    *

        *                                                                *

        \****************************************************************/







        /* Subroutine Declarations */

           int x1, x2, out;                       /* see Figure 2 */







        /* Select Correct Task to Execute */



        /* Task 1 */



           if (passnum == PASS_CONFIG)   {



              /* Reset and Configure the DSP56200 */



                 wrbyte(CNFIG_1, CONFIG);  /* Configuration:                */

                                           /*    - Dual FIR Filters         */

                                           /*    - Not Cascaded             */

                                           /*    - 16 Bit Rounding          */

                                           /*    - DC Tap Disabled          */

                                           /*    - Register Bank 1 Selected */

                 wrbyte(FTL_VAL, FTL);     /* Writing this reg also resets   */

                                           /*    the chip at the beginning   */

                                           /*    of the next sample period,  */

                                           /*    which destroys any previous */

                                           /*    contents of the Data RAM.   */



                 wrbyte(CNFIG_0, CONFIG);       /* Switch to register bank 0 */







              /* Setup the DSP56200 registers for RAM initialization */



                 wrbyte(0, X1_HI);   /* clears Data RAM when loading coeffs */

                 wrbyte(0, X1_LO);



                 wrbyte(0, X2_HI);

                 wrbyte(0, X2_LO);



                 wrbyte(coeff[0][0], COEFF_HI);   /* 1st coeff of 1st FIR */

                 wrbyte(coeff[0][1], COEFF_MD);

                 wrbyte(coeff[0][2], COEFF_LO);



                 wrbyte(0, RAM_ADR);      /* autoincrements w/ each START */



                 passnum = passnum-1;            /* Goes to PASS_RAMINIT on

                                                    next START interrupt */

              /* Exit Routine */

                 return;

           }



        /* Task 2 */



           if (passnum == PASS_RAMINIT)   {



              /* Load One Coeff into the DSP56200's Coefficient RAM */



                 tap = tap + 1;



                 wrbyte(coeff[tap][0], COEFF_HI);

                 wrbyte(coeff[tap][1], COEFF_MD);

                 wrbyte(coeff[tap][2], COEFF_LO);

                                     /*  Note that the Data RAM is cleared   */

                                     /*  since the DSP56200's X1 and X2 regs */

                                     /*  are set to "0", resulting in "0"s   */

                                     /*  being "shifted" into the filter's   */

                                     /*  Data RAM (delay line) every sample  */

                                     /*  period.                             */



                 if (tap == (1 + 2*FTL_VAL))

                    passnum = passnum-1;            /* Goes to PASS_REALTIM on

                                                       next START interrupt */



              /* Exit Routine */

                 return;

           }



        /* Task 3 */



           if (passnum == PASS_REALTIM)   {



              /* Read New Samples from the A/Ds and Write to the DSP56200 */



                 x1 = get_ad(1);

                 x2 = get_ad(2);



                 wrbyte((x1>>8)  0x0ff, X1_HI);      /* writes upper byte */

                 wrbyte( x1      0x0ff, X1_LO);      /* writes lower byte */

                 wrbyte((x2>>8)  0x0ff, X2_HI);      /* writes upper byte */

                 wrbyte( x2      0x0ff, X2_LO);      /* writes lower byte */



              /* Read the Results from the 56200 and Write to the D/As */



                 out = rdbyte(OUTPUT3);

                 out = out << 8;                      /* move to upper byte */

                 out = out + (0x0ff  rdbyte(OUTPUT2));

                 send_da(out,1);



                 out = rdbyte(OUTPUT1);

                 out = out << 8;                      /* move to upper byte */

                 out = out + (0x0ff  rdbyte(OUTPUT0));

                 send_da(out,2);



              /* Exit Routine */

                 return;

           }

}







        /* WRBYTE */



wrbyte(val,adr)

int val, adr;

{

        /**************************************************************\

        *                                                              *

        *   This subroutine writes one byte to the DSP56200 register   *

        *   specified by "adr".                                        *

        *   Note that the correct register bank has already been       *

        *   selected (defined by the LSB of the Configuration reg).    *

        *                                                              *

        *   This subroutine could be defined as a macro for faster     *

        *   execution.                                                 *

        *                                                              *

        *   Inputs:                                                    *

        *      val  = bytewide value to be written to the DSP56200     *

        *      adr  = address of the DSP56200 register to be written   *

        *                                                              *

        \**************************************************************/



        /* Actual program code depends on the user's system. */

}







        /* RDBYTE */



rdbyte(adr)

int adr;

{

        /**************************************************************\

        *                                                              *

        *  This subroutine reads one byte from the DSP56200 register   *

        *  specified by "adr".                                         *

        *  Note that the correct register bank has already been        *

        *  selected (defined by the LSB of the Configuration reg).     *

        *                                                              *

        *  This subroutine could be defined as a macro for faster      *

        *  execution.                                                  *

        *                                                              *

        *   Inputs:                                                    *

        *      adr  = address of the DSP56200 register to be read      *

        *                                                              *

        *   Outputs:                                                   *

        *      The routine returns the byte read from the DSP56200     *

        *                                                              *

        \**************************************************************/



        int valread;



        /* Actual program code depends on the user's system. */



        return(valread);

}







        /* GET_AD */



get_ad(devnum)

int devnum;

{

        /******************************************************************\

        *                                                                  *

        *   This subroutine returns a 16 bit value read from one of the    *

        *   two A/D converters in the filtering system.                    *

        *                                                                  *

        *   Inputs:                                                        *

        *      devnum = A/D Converter number:  1=1st FIR, 2=2nd FIR.       *

        *                                                                  *

        *   Outputs:                                                       *

        *      The routine returns the value read from the selected A/D.   *

        *                                                                  *

        \******************************************************************/



        int ad_val;



        /* Actual program code depends on the user's system. */



        /*  If a codec is used for A/D conversion, the 8 bit companded  */

        /*  sample must be converted into a 12 bit linear quantity and  */

        /*  then sign extended to 16 bits.                              */



        /*  If the converter uses an offset binary format, it may be  */

        /*  necessary to invert the sign bit (and any sign extension  */

        /*  bits) to obtain a 2's complement number.                  */



        return(ad_val);

}







        /* SEND_DA */



send_da(val,devnum)

int val, devnum;

{

        /**************************************************************\

        *                                                              *

        *   This subroutine sends a value to a D/A converter where it  *

        *   gets converted to an analog signal.                        *

        *                                                              *

        *   Inputs:                                                    *

        *      val = value to be sent to the selected D/A converter    *

        *      devnum = D/A Converter number:  1=1st FIR, 2=2nd FIR.   *

        *                                                              *

        \**************************************************************/



        /* Actual program code depends on the user's system. */



        /*  If a codec is used for D/A conversion, the 16 bit linear   */

        /*  sample must be converted into a 8 bit companded quantity.  */



        /*  If the converter uses an offset binary format, it may be  */

        /*  necessary to invert the sign bit (and any sign extension  */

        /*  bits) to obtain a number in offset binary format.         */

}

