

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

         |**                                           **|

         |**   DSP56200 CHIP DRIVER -ADAPTIVE FILTER   **|

         |**                        -INTERRUPT DRIVEN  **|

         |**                                           **|

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







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

*                                                                        *

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

*   to setup and service the DSP56200 as a real-time adaptive filter.    *

*   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                                  *

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

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

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

*                             | (contains code |--->| D/A |--> out(t)    *

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

*         x1(t) -->| A/D |--->|     file)      |                         *

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

*                                                                        *

*                                                                        *

*                    Figure 1. Adaptive Filtering System                 *

*                                                                        *

*                                                                        *

*                                                                        *

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

*   DSP56200s in cascade), and it is configured as an adaptive filter    *

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

*   Since only 16 bits of the result  are sent to the D/A Converter,     *

*   the output is rounded to a 16 bit result by the DSP56200.            * 

*                                                                        *

*                                                                        *

*                                                                        *

*                                                                        *

*         d(n) -------------------------------                           *

*                                          - |                           *

*                                            v                           *

*                    --------------     +   ---                          *

*        x1(n) ----->|    FIR     |------->| + |-----> out(n)            *

*                    |  Structure |         ---           = -1 * error   *

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

*                          ^                 |                           *

*                          |                 |                           *

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

*                                                                        *

*                                                                        *

*                   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 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   3       /* Pass for Configuring the DSP56200 */

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

#define   PASS_ENABLE   1       /* Pass for Enabling Coeff Updates   */

#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

#define   D_LO      0x3

#define   K_HI      0x4

#define   K_LO      0x5

#define   X2_HI     0x6                     /* unused -Dual FIR mode only */

#define   X2_LO     0x7                     /* unused -Dual FIR mode only */

#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 result */

#define   OUTPUT2   0x1

#define   OUTPUT1   0x2               /* Two least significant bytes are  */

#define   OUTPUT0   0x3               /* unused since rounded to 16 bits */

#define   LTAP1_HI  0x4                     /* unused */

#define   LTAP1_LO  0x5                     /* unused */

#define   LTAP2_HI  0x6                     /* unused */

#define   LTAP2_LO  0x7                     /* unused */



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

#define   FTL       0x1







#define   LKG_VAL   0x00        /* Values (hex) written to the DSP56200 regs */

#define   FTL_VAL   0xff              /* 256 taps */

#define   DCONFIG_0 0x98              /* Updates disabled, Selects bank 0   */

#define   DCONFIG_1 0x99              /* Updates disabled, Selects bank 1   */

#define   ECONFIG_0 0x90              /* Updates enabled,  Selects bank 0   */

#define   KVAL_HI   0x04

#define   KVAL_LO   0x00              /* It may be desirable to make the K 

                                         register a variable so it can be 

                                         updated every sample period.   */





        /*** GLOBAL VARS ***/



int  tap;                             /* filter tap number */

int  passnum;                         /* Determines action taken by the

                                         interrupt service routine when

                                         a START interrupt is received.  */







        /*** MAIN PROGRAM ***/



main()   {



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

        *                                                                    *

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

        *   processor to service a DSP56200 configured as an adaptive        *

        *   filter.  Three functions are performed:                          *

        *                                                                    *

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

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

        *         3. Run the Adaptive Filter in a real-time environment.     *

        *                                                                    *

        *   Things to watch for when setting up an adaptive filter system:   *

        *                                                                    *

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

        *         - The SEI pin must be directly wired to the SSO pin.       *

        *         - The value of the K register must not be too large.       *

        *         - 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()".        *

        *                                                                    *

        *   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  */

           /*  adaptive 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 Adaptive Filter 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 four tasks when executed:                          *

        *                                                                *

        *         Task 1. Configure the DSP56200.                        *

        *                                                                *

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

        *                 one location in the Coefficient RAM.           *

        *                                                                *

        *         Task 3. Enable Updates of the Coefficients.            *

        *                                                                *

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

        *                 and read out one error term 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 uses one sample period (i.e. the next    *

        *   interrupt) to enable updates of the coefficients.  From this *

        *   time on, the host executes Task 4 with each new interrupt it *

        *   receives.  If the user wants to update the value of the K    *

        *   (loop gain) register, it could also be done within Task 4.   *

        *                                                                *

        *   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: The DSP56200 outputs "-1 * error".  If the correct     *

        *         sign for the error term is required, then the host     *

        *         processor must perform a 2's complement operation      *

        *         on the 16 bit value read from the DSP56200's OUTPUT    *

        *         register (bytes 3 and 2).                              *

        *                                                                *

        *   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, d, out;                                 /* see Figure 2 */







        /* Select Correct Task to Execute */



        /* TASK 1 */



           if (passnum == PASS_CONFIG)   {



              /* Reset and Configure the DSP56200 */



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

                                            /*    - Single Adaptive Filter   */

                                            /*    - Not Cascaded             */

                                            /*    - 16 Bit Rounding          */

                                            /*    - Coeff Update Disabled    */

                                            /*    - DC Tap Disabled          */

                                            /*    - Leakage 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(LKG_VAL, LEAKAGE);



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



                 wrbyte(KVAL_HI, K_HI);

                 wrbyte(KVAL_LO, K_LO);



              /* Setup the DSP56200 registers for RAM initialization */



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

                    wrbyte(0, X1_LO);



                    wrbyte(0, D_HI);

                    wrbyte(0, D_LO);



                    wrbyte(0, COEFF_HI);      /* Coeff_RAM[0] = 0 */

                    wrbyte(0, COEFF_MD);

                    wrbyte(0, 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)   {



             /* Clear 1 Location in the DSP56200's Coefficient and Data RAMS */



                 tap = tap + 1;



                 wrbyte(0, COEFF_HI);      /* Coeff_RAM[tap] = 0 */

                 wrbyte(0, COEFF_MD);

                 wrbyte(0, COEFF_LO);

                                       /*  Note that the Data RAM is also   */

                                       /*  cleared since the DSP56200's X1  */

                                       /*  reg is set to "0", resulting in  */

                                       /*  "0"s being "shifted" into the    */

                                       /*  filter's Data RAM (delay line)   */

                                       /*  every sample period.             */



                 if (tap == FTL_VAL)

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

                                                       next START interrupt */



              /* Exit Routine */

                 return;

           }



        /* TASK 3 */



           if (passnum == PASS_ENABLE)   {         



                 wrbyte(ECONFIG_0, CONFIG);         /* Enables coeff updates by

                                                       toggling bit 3 to "0" */



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

                                                       next START interrupt */



                 return;                            /* Exit Routine */

           }



        /* TASK 4 */



           if (passnum == PASS_REALTIM)   {



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



                 x1 = get_ad(1);

                 d  = get_ad(2);



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

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

                 wrbyte((d>>8)   0x0ff, D_HI);       /* writes upper byte */

                 wrbyte( d       0x0ff, D_LO);       /* writes lower byte */



              /* Read Error Term from the 56200 and Write to the D/A */



                 out = rdbyte(OUTPUT3);

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

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



                 send_da(out);



              /* 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 = x1 input, 2 = d input.  *

        *                                                                  *

        *   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)

int val;

{

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

        *                                                              *

        *   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 D/A converter             *

        *                                                              *

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



        /* 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.         */

}

